Files
mengyastore/mengyastore-backend-go/main.go

147 lines
5.0 KiB
Go
Raw 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"
"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)
}
}