191 lines
7.2 KiB
Go
191 lines
7.2 KiB
Go
package main
|
||
|
||
import (
|
||
"context"
|
||
"log"
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
|
||
"wx_service/config"
|
||
adminmodule "wx_service/internal/admin"
|
||
authhandler "wx_service/internal/common/auth/handler"
|
||
authservice "wx_service/internal/common/auth/service"
|
||
qiniuhandler "wx_service/internal/common/qiniu/handler"
|
||
qiniuservice "wx_service/internal/common/qiniu/service"
|
||
rediscache "wx_service/internal/common/redis/cache"
|
||
redisservice "wx_service/internal/common/redis/service"
|
||
oahandler "wx_service/internal/common/wechat_official/handler"
|
||
oaservice "wx_service/internal/common/wechat_official/service"
|
||
"wx_service/internal/database"
|
||
expiry "wx_service/internal/expiry"
|
||
lawyerhandler "wx_service/internal/lawyer/handler"
|
||
lawyerservice "wx_service/internal/lawyer/service"
|
||
marketinghandler "wx_service/internal/marketing/handler"
|
||
marketingmodel "wx_service/internal/marketing/model"
|
||
marketingrepo "wx_service/internal/marketing/repository"
|
||
marketingservice "wx_service/internal/marketing/service"
|
||
membershiphandler "wx_service/internal/membership/handler"
|
||
membershipmodel "wx_service/internal/membership/model"
|
||
membershipservice "wx_service/internal/membership/service"
|
||
"wx_service/internal/model"
|
||
"wx_service/internal/observability"
|
||
rmhandler "wx_service/internal/remove_watermark/handler"
|
||
rmmodel "wx_service/internal/remove_watermark/model"
|
||
rmservice "wx_service/internal/remove_watermark/service"
|
||
"wx_service/internal/routes"
|
||
smokehandler "wx_service/internal/smoke/handler"
|
||
smokemodel "wx_service/internal/smoke/model"
|
||
smokeservice "wx_service/internal/smoke/service"
|
||
)
|
||
|
||
func main() {
|
||
if loc, err := time.LoadLocation("Asia/Shanghai"); err == nil {
|
||
time.Local = loc
|
||
} else {
|
||
time.Local = time.FixedZone("CST", 8*3600)
|
||
}
|
||
|
||
// 1) 加载配置(通常来自环境变量 / .env)
|
||
config.LoadConfig()
|
||
|
||
// 2) 初始化数据库连接
|
||
if err := database.InitDB(); err != nil {
|
||
log.Fatalf("init database failed: %v", err)
|
||
}
|
||
// 3) 自动建表/迁移(开发阶段很方便;生产环境可改为手动迁移)
|
||
if err := database.AutoMigrate(
|
||
&adminmodule.Admin{},
|
||
&adminmodule.SystemConfig{},
|
||
&model.MiniProgram{},
|
||
&model.User{},
|
||
&model.UserMembership{},
|
||
&expiry.ExpiryItem{},
|
||
&expiry.ExpiryUserSettings{},
|
||
&membershipmodel.MembershipRedeemCode{},
|
||
&membershipmodel.MembershipRedemption{},
|
||
&rmmodel.VideoParseLog{},
|
||
&rmmodel.VideoParseUnlock{},
|
||
&rmmodel.VideoDownloadFailure{},
|
||
&smokemodel.SmokeLog{},
|
||
&smokemodel.SmokeUserProfile{},
|
||
&smokemodel.SmokeAIAdvice{},
|
||
&smokemodel.SmokeAIAdviceUnlock{},
|
||
&smokemodel.SmokeAINextSmoke{},
|
||
&smokemodel.SmokeMotivationQuote{},
|
||
&smokemodel.SmokeShare{},
|
||
&marketingmodel.MarketingCategory{},
|
||
&marketingmodel.MarketingTemplate{},
|
||
&marketingmodel.MarketingDownload{},
|
||
); err != nil {
|
||
log.Fatalf("auto migrate failed: %v", err)
|
||
}
|
||
|
||
// 4) 初始化 HTTP 框架(Gin)
|
||
gin.SetMode(config.AppConfig.Server.Mode)
|
||
router := gin.Default()
|
||
|
||
metricsCollector := observability.NewCollector()
|
||
router.Use(observability.RequestLogMiddleware(metricsCollector))
|
||
router.GET("/metrics/basic", observability.BasicMetricsHandler(metricsCollector))
|
||
|
||
// 5) 依赖注入:先创建 service,再创建 handler(handler 只关心 HTTP 输入/输出)
|
||
miniProgramService := authservice.NewMiniProgramService(database.DB)
|
||
authService := authservice.NewAuthService(database.DB, miniProgramService)
|
||
authHandler := authhandler.NewAuthHandler(authService)
|
||
videoService, err := rmservice.NewVideoService(database.DB, config.AppConfig.ShortVideo)
|
||
if err != nil {
|
||
log.Fatalf("init video service failed: %v", err)
|
||
}
|
||
videoHandler := rmhandler.NewVideoHandler(videoService)
|
||
|
||
smokeLogService := smokeservice.NewSmokeLogService(database.DB)
|
||
smokeAIAdviceService := smokeservice.NewSmokeAIAdviceService(database.DB, config.AppConfig.AI)
|
||
smokeProfileService := smokeservice.NewSmokeProfileService(database.DB)
|
||
smokeNextService := smokeservice.NewSmokeNextService(database.DB)
|
||
smokeAINextService := smokeservice.NewSmokeAINextSmokeService(database.DB, config.AppConfig.AI)
|
||
smokeShareService := smokeservice.NewSmokeShareService(database.DB)
|
||
smokeHandler := smokehandler.NewSmokeHandler(smokeLogService, smokeAIAdviceService, smokeProfileService, smokeNextService, smokeAINextService, smokeShareService)
|
||
|
||
redeemCodeService := membershipservice.NewRedeemCodeService(database.DB, config.AppConfig.Admin.Token)
|
||
redeemCodeHandler := membershiphandler.NewRedeemCodeHandler(redeemCodeService)
|
||
|
||
qiniuService := qiniuservice.NewQiniuService(config.AppConfig.Qiniu)
|
||
uploadHandler := qiniuhandler.NewUploadHandler(qiniuService)
|
||
|
||
oaService := oaservice.NewWeChatOAService(config.AppConfig.WeChatOA)
|
||
oaOAuthHandler := oahandler.NewOAuthHandler(oaService)
|
||
|
||
var sessionCache *rediscache.SessionUserCache
|
||
redisClient, err := redisservice.NewClient(config.AppConfig.Redis)
|
||
if err != nil {
|
||
log.Printf("redis disabled: %v", err)
|
||
} else if redisClient != nil {
|
||
sessionCache = rediscache.NewSessionUserCache(redisClient.Redis(), redisClient.KeyPrefix(), redisClient.SessionTTL())
|
||
}
|
||
|
||
var lawyerHandler *lawyerhandler.LawyerHandler
|
||
if lawyerDB, ok := database.GetAdditionalDB("lawyer"); ok {
|
||
lawyerService := lawyerservice.NewService(lawyerDB)
|
||
lawyerHandler = lawyerhandler.NewLawyerHandler(lawyerService)
|
||
} else {
|
||
log.Println("lawyer 数据库未配置,/lawyers 接口已禁用")
|
||
}
|
||
|
||
expiryRepo := expiry.NewRepository(database.DB)
|
||
expiryService := expiry.NewService(expiryRepo)
|
||
if redisClient != nil {
|
||
expirySummaryCache := expiry.NewSummaryCache(redisClient.Redis(), redisClient.KeyPrefix(), 5*time.Minute)
|
||
expiryService.BindSummaryCache(expirySummaryCache)
|
||
}
|
||
expiryHandler := expiry.NewHandler(expiryService)
|
||
|
||
categoryRepo := marketingrepo.NewCategoryRepository(database.DB)
|
||
templateRepo := marketingrepo.NewTemplateRepository(database.DB)
|
||
downloadRepo := marketingrepo.NewDownloadRepository(database.DB)
|
||
categorySvc := marketingservice.NewCategoryService(categoryRepo)
|
||
templateSvc := marketingservice.NewTemplateService(templateRepo)
|
||
downloadSvc := marketingservice.NewDownloadService(downloadRepo, templateRepo)
|
||
marketingCategoryHandler := marketinghandler.NewCategoryHandler(categorySvc)
|
||
marketingTemplateHandler := marketinghandler.NewTemplateHandler(templateSvc)
|
||
marketingDownloadHandler := marketinghandler.NewDownloadHandler(downloadSvc)
|
||
|
||
adminService := adminmodule.NewService(
|
||
database.DB,
|
||
config.AppConfig.JWT.Secret,
|
||
time.Duration(config.AppConfig.JWT.Expire)*time.Second,
|
||
config.AppConfig.Admin.DefaultUsername,
|
||
config.AppConfig.Admin.DefaultPassword,
|
||
)
|
||
if err := adminService.EnsureDefaultAdmin(context.Background()); err != nil {
|
||
log.Fatalf("ensure default admin failed: %v", err)
|
||
}
|
||
adminHandler := adminmodule.NewHandler(adminService)
|
||
|
||
// 6) 注册路由:把 URL 映射到 handler
|
||
routes.Register(
|
||
router,
|
||
database.DB,
|
||
authHandler,
|
||
videoHandler,
|
||
smokeHandler,
|
||
redeemCodeHandler,
|
||
uploadHandler,
|
||
oaOAuthHandler,
|
||
sessionCache,
|
||
lawyerHandler,
|
||
expiryHandler,
|
||
adminHandler,
|
||
config.AppConfig.Admin.Token,
|
||
marketingCategoryHandler,
|
||
marketingTemplateHandler,
|
||
marketingDownloadHandler,
|
||
)
|
||
|
||
// 7) 启动监听端口
|
||
addr := ":" + config.AppConfig.Server.Port
|
||
if err := router.Run(addr); err != nil {
|
||
log.Fatalf("server stopped: %v", err)
|
||
}
|
||
}
|