Files
slogan/server/main.go
T
admin fc56b47406 server: web 静态托管完善 + 联调脚本 + 清理过期工具
- main.go/auth_middleware: web 静态目录托管与 history 回退、Chrome DevTools 探测处理
- 新增 scripts/build_web.sh(缓存判断构建 web)与 scripts/dev.sh(一键构建+启动)
- 删除已过时的 routes.sh(goframe 自动生成 api.json)与 split_db(数据库已拆分完毕)
- docs: 补充联调与测试规范(测试必须用真实用户数据 wenwu901/123456)
2026-08-04 17:15:37 +08:00

104 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"context"
"net/http"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
commonHttp "slogan-agent/common"
"slogan-agent/styleagent/controller"
"slogan-agent/styleagent/service"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
)
func main() {
// ==================== Web 静态资源(Flutter web 构建产物) ====================
// 静态目录不存在时优雅跳过(仅 API 模式运行);注册顺序在 Auth 之后,history 回退先经鉴权放行
if dir := commonHttp.WebStaticDir(); dir != "" {
commonHttp.Httpserver.SetServerRoot(dir)
commonHttp.Httpserver.BindMiddlewareDefault(func(r *ghttp.Request) {
r.Middleware.Next()
if r.Response.Status == http.StatusNotFound && commonHttp.IsWebHistoryRoute(r.URL.Path) {
r.Response.ClearBuffer()
r.Response.ServeFile(filepath.Join(dir, "index.html"))
}
})
// Chrome DevTools 探测请求:.well-known 协议处理器探测返回 204;
// flutter.js 尾部保留 sourceMappingURL 注释但 release 构建不生成 map,返回合法空 sourcemap
// 避免每次打开 DevTools 都产生 404(覆盖本地直服与 Docker 两种部署)
commonHttp.Httpserver.BindHandler("/.well-known/appspecific/com.chrome.devtools.json", func(r *ghttp.Request) {
r.Response.WriteStatus(http.StatusNoContent)
})
commonHttp.Httpserver.BindHandler("/flutter.js.map", func(r *ghttp.Request) {
r.Response.WriteJson(map[string]interface{}{
"version": 3,
"sources": []string{},
"names": []string{},
"mappings": "",
})
})
}
// ==================== API 路由(RouteRegister 反射注册,kebab-case 前缀) ====================
commonHttp.RouteRegister([]interface{}{
controller.User,
controller.UserPhoto,
controller.Wardrobe,
controller.BodyMeasurement,
controller.Avatar,
controller.Hairstyle,
controller.Outfit,
controller.PartnerStore,
controller.Member,
controller.Ad,
controller.Cps,
})
// 虎皮棋支付回调(裸文本 "success",不走统一 JSON 包装)
commonHttp.Httpserver.Group("/member/order", func(group *ghttp.RouterGroup) {
group.POST("/notify", controller.MemberNotify)
})
// ==================== Workspace 文件服务(鉴权保护) ====================
commonHttp.Httpserver.BindHandler("/workspace/*", func(r *ghttp.Request) {
relPath := strings.TrimPrefix(r.URL.Path, "/workspace/")
if relPath == "" || strings.Contains(relPath, "..") {
r.Response.WriteStatus(http.StatusForbidden)
return
}
filePath := filepath.Join("workspace", relPath)
if _, err := os.Stat(filePath); os.IsNotExist(err) {
r.Response.WriteStatus(http.StatusNotFound)
return
}
r.Response.ServeFile(filePath)
})
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
// 恢复未完成的生成任务(重启后标记失败,避免重复消耗 LLM 费用)
service.OutfitService.StartWorker(ctx)
// CPS 联盟商品定时同步(未配置 key 时空转)
service.CpsProductService.StartSyncLoop(ctx)
g.Log().Info(ctx, "slogan-agent started on :3007")
<-ctx.Done()
g.Log().Info(ctx, "shutting down...")
time.Sleep(1 * time.Second)
g.Log().Info(ctx, "bye")
}