refactor websocket message protocol, keep the only connection for all clients

This commit is contained in:
RockYang
2024-09-27 17:50:54 +08:00
parent 478bc32ddd
commit 2debe7e927
29 changed files with 407 additions and 567 deletions

View File

@@ -51,9 +51,9 @@ func NewServer(appConfig *types.AppConfig) *AppServer {
func (s *AppServer) Init(debug bool, client *redis.Client) {
if debug { // 调试模式允许跨域请求 API
s.Debug = debug
s.Engine.Use(corsMiddleware())
logger.Info("Enabled debug mode")
}
s.Engine.Use(corsMiddleware())
s.Engine.Use(staticResourceMiddleware())
s.Engine.Use(authorizeMiddleware(s, client))
s.Engine.Use(parameterHandlerMiddleware())
@@ -101,9 +101,9 @@ func corsMiddleware() gin.HandlerFunc {
c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
//允许跨域设置可以返回其他子段,可以自定义字段
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, Content-Type, Chat-Token, Admin-Authorization")
c.Header("Access-Control-Allow-Headers", "Authorization, Body-Length, Body-Type, Admin-Authorization,content-type")
// 允许浏览器(客户端)可以解析的头部 (重要)
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
c.Header("Access-Control-Expose-Headers", "Body-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
//设置缓存时间
c.Header("Access-Control-Max-Age", "172800")
//允许客户端传递校验信息比如 cookie (重要)
@@ -131,7 +131,7 @@ func authorizeMiddleware(s *AppServer, client *redis.Client) gin.HandlerFunc {
isAdminApi := strings.Contains(c.Request.URL.Path, "/api/admin/")
if isAdminApi { // 后台管理 API
tokenString = c.GetHeader(types.AdminAuthHeader)
} else if c.Request.URL.Path == "/api/chat/new" {
} else if c.Request.URL.Path == "/api/ws" { // Websocket 连接
tokenString = c.Query("token")
} else {
tokenString = c.GetHeader(types.UserAuthHeader)
@@ -209,23 +209,18 @@ func needLogin(c *gin.Context) bool {
c.Request.URL.Path == "/api/app/list/user" ||
c.Request.URL.Path == "/api/model/list" ||
c.Request.URL.Path == "/api/mj/imgWall" ||
c.Request.URL.Path == "/api/mj/client" ||
c.Request.URL.Path == "/api/mj/notify" ||
c.Request.URL.Path == "/api/invite/hits" ||
c.Request.URL.Path == "/api/sd/imgWall" ||
c.Request.URL.Path == "/api/sd/client" ||
c.Request.URL.Path == "/api/dall/imgWall" ||
c.Request.URL.Path == "/api/dall/client" ||
c.Request.URL.Path == "/api/product/list" ||
c.Request.URL.Path == "/api/menu/list" ||
c.Request.URL.Path == "/api/markMap/client" ||
c.Request.URL.Path == "/api/payment/doPay" ||
c.Request.URL.Path == "/api/payment/payWays" ||
c.Request.URL.Path == "/api/suno/client" ||
c.Request.URL.Path == "/api/suno/detail" ||
c.Request.URL.Path == "/api/suno/play" ||
c.Request.URL.Path == "/api/download" ||
c.Request.URL.Path == "/api/video/client" ||
strings.HasPrefix(c.Request.URL.Path, "/api/test") ||
strings.HasPrefix(c.Request.URL.Path, "/api/payment/notify/") ||
strings.HasPrefix(c.Request.URL.Path, "/api/user/clogin") ||

View File

@@ -52,14 +52,13 @@ type Delta struct {
// ChatSession 聊天会话对象
type ChatSession struct {
SessionId string `json:"session_id"`
UserId uint `json:"user_id"`
ClientIP string `json:"client_ip"` // 客户端 IP
ChatId string `json:"chat_id"` // 客户端聊天会话 ID, 多会话模式专用字段
Model ChatModel `json:"model"` // GPT 模型
Start int64 `json:"start"` // 开始请求时间戳
Tools []int `json:"tools"` // 工具函数列表
Stream bool `json:"stream"` // 是否采用流式输出
UserId uint `json:"user_id"`
ClientIP string `json:"client_ip"` // 客户端 IP
ChatId string `json:"chat_id"` // 客户端聊天会话 ID, 多会话模式专用字段
Model ChatModel `json:"model"` // GPT 模型
Start int64 `json:"start"` // 开始请求时间戳
Tools []int `json:"tools"` // 工具函数列表
Stream bool `json:"stream"` // 是否采用流式输出
}
type ChatModel struct {

View File

@@ -17,15 +17,17 @@ var ErrConClosed = errors.New("connection Closed")
// WsClient websocket client
type WsClient struct {
Id string
Conn *websocket.Conn
lock sync.Mutex
mt int
Closed bool
}
func NewWsClient(conn *websocket.Conn) *WsClient {
func NewWsClient(conn *websocket.Conn, id string) *WsClient {
return &WsClient{
Conn: conn,
Id: id,
lock: sync.Mutex{},
mt: 2, // fixed bug for 'Invalid UTF-8 in text frame'
Closed: false,

View File

@@ -19,35 +19,44 @@ type BizVo struct {
// ReplyMessage 对话回复消息结构
type ReplyMessage struct {
Channel WsChannel `json:"channel"` // 消息频道,目前只有 chat
Type WsMsgType `json:"type"` // 消息类别
Content interface{} `json:"content"`
Channel WsChannel `json:"channel"` // 消息频道,目前只有 chat
ClientId string `json:"clientId"` // 客户端ID
Type WsMsgType `json:"type"` // 消息类别
Body interface{} `json:"body"`
}
type WsMsgType string
type WsChannel string
const (
WsMsgTypeContent = WsMsgType("content") // 输出内容
WsMsgTypeEnd = WsMsgType("end")
WsMsgTypeErr = WsMsgType("error")
WsMsgTypePing = WsMsgType("ping") // 心跳消息
MsgTypeText = WsMsgType("text") // 输出内容
MsgTypeEnd = WsMsgType("end")
MsgTypeErr = WsMsgType("error")
MsgTypePing = WsMsgType("ping") // 心跳消息
WsChat = WsChannel("chat")
WsMj = WsChannel("mj")
WsSd = WsChannel("sd")
WsDall = WsChannel("dall")
WsSuno = WsChannel("suno")
WsLuma = WsChannel("luma")
ChPing = WsChannel("ping")
ChChat = WsChannel("chat")
ChMj = WsChannel("mj")
ChSd = WsChannel("sd")
ChDall = WsChannel("dall")
ChSuno = WsChannel("suno")
ChLuma = WsChannel("luma")
)
// InputMessage 对话输入消息结构
type InputMessage struct {
Channel WsChannel `json:"channel"` // 消息频道
Type WsMsgType `json:"type"` // 消息类别
Content string `json:"content"`
Tools []int `json:"tools"` // 允许调用工具列表
Stream bool `json:"stream"` // 是否采用流式输出
Channel WsChannel `json:"channel"` // 消息频道
Type WsMsgType `json:"type"` // 消息类别
Body interface{} `json:"body"`
}
type ChatMessage struct {
Tools []int `json:"tools,omitempty"` // 允许调用工具列表
Stream bool `json:"stream,omitempty"` // 是否采用流式输出
RoleId int `json:"role_id"`
ModelId int `json:"model_id"`
ChatId string `json:"chat_id"`
Content string `json:"content"`
}
type BizCode int