fix: add lock map data structure, fixed bug for 'concurrent map writes'

This commit is contained in:
RockYang
2023-06-16 15:32:11 +08:00
parent c9875d24b4
commit 111572e3f2
10 changed files with 191 additions and 54 deletions

View File

@@ -23,14 +23,14 @@ var logger = logger2.GetLogger()
type AppServer struct {
AppConfig *types.AppConfig
Engine *gin.Engine
ChatContexts map[string][]types.Message // 聊天上下文 [chatId] => []Message
ChatConfig *types.ChatConfig // 聊天配置
ChatContexts *types.LMap[string, []types.Message] // 聊天上下文 Map [chatId] => []Message
ChatConfig *types.ChatConfig // 聊天配置
// 保存 Websocket 会话 UserId, 每个 UserId 只能连接一次
// 防止第三方直接连接 socket 调用 OpenAI API
ChatSession map[string]types.ChatSession //map[sessionId]UserId
ChatClients map[string]*WsClient // Websocket 连接集合
ReqCancelFunc map[string]context.CancelFunc // HttpClient 请求取消 handle function
ChatSession *types.LMap[string, types.ChatSession] //map[sessionId]UserId
ChatClients *types.LMap[string, *types.WsClient] // Websocket 连接集合
ReqCancelFunc *types.LMap[string, context.CancelFunc] // HttpClient 请求取消 handle function
}
func NewServer(appConfig *types.AppConfig) *AppServer {
@@ -39,10 +39,10 @@ func NewServer(appConfig *types.AppConfig) *AppServer {
return &AppServer{
AppConfig: appConfig,
Engine: gin.Default(),
ChatContexts: make(map[string][]types.Message, 16),
ChatSession: make(map[string]types.ChatSession),
ChatClients: make(map[string]*WsClient),
ReqCancelFunc: make(map[string]context.CancelFunc),
ChatContexts: types.NewLMap[string, []types.Message](),
ChatSession: types.NewLMap[string, types.ChatSession](),
ChatClients: types.NewLMap[string, *types.WsClient](),
ReqCancelFunc: types.NewLMap[string, context.CancelFunc](),
}
}
@@ -149,7 +149,8 @@ func authorizeMiddleware(s *AppServer) gin.HandlerFunc {
// WebSocket 连接请求验证
if c.Request.URL.Path == "/api/chat" {
sessionId := c.Query("sessionId")
if session, ok := s.ChatSession[sessionId]; ok && session.ClientIP == c.ClientIP() {
session := s.ChatSession.Get(sessionId)
if session.ClientIP == c.ClientIP() {
c.Next()
} else {
c.Abort()

View File

@@ -1,4 +1,4 @@
package core
package types
import (
"errors"

View File

@@ -0,0 +1,63 @@
package types
import (
"context"
"sync"
)
type MKey interface {
string | int
}
type MValue interface {
*WsClient | ChatSession | []Message | context.CancelFunc
}
type LMap[K MKey, T MValue] struct {
lock sync.RWMutex
data map[K]T
}
func NewLMap[K MKey, T MValue]() *LMap[K, T] {
return &LMap[K, T]{
lock: sync.RWMutex{},
data: make(map[K]T),
}
}
func (m *LMap[K, T]) Put(key K, value T) {
m.lock.Lock()
defer m.lock.Unlock()
m.data[key] = value
}
func (m *LMap[K, T]) Get(key K) T {
m.lock.RLock()
defer m.lock.RUnlock()
return m.data[key]
}
func (m *LMap[K, T]) Has(key K) bool {
m.lock.RLock()
defer m.lock.RUnlock()
_, ok := m.data[key]
return ok
}
func (m *LMap[K, T]) Delete(key K) {
m.lock.Lock()
defer m.lock.Unlock()
delete(m.data, key)
}
func (m *LMap[K, T]) ToList() []T {
m.lock.Lock()
defer m.lock.Unlock()
var s = make([]T, 0)
for _, v := range m.data {
s = append(s, v)
}
return s
}