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() { // ==================== 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") }