初始化功能

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

209
internal/api/handler.go Normal file
View File

@@ -0,0 +1,209 @@
/**
* package api
* 作用:处理 HTTP 请求接口,包括消息发送、历史记录、系统状态检查等。
* 说明V2 版本中消息发送主要通过 HTTP 接口进行,而非 WebSocket 直接推送。
*/
package api
import (
"fmt"
"net/http"
"time"
"xk-websocket-v2/internal/manager"
"xk-websocket-v2/internal/model"
"xk-websocket-v2/internal/service"
"xk-websocket-v2/internal/turnserver"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
)
// ==========================================
// 消息发送相关接口
// ==========================================
/**
* SendHandler
* 功能:通用消息发送接口 (HTTP -> WebSocket)。
* 路径POST /api/send
* 逻辑:支持通过 target_client_id 或 receiver_user_id 发送。
* 重要:必须正确处理 SenderClientID防止多端同步时误通知发送端自己。
*/
func SendHandler(c *gin.Context) {
var req model.SendMessageReq
// 1. 绑定并校验 JSON 参数
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的JSON参数"})
return
}
// 2. 获取发送者 ID (从 Header 中获取,模拟鉴权)
// 生产环境应从 JWT Token 中解析 UserID
senderID := c.GetHeader("X-User-ID")
if senderID == "" {
senderID = "system" // 默认为系统消息
}
// 3. [关键修复] 获取发送端的 WebSocket ClientID
// 前端在调用此接口时,必须带上自己的 socket_client_id
// 如果前端没传 (兼容旧代码),则 fallback 到 api-gateway这会导致发送端自己也收到"其他设备接听"通知
clientID := req.SenderClientID
if clientID == "" {
clientID = "api-gateway"
}
// 4. 构造临时的发送者客户端对象
// 这个对象将传递给 Service 层,用于识别消息来源
mockClient := &manager.Client{
UserID: senderID,
ID: clientID,
}
// 5. 调用核心业务逻辑处理消息
service.ChatSvc.HandleUserMessage(mockClient, &req)
// 6. 返回成功响应
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}
/**
* SendToUserHandler (V1 兼容)
* 功能:专门用于给指定用户发送消息。
* 路径POST /api/send-to-user
*/
func SendToUserHandler(c *gin.Context) {
// 复用 SendHandler因为 V2 的 SendHandler 已经支持 ReceiverUserID
SendHandler(c)
}
// ==========================================
// 用户与连接管理接口
// ==========================================
/**
* BindHandler
* 功能:手动绑定 ClientID 和 UserID。
* 路径POST /api/bind
* 场景:当 WebSocket 连接建立后,客户端通过 HTTP 接口补充用户信息。
*/
func BindHandler(c *gin.Context) {
var req model.BindReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
return
}
// 调用服务层进行绑定
service.ChatSvc.BindUserByClientID(req.ClientID, req.UserID)
c.JSON(http.StatusOK, gin.H{"status": "success"})
}
/**
* CheckUserOnlineHandler
* 功能:检查用户是否在线。
* 路径GET /api/check-user-online
*/
func CheckUserOnlineHandler(c *gin.Context) {
userID := c.Query("user_id")
// 调用服务层查询 Redis
isOnline := service.ChatSvc.IsUserOnline(userID)
c.JSON(http.StatusOK, gin.H{"status": "success", "result": isOnline})
}
// ==========================================
// 数据查询接口
// ==========================================
/**
* HistoryHandler
* 功能:获取历史消息记录 (分页)。
* 路径GET /api/messages
*/
func HistoryHandler(c *gin.Context) {
roomID := c.Query("room_id")
var msgs []model.ChatMessage
// 简单查询最近 50 条
// 生产环境应添加 page, page_size 参数
result := service.ChatSvc.DB.Where("room_id = ?", roomID).
Order("created_at desc").Limit(50).Find(&msgs)
if result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "db error"})
return
}
c.JSON(http.StatusOK, gin.H{"data": msgs})
}
/**
* SyncMessagesHandler
* 功能:全量同步消息 (V1 兼容)。
* 路径GET /api/messages/sync
*/
func SyncMessagesHandler(c *gin.Context) {
HistoryHandler(c)
}
/**
* ContactListHandler
* 功能:获取联系人列表 (模拟数据)。
* 路径GET /api/contacts
* 说明:用于前端展示登录后的好友列表。
*/
func ContactListHandler(c *gin.Context) {
// 模拟 10 个用户数据
users := []model.UserContact{
{ID: "1001", Name: "张三 (我)", Avatar: "张", Desc: "Golang 专家"},
{ID: "1002", Name: "李琦 (妻)", Avatar: "李", Desc: "在线"},
{ID: "1003", Name: "王医生", Avatar: "医", Desc: "主任医师"},
{ID: "1004", Name: "客服小蜜", Avatar: "客", Desc: "全天在线"},
{ID: "1005", Name: "技术支持", Avatar: "技", Desc: "请重启试试"},
{ID: "1006", Name: "财务小赵", Avatar: "财", Desc: "报销单请提交"},
{ID: "1007", Name: "运维阿强", Avatar: "运", Desc: "服务器维护中"},
{ID: "1008", Name: "测试小丽", Avatar: "测", Desc: "Bug 太多了"},
{ID: "1009", Name: "HR", Avatar: "人", Desc: "本月考勤异常"},
{ID: "1010", Name: "老板", Avatar: "老", Desc: "今晚开会"},
}
c.JSON(http.StatusOK, gin.H{"data": users})
}
// ==========================================
// 系统与 WebRTC 接口
// ==========================================
/**
* HealthHandler
* 功能:服务健康检查。
* 路径GET /api/health
*/
func HealthHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"node": viper.GetString("app.node_id"),
"time": time.Now().Format(time.RFC3339),
})
}
/**
* ICEHandler
* 功能:获取 TURN/STUN 服务器配置及临时凭证。
* 路径GET /api/ice-servers
* 用途WebRTC 前端在建立 PeerConnection 前需调用此接口。
*/
func ICEHandler(c *gin.Context) {
userID := c.Query("user_id")
// 生成临时凭证 (HMAC-SHA1)
username, credential := turnserver.GenerateCredentials(userID)
// 从配置读取公网IP和端口
ip := viper.GetString("turn.public_ip")
port := viper.GetInt("turn.listen_port")
// 构造配置返回给前端
cfg := model.ICEServerConfig{
Urls: []string{fmt.Sprintf("turn:%s:%d", ip, port)},
Username: username,
Credential: credential,
}
c.JSON(http.StatusOK, gin.H{"data": []model.ICEServerConfig{cfg}})
}