|
@@ -107,7 +107,7 @@ func (m *ACPManager) CreateNewSession(userId string) (*ACPSession, error) {
|
|
|
|
|
|
|
|
// 归档当前活跃会话
|
|
// 归档当前活跃会话
|
|
|
if sess, ok := m.sessions[userId]; ok {
|
|
if sess, ok := m.sessions[userId]; ok {
|
|
|
- m.archiveToRedis(userId, sess)
|
|
|
|
|
|
|
+ m.archiveSession(userId, sess)
|
|
|
sess.Client.Close()
|
|
sess.Client.Close()
|
|
|
delete(m.sessions, userId)
|
|
delete(m.sessions, userId)
|
|
|
}
|
|
}
|
|
@@ -127,7 +127,7 @@ func (m *ACPManager) LoadSession(userId string, sessionId string) (*ACPSession,
|
|
|
return sess, nil
|
|
return sess, nil
|
|
|
}
|
|
}
|
|
|
// 归档当前活跃会话
|
|
// 归档当前活跃会话
|
|
|
- m.archiveToRedis(userId, sess)
|
|
|
|
|
|
|
+ m.archiveSession(userId, sess)
|
|
|
sess.Client.Close()
|
|
sess.Client.Close()
|
|
|
delete(m.sessions, userId)
|
|
delete(m.sessions, userId)
|
|
|
}
|
|
}
|
|
@@ -176,13 +176,8 @@ func (m *ACPManager) LoadSession(userId string, sessionId string) (*ACPSession,
|
|
|
client.UserId = userId
|
|
client.UserId = userId
|
|
|
m.sessions[userId] = sess
|
|
m.sessions[userId] = sess
|
|
|
|
|
|
|
|
- // 更新 Redis 活跃会话
|
|
|
|
|
- repositories.SaveAiSession(userId, repositories.AiActiveSession{
|
|
|
|
|
- SessionId: sess.SessionId,
|
|
|
|
|
- Title: sess.Title,
|
|
|
|
|
- CreatedAt: sess.CreatedAt.UnixMilli(),
|
|
|
|
|
- LastActive: sess.LastActive.UnixMilli(),
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ // 持久化
|
|
|
|
|
+ m.activateSession(userId, sess)
|
|
|
|
|
|
|
|
zap.L().Info("[AIChat] 会话加载成功", zap.String("userId", userId), zap.String("sessionId", sessionId))
|
|
zap.L().Info("[AIChat] 会话加载成功", zap.String("userId", userId), zap.String("sessionId", sessionId))
|
|
|
return sess, nil
|
|
return sess, nil
|
|
@@ -251,18 +246,12 @@ func (m *ACPManager) UpdateSessionTitle(userId string, sessionId string, title s
|
|
|
// 检查当前活跃会话
|
|
// 检查当前活跃会话
|
|
|
if sess, ok := m.sessions[userId]; ok && sess.SessionId == sessionId {
|
|
if sess, ok := m.sessions[userId]; ok && sess.SessionId == sessionId {
|
|
|
sess.Title = title
|
|
sess.Title = title
|
|
|
- // 同步到 Redis 活跃会话 key
|
|
|
|
|
- repositories.SaveAiSession(userId, repositories.AiActiveSession{
|
|
|
|
|
- SessionId: sess.SessionId,
|
|
|
|
|
- Title: sess.Title,
|
|
|
|
|
- CreatedAt: sess.CreatedAt.UnixMilli(),
|
|
|
|
|
- LastActive: sess.LastActive.UnixMilli(),
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ m.saveSessionTitle(userId, sess)
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 同步到 Redis 历史列表
|
|
|
|
|
- repositories.UpdateAiSessionTitle(userId, sessionId, title)
|
|
|
|
|
|
|
+ // 历史会话
|
|
|
|
|
+ m.saveHistorySessionTitle(userId, sessionId, title)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// DeleteSessionFromHistory 删除某会话
|
|
// DeleteSessionFromHistory 删除某会话
|
|
@@ -274,12 +263,12 @@ func (m *ACPManager) DeleteSessionFromHistory(userId string, sessionId string) {
|
|
|
if sess, ok := m.sessions[userId]; ok && sess.SessionId == sessionId {
|
|
if sess, ok := m.sessions[userId]; ok && sess.SessionId == sessionId {
|
|
|
sess.Client.Close()
|
|
sess.Client.Close()
|
|
|
delete(m.sessions, userId)
|
|
delete(m.sessions, userId)
|
|
|
- repositories.DeleteAiSession(userId)
|
|
|
|
|
|
|
+ m.removeSession(userId, sessionId, true)
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 从 Redis 历史列表中移除
|
|
|
|
|
- m.removeFromRedisHistory(userId, sessionId)
|
|
|
|
|
|
|
+ // 历史会话
|
|
|
|
|
+ m.removeSession(userId, sessionId, false)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// DeleteSession 删除当前活跃会话
|
|
// DeleteSession 删除当前活跃会话
|
|
@@ -290,7 +279,7 @@ func (m *ACPManager) DeleteSession(userId string) {
|
|
|
if sess, ok := m.sessions[userId]; ok {
|
|
if sess, ok := m.sessions[userId]; ok {
|
|
|
sess.Client.Close()
|
|
sess.Client.Close()
|
|
|
delete(m.sessions, userId)
|
|
delete(m.sessions, userId)
|
|
|
- repositories.DeleteAiSession(userId)
|
|
|
|
|
|
|
+ m.removeSession(userId, sess.SessionId, true)
|
|
|
zap.L().Info("[AIChat] 会话已删除", zap.String("userId", userId))
|
|
zap.L().Info("[AIChat] 会话已删除", zap.String("userId", userId))
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -395,13 +384,8 @@ func (m *ACPManager) createSession(userId string) (*ACPSession, error) {
|
|
|
client.UserId = userId
|
|
client.UserId = userId
|
|
|
m.sessions[userId] = sess
|
|
m.sessions[userId] = sess
|
|
|
|
|
|
|
|
- // 持久化活跃会话到 Redis
|
|
|
|
|
- repositories.SaveAiSession(userId, repositories.AiActiveSession{
|
|
|
|
|
- SessionId: sess.SessionId,
|
|
|
|
|
- Title: sess.Title,
|
|
|
|
|
- CreatedAt: sess.CreatedAt.UnixMilli(),
|
|
|
|
|
- LastActive: sess.LastActive.UnixMilli(),
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ // 持久化
|
|
|
|
|
+ m.saveNewSession(userId, sess)
|
|
|
|
|
|
|
|
zap.L().Info("[AIChat] 会话创建成功", zap.String("userId", userId), zap.String("sessionId", sessionId))
|
|
zap.L().Info("[AIChat] 会话创建成功", zap.String("userId", userId), zap.String("sessionId", sessionId))
|
|
|
return sess, nil
|
|
return sess, nil
|
|
@@ -439,8 +423,41 @@ func (m *ACPManager) startAndLoadSession(userId string, active *repositories.AiA
|
|
|
return sess, nil
|
|
return sess, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// archiveToRedis 将会话归档到 Redis 历史列表
|
|
|
|
|
-func (m *ACPManager) archiveToRedis(userId string, sess *ACPSession) {
|
|
|
|
|
|
|
+// ============ 内部方法:会话存储 ============
|
|
|
|
|
+
|
|
|
|
|
+// persistNewSession 持久化新创建的活跃会话(Redis + MongoDB)
|
|
|
|
|
+func (m *ACPManager) saveNewSession(userId string, sess *ACPSession) {
|
|
|
|
|
+ repositories.SaveAiSession(userId, repositories.AiActiveSession{
|
|
|
|
|
+ SessionId: sess.SessionId,
|
|
|
|
|
+ Title: sess.Title,
|
|
|
|
|
+ CreatedAt: sess.CreatedAt.UnixMilli(),
|
|
|
|
|
+ LastActive: sess.LastActive.UnixMilli(),
|
|
|
|
|
+ })
|
|
|
|
|
+ repositories.DeactivateAllAiChatSessions(userId)
|
|
|
|
|
+ repositories.UpsertAiChatSession(repositories.AiChatSession{
|
|
|
|
|
+ UserId: userId,
|
|
|
|
|
+ SessionId: sess.SessionId,
|
|
|
|
|
+ Title: sess.Title,
|
|
|
|
|
+ IsActive: true,
|
|
|
|
|
+ CreatedAt: sess.CreatedAt,
|
|
|
|
|
+ LastActive: sess.LastActive,
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// persistActivateSession 持久化会话激活(Redis + MongoDB)
|
|
|
|
|
+func (m *ACPManager) activateSession(userId string, sess *ACPSession) {
|
|
|
|
|
+ repositories.SaveAiSession(userId, repositories.AiActiveSession{
|
|
|
|
|
+ SessionId: sess.SessionId,
|
|
|
|
|
+ Title: sess.Title,
|
|
|
|
|
+ CreatedAt: sess.CreatedAt.UnixMilli(),
|
|
|
|
|
+ LastActive: sess.LastActive.UnixMilli(),
|
|
|
|
|
+ })
|
|
|
|
|
+ repositories.DeactivateAllAiChatSessions(userId)
|
|
|
|
|
+ repositories.UpdateAiChatSessionActive(userId, sess.SessionId, true)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// persistArchiveSession 持久化会话归档(Redis + MongoDB)
|
|
|
|
|
+func (m *ACPManager) archiveSession(userId string, sess *ACPSession) {
|
|
|
item := repositories.AiSessionItem{
|
|
item := repositories.AiSessionItem{
|
|
|
SessionId: sess.SessionId,
|
|
SessionId: sess.SessionId,
|
|
|
Title: sess.Title,
|
|
Title: sess.Title,
|
|
@@ -448,18 +465,12 @@ func (m *ACPManager) archiveToRedis(userId string, sess *ACPSession) {
|
|
|
LastActive: sess.LastActive.UnixMilli(),
|
|
LastActive: sess.LastActive.UnixMilli(),
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 读取现有历史
|
|
|
|
|
list, _ := repositories.GetAiSessionList(userId)
|
|
list, _ := repositories.GetAiSessionList(userId)
|
|
|
-
|
|
|
|
|
- // 插入头部
|
|
|
|
|
list = append([]repositories.AiSessionItem{item}, list...)
|
|
list = append([]repositories.AiSessionItem{item}, list...)
|
|
|
|
|
|
|
|
- // 超过 50 条:删除多余的 Kiro 会话
|
|
|
|
|
if len(list) > 50 {
|
|
if len(list) > 50 {
|
|
|
overflow := list[50:]
|
|
overflow := list[50:]
|
|
|
list = list[:50]
|
|
list = list[:50]
|
|
|
-
|
|
|
|
|
- // 后台异步删除多余会话
|
|
|
|
|
go func() {
|
|
go func() {
|
|
|
for _, old := range overflow {
|
|
for _, old := range overflow {
|
|
|
m.deleteKiroSession(old.SessionId)
|
|
m.deleteKiroSession(old.SessionId)
|
|
@@ -470,11 +481,37 @@ func (m *ACPManager) archiveToRedis(userId string, sess *ACPSession) {
|
|
|
if err := repositories.SaveAiSessionList(userId, list); err != nil {
|
|
if err := repositories.SaveAiSessionList(userId, list); err != nil {
|
|
|
zap.L().Warn("[AIChat] 归档会话到Redis失败", zap.String("userId", userId), zap.Error(err))
|
|
zap.L().Warn("[AIChat] 归档会话到Redis失败", zap.String("userId", userId), zap.Error(err))
|
|
|
}
|
|
}
|
|
|
|
|
+ repositories.UpdateAiChatSessionActive(userId, sess.SessionId, false)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// persistUpdateTitle 持久化标题更新(Redis + MongoDB)
|
|
|
|
|
+func (m *ACPManager) saveSessionTitle(userId string, sess *ACPSession) {
|
|
|
|
|
+ repositories.SaveAiSession(userId, repositories.AiActiveSession{
|
|
|
|
|
+ SessionId: sess.SessionId,
|
|
|
|
|
+ Title: sess.Title,
|
|
|
|
|
+ CreatedAt: sess.CreatedAt.UnixMilli(),
|
|
|
|
|
+ LastActive: sess.LastActive.UnixMilli(),
|
|
|
|
|
+ })
|
|
|
|
|
+ repositories.UpdateAiChatSessionTitle(userId, sess.SessionId, sess.Title)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// persistUpdateHistoryTitle 持久化历史会话标题更新(Redis + MongoDB)
|
|
|
|
|
+func (m *ACPManager) saveHistorySessionTitle(userId string, sessionId string, title string) {
|
|
|
|
|
+ repositories.UpdateAiSessionTitle(userId, sessionId, title)
|
|
|
|
|
+ repositories.UpdateAiChatSessionTitle(userId, sessionId, title)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// persistDeleteSession 持久化删除会话(Redis + MongoDB)
|
|
|
|
|
+func (m *ACPManager) removeSession(userId string, sessionId string, isActive bool) {
|
|
|
|
|
+ if isActive {
|
|
|
|
|
+ repositories.DeleteAiSession(userId)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ m.removeFromRedisHistory(userId, sessionId)
|
|
|
|
|
+ }
|
|
|
|
|
+ repositories.DeleteAiChatSession(userId, sessionId)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// archiveActiveSessionFromRedis 将 Redis session key 中的活跃会话归档到历史列表
|
|
|
|
|
-// 用于后端重启后、内存中无活跃会话时的归档保护
|
|
|
|
|
-// removeFromRedisHistory 从 Redis 历史列表中移除指定会话
|
|
|
|
|
|
|
+// ============ 内部方法:Redis 操作 ============
|
|
|
func (m *ACPManager) removeFromRedisHistory(userId string, sessionId string) {
|
|
func (m *ACPManager) removeFromRedisHistory(userId string, sessionId string) {
|
|
|
list, err := repositories.GetAiSessionList(userId)
|
|
list, err := repositories.GetAiSessionList(userId)
|
|
|
if err != nil || len(list) == 0 {
|
|
if err != nil || len(list) == 0 {
|