package modules import ( "crypto/rand" "encoding/hex" "fmt" "net/http" "github.com/gin-gonic/gin" "github.com/lineup/app-server/internal/wkapi" "github.com/spf13/viper" ) // UserModule 用户模块: 登录 / 注册 type UserModule struct { vp *viper.Viper wk *wkapi.Client } // RegisterRoutes 注册路由 func (m *UserModule) RegisterRoutes(r *gin.Engine) { r.POST("/login", m.handleLogin) } // LoginRequest 登录请求 type LoginRequest struct { Phone string `json:"phone" binding:"required"` Code string `json:"code" binding:"required"` } // LoginResponse 登录响应 type LoginResponse struct { UID string `json:"uid"` Token string `json:"token"` IMAddr string `json:"im_addr"` // WuKongIM WS地址 AgentUID string `json:"agent_uid"` // Agent的UID ChannelID string `json:"channel_id"` // Agent频道ID ChannelType uint8 `json:"channel_type"` // Agent频道类型 } // handleLogin 处理登录请求 func (m *UserModule) handleLogin(c *gin.Context) { var req LoginRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误: phone和code必填"}) return } // 生成用户 UID uid := fmt.Sprintf("user_%s", req.Phone) // 生成 Token (随机32字节) token := generateToken() // 注册 Token 到 WuKongIM if err := m.wk.RegisterToken(uid, token); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("注册Token失败: %v", err)}) return } // 确保 Agent 频道存在并将用户加入订阅者 agentChannelID := m.vp.GetString("agent.channelID") agentUID := m.vp.GetString("agent.uid") agentChannelType := uint8(m.vp.GetInt("agent.channelType")) if agentChannelType == 0 { agentChannelType = 2 } // 创建/更新频道,确保 Agent 和用户都是订阅者 m.wk.UpsertChannel(agentChannelID, agentChannelType, []string{agentUID}) // 将用户加入频道订阅者 m.wk.SubscriberAdd(agentChannelID, agentChannelType, []string{uid}) // 获取 WebSocket 地址 route, err := m.wk.GetRoute() wsAddr := m.vp.GetString("wukongim.wsAddr") if err == nil && route.WSAddr != "" { wsAddr = route.WSAddr } c.JSON(http.StatusOK, LoginResponse{ UID: uid, Token: token, IMAddr: wsAddr, AgentUID: m.vp.GetString("agent.uid"), ChannelID: m.vp.GetString("agent.channelID"), ChannelType: uint8(m.vp.GetInt("agent.channelType")), }) } // generateToken 生成32字节随机Token func generateToken() string { b := make([]byte, 32) rand.Read(b) return hex.EncodeToString(b) }