初始化功能

This commit is contained in:
2025-12-02 21:00:26 +08:00
commit 3eee37fa55
13 changed files with 1773 additions and 0 deletions

128
cmd/server/main.go Normal file
View File

@@ -0,0 +1,128 @@
package main
import (
"fmt"
"log"
"net/http"
"time"
"xk-websocket-v2/internal/api"
"xk-websocket-v2/internal/manager"
"xk-websocket-v2/internal/model"
"xk-websocket-v2/internal/service"
"xk-websocket-v2/internal/turnserver"
"xk-websocket-v2/internal/ws"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
"github.com/gorilla/websocket"
"github.com/spf13/viper"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// ... (initConfig, initDB, initRedis 保持不变) ...
func initConfig() {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("configs")
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
log.Fatalf("❌ 无法读取配置文件: %v", err)
}
}
func initDB() *gorm.DB {
dsn := viper.GetString("database.dsn")
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatalf("❌ 数据库连接失败: %v", err)
}
db.AutoMigrate(&model.ChatMessage{})
return db
}
func initRedis() *redis.Client {
rdb := redis.NewClient(&redis.Options{
Addr: viper.GetString("redis.addr"),
Password: viper.GetString("redis.password"),
DB: viper.GetInt("redis.db"),
})
if _, err := rdb.Ping(rdb.Context()).Result(); err != nil {
log.Fatalf("❌ Redis 连接失败: %v", err)
}
return rdb
}
func main() {
initConfig()
db := initDB()
rdb := initRedis()
ws.StartWorkerPool()
defer ws.StopWorkerPool()
service.InitChatService(db, rdb)
go turnserver.Start()
r := gin.Default()
// 允许跨域 (重要:为了前端本地开发)
r.Use(func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-User-ID")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
})
r.GET("/ws", func(c *gin.Context) {
upgrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
return
}
userID := c.Query("user_id")
clientID := fmt.Sprintf("%s-%d", viper.GetString("app.node_id"), time.Now().UnixNano())
client := &manager.Client{ID: clientID, Conn: conn, SendQueue: make(chan []byte, 256)}
manager.Manager.Register(client)
if userID != "" {
service.ChatSvc.BindUser(client, userID)
}
client.SendQueue <- []byte(fmt.Sprintf(`{"clientId": "%s"}`, clientID))
for {
_, message, err := conn.ReadMessage()
if err != nil {
manager.Manager.Unregister(client)
break
}
// WebSocket 仅处理信令和心跳,不再处理 send_message (改走API)
// 但为了兼容,仍保留 PushTask
ws.PushTask(client, message)
}
})
apiGroup := r.Group("/api")
{
apiGroup.POST("/send", api.SendHandler)
apiGroup.POST("/send-to-user", api.SendToUserHandler)
apiGroup.POST("/bind", api.BindHandler)
apiGroup.GET("/check-user-online", api.CheckUserOnlineHandler)
apiGroup.GET("/messages", api.HistoryHandler)
apiGroup.GET("/messages/sync", api.SyncMessagesHandler)
apiGroup.GET("/health", api.HealthHandler)
apiGroup.GET("/ice-servers", api.ICEHandler)
// 新增:联系人列表
apiGroup.GET("/contacts", api.ContactListHandler)
}
port := viper.GetString("app.port")
log.Printf("🚀 服务启动在端口: %s", port)
r.Run(":" + port)
}