96 lines
2.5 KiB
Go
96 lines
2.5 KiB
Go
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)
|
|
}
|