package main import ( "context" "log" "net/http" "time" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "mengyastore-backend/internal/auth" "mengyastore-backend/internal/config" "mengyastore-backend/internal/database" "mengyastore-backend/internal/handlers" "mengyastore-backend/internal/mq" "mengyastore-backend/internal/storage" ) func main() { cfg, err := config.Load() if err != nil { log.Fatalf("加载配置失败: %v", err) } startedAt := time.Now() // 初始化数据库连接 db, err := database.Open(cfg.DatabaseDSN) if err != nil { log.Fatalf("初始化数据库失败: %v", err) } store, err := storage.NewProductStore(db) if err != nil { log.Fatalf("初始化商品存储失败: %v", err) } orderStore, err := storage.NewOrderStore(db) if err != nil { log.Fatalf("初始化订单存储失败: %v", err) } siteStore, err := storage.NewSiteStore(db) if err != nil { log.Fatalf("初始化站点存储失败: %v", err) } wishlistStore, err := storage.NewWishlistStore(db) if err != nil { log.Fatalf("初始化收藏夹存储失败: %v", err) } chatStore, err := storage.NewChatStore(db) if err != nil { log.Fatalf("初始化聊天存储失败: %v", err) } ctx, cancel := context.WithCancel(context.Background()) defer cancel() var mqClient *mq.Client if cfg.RabbitMQEnabled { if cfg.RabbitMQURL == "" { log.Println("[MQ] 已启用但未配置连接串:请设置 RABBITMQ_URL,或设置 RABBITMQ_PASSWORD(及可选 RABBITMQ_HOST/RABBITMQ_VHOST)") } else { c, err := mq.New(cfg.RabbitMQURL, cfg.RabbitMQEnv) if err != nil { log.Printf("[MQ] 连接失败,将仅用直发邮件降级: %v", err) } else { mqClient = c defer mqClient.Close() go mqClient.StartConsumer(ctx, siteStore) log.Printf("[MQ] 已连接 env=%s exchange=%s", cfg.RabbitMQEnv, mq.ExchangeName(cfg.RabbitMQEnv)) } } } r := gin.Default() r.Use(cors.New(cors.Config{ AllowOrigins: []string{"*"}, AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization", "X-Admin-Token"}, ExposeHeaders: []string{"Content-Length"}, AllowCredentials: false, MaxAge: 12 * time.Hour, })) r.GET("/api/health", func(c *gin.Context) { resp := gin.H{"status": "ok", "rabbitmq": "disabled"} if mqClient != nil { if err := mqClient.Ping(); err != nil { resp["rabbitmq"] = "error: " + err.Error() } else { resp["rabbitmq"] = "ok" } } c.JSON(http.StatusOK, resp) }) authClient := auth.NewSproutGateClient(cfg.AuthAPIURL) publicHandler := handlers.NewPublicHandler(store) adminHandler := handlers.NewAdminHandler(store, cfg, siteStore, orderStore, chatStore) orderHandler := handlers.NewOrderHandler(store, orderStore, siteStore, authClient, mqClient) statsHandler := handlers.NewStatsHandler(orderStore, siteStore) wishlistHandler := handlers.NewWishlistHandler(wishlistStore, authClient) chatHandler := handlers.NewChatHandler(chatStore, authClient) statusHandler := handlers.NewSystemStatusHandler(cfg, db, mqClient, startedAt) r.GET("/api/products", publicHandler.ListProducts) r.POST("/api/checkout", orderHandler.CreateOrder) r.POST("/api/products/:id/view", publicHandler.RecordProductView) r.GET("/api/stats", statsHandler.GetStats) r.POST("/api/site/visit", statsHandler.RecordVisit) r.GET("/api/site/maintenance", statsHandler.GetMaintenance) r.GET("/api/orders", orderHandler.ListMyOrders) r.POST("/api/orders/:id/confirm", orderHandler.ConfirmOrder) r.POST("/api/admin/verify", adminHandler.VerifyAdminToken) r.GET("/api/admin/products", adminHandler.ListAllProducts) r.POST("/api/admin/products", adminHandler.CreateProduct) r.PUT("/api/admin/products/:id", adminHandler.UpdateProduct) r.PATCH("/api/admin/products/:id/status", adminHandler.ToggleProduct) r.DELETE("/api/admin/products/:id", adminHandler.DeleteProduct) r.POST("/api/admin/site/maintenance", adminHandler.SetMaintenance) r.GET("/api/admin/site/smtp", adminHandler.GetSMTPConfig) r.POST("/api/admin/site/smtp", adminHandler.SetSMTPConfig) r.GET("/api/admin/orders", adminHandler.ListAllOrders) r.DELETE("/api/admin/orders/:id", adminHandler.DeleteOrder) r.GET("/api/admin/system-status", statusHandler.GetSystemStatus) r.GET("/api/wishlist", wishlistHandler.GetWishlist) r.POST("/api/wishlist", wishlistHandler.AddToWishlist) r.DELETE("/api/wishlist/:id", wishlistHandler.RemoveFromWishlist) // 用户聊天路由 r.GET("/api/chat/messages", chatHandler.GetMyMessages) r.POST("/api/chat/messages", chatHandler.SendMyMessage) // 管理员聊天路由 r.GET("/api/admin/chat", adminHandler.GetAllConversations) r.GET("/api/admin/chat/:account", adminHandler.GetConversation) r.POST("/api/admin/chat/:account", adminHandler.AdminReply) r.DELETE("/api/admin/chat/:account", adminHandler.ClearConversation) log.Println("萌芽小店后端启动于 http://localhost:8080") if err := r.Run(":8080"); err != nil { log.Fatalf("服务器启动失败: %v", err) } }