package main import ( "context" "log" "time" "affiliate_dash/internal/config" "affiliate_dash/internal/database" "affiliate_dash/internal/handler" "affiliate_dash/internal/pkg/applog" "affiliate_dash/internal/pkg/jwt" "affiliate_dash/internal/pkg/openlog" "affiliate_dash/internal/pkg/timeutil" "affiliate_dash/internal/router" "affiliate_dash/internal/service" "github.com/gin-gonic/gin" "gorm.io/driver/postgres" "gorm.io/gorm" ) func main() { cfg := config.Load() time.Local = timeutil.Location() // 日志:控制台 + 文件 logFile, err := applog.Setup(cfg.LogFile) if err != nil { log.Fatalf("setup log: %v", err) } if logFile != nil { defer logFile.Close() } gin.SetMode(cfg.Mode) db, err := gorm.Open(postgres.Open(cfg.DatabaseURL), &gorm.Config{ Logger: applog.NewGormLogger(cfg.Mode), }) if err != nil { log.Fatalf("open db: %v", err) } if err := database.Migrate(db); err != nil { log.Fatalf("migrate: %v", err) } jm := jwt.NewManager(cfg.JWTSecret) codec, err := service.NewSecretCodec(cfg.DataEncryptionKey) if err != nil { log.Fatalf("setup secret codec: %v", err) } tenantSvc := service.NewTenantService(db) authSvc := service.NewAuthService(db, jm, tenantSvc) userSvc := service.NewUserService(db, tenantSvc) callbackSvc := service.NewCallbackService(db, codec) fulfillmentSvc := service.NewFulfillmentService(db, callbackSvc) merchantSvc := service.NewMerchantService(db, codec, tenantSvc) deliverySvc := service.NewDeliveryService( fulfillmentSvc, cfg.DeliveryBFFBaseURL, cfg.DeliveryChannel, cfg.DeliveryBaseURL, cfg.DeliveryLinkSecret, cfg.DeliveryLinkTTLMinutes, ) if err := authSvc.EnsureAdmin(); err != nil { log.Fatalf("ensure admin: %v", err) } openlog.Init(cfg.OpenAPIDebug) h := &router.Handlers{ Auth: handler.NewAuthHandler(authSvc), Dashboard: handler.NewDashboardHandler(fulfillmentSvc), Delivery: handler.NewDeliveryHandler(deliverySvc), User: handler.NewUserHandler(userSvc), Open: handler.NewOpenV1Handler(merchantSvc, fulfillmentSvc, deliverySvc), SourceOpen: handler.NewOpenHandler(fulfillmentSvc), Merchant: handler.NewMerchantHandler(merchantSvc, fulfillmentSvc, callbackSvc, deliverySvc), JWT: jm, Tenant: tenantSvc, OpenDB: db, SecretCodec: codec, OpenAPIKey: cfg.OpenAPIKey, OpenAPISecret: cfg.OpenAPISecret, OpenSignSkew: cfg.OpenSignSkew, OpenAPIDebug: cfg.OpenAPIDebug, } go callbackSvc.Run(context.Background()) go fulfillmentSvc.RunProcessingTimeoutMonitor( context.Background(), time.Duration(cfg.FulfillmentProcessingTimeoutMinutes)*time.Minute, time.Duration(cfg.FulfillmentTimeoutScanIntervalSeconds)*time.Second, ) r := router.Setup(h) addr := ":" + cfg.Port log.Printf("游戏皮肤供货平台 API 启动: http://localhost%s", addr) log.Printf("数据库: PostgreSQL") log.Printf("默认管理员: admin / admin123") log.Printf("开放接口鉴权: X-App-Key + X-Timestamp + X-Nonce + X-Sign (HMAC-SHA256)") if cfg.OpenAPIDebug { log.Printf("开放接口调试日志: 开启 (OPEN_API_DEBUG=0 可关闭)") } if cfg.LogFile != "" { log.Printf("日志文件: %s (同时输出控制台)", cfg.LogFile) } if err := r.Run(addr); err != nil { log.Fatalf("server: %v", err) } }