Files

228 lines
8.9 KiB
Go
Raw Permalink 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"
"log"
"time"
"github.com/gin-gonic/gin"
"wx_service/config"
"wx_service/internal/achievement"
adminmodule "wx_service/internal/admin"
authhandler "wx_service/internal/common/auth/handler"
authservice "wx_service/internal/common/auth/service"
rediscache "wx_service/internal/common/redis/cache"
redisservice "wx_service/internal/common/redis/service"
uploadhandler "wx_service/internal/common/upload/handler"
uploadservice "wx_service/internal/common/upload/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"
quitcheckinhandler "wx_service/internal/quitcheckin/handler"
quitcheckinmodel "wx_service/internal/quitcheckin/model"
quitcheckinservice "wx_service/internal/quitcheckin/service"
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{},
&smokemodel.SmokeQuitPlan{},
&smokemodel.SmokeQuitPlanDay{},
&marketingmodel.MarketingCategory{},
&marketingmodel.MarketingTemplate{},
&marketingmodel.MarketingDownload{},
&marketingmodel.UserLogo{},
&marketingmodel.AdPlacement{},
&quitcheckinmodel.Profile{},
&quitcheckinmodel.DailyStatus{},
&quitcheckinmodel.RelapseEvent{},
&quitcheckinmodel.HPChangeLog{},
&quitcheckinmodel.SupervisorInvite{},
&quitcheckinmodel.SupervisorBinding{},
&quitcheckinmodel.SupervisorReminderSetting{},
&quitcheckinmodel.SupervisorReminderLog{},
&quitcheckinmodel.RewardGoal{},
&quitcheckinmodel.DreamPreset{},
&achievement.Theme{},
&achievement.Level{},
); 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,再创建 handlerhandler 只关心 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)
smokeQuitPlanService := smokeservice.NewSmokeQuitPlanService(database.DB, config.AppConfig.AI)
achievementService := achievement.NewService(database.DB)
if err := achievementService.SeedDefaults(context.Background()); err != nil {
log.Printf("seed achievement defaults: %v", err)
}
quitCheckinService := quitcheckinservice.NewService(database.DB)
smokeHandler := smokehandler.NewSmokeHandler(smokeLogService, smokeAIAdviceService, smokeProfileService, smokeNextService, smokeAINextService, smokeShareService, achievementService, quitCheckinService)
quitPlanHandler := smokehandler.NewQuitPlanHandler(smokeQuitPlanService)
quitCheckinHandler := quitcheckinhandler.NewHandler(quitCheckinService)
redeemCodeService := membershipservice.NewRedeemCodeService(database.DB, config.AppConfig.Admin.Token)
redeemCodeHandler := membershiphandler.NewRedeemCodeHandler(redeemCodeService)
uploadSvc := uploadservice.NewUploadService(config.AppConfig.OSS)
uploadHandler := uploadhandler.NewUploadHandler(uploadSvc)
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)
userLogoRepo := marketingrepo.NewUserLogoRepository(database.DB)
categorySvc := marketingservice.NewCategoryService(categoryRepo)
templateSvc := marketingservice.NewTemplateService(templateRepo)
downloadSvc := marketingservice.NewDownloadService(downloadRepo, templateRepo)
userLogoSvc := marketingservice.NewUserLogoService(userLogoRepo)
marketingCategoryHandler := marketinghandler.NewCategoryHandler(categorySvc)
marketingTemplateHandler := marketinghandler.NewTemplateHandler(templateSvc)
marketingDownloadHandler := marketinghandler.NewDownloadHandler(downloadSvc)
marketingUserLogoHandler := marketinghandler.NewUserLogoHandler(userLogoSvc)
adPlacementRepo := marketingrepo.NewAdPlacementRepository(database.DB)
marketingAdPlacementHandler := marketinghandler.NewAdPlacementHandler(adPlacementRepo)
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,
quitPlanHandler,
redeemCodeHandler,
uploadHandler,
oaOAuthHandler,
sessionCache,
lawyerHandler,
expiryHandler,
adminHandler,
config.AppConfig.Admin.Token,
marketingCategoryHandler,
marketingTemplateHandler,
marketingDownloadHandler,
marketingUserLogoHandler,
marketingAdPlacementHandler,
quitCheckinHandler,
)
// 7) 启动监听端口
addr := ":" + config.AppConfig.Server.Port
if err := router.Run(addr); err != nil {
log.Fatalf("server stopped: %v", err)
}
}