Ensure default channel and rebind Agent/Binding on list, ticket, agents/me, and ensure-binding so SyncPage does not stay on deleted-channel errors. Co-authored-by: Cursor <cursoragent@cursor.com>
106 lines
3.5 KiB
Go
106 lines
3.5 KiB
Go
package applogic
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
"aijianzhan/platform/internal/agentstore"
|
||
"aijianzhan/platform/internal/dbsync"
|
||
"aijianzhan/platform/internal/svc"
|
||
"aijianzhan/platform/internal/types"
|
||
"aijianzhan/platform/internal/userstore"
|
||
)
|
||
|
||
// fillAgentSyncOnToken Z12a:换票带回同步落点。
|
||
func fillAgentSyncOnToken(resp *types.TokenResp, acc *agentstore.Account) {
|
||
if resp == nil || acc == nil {
|
||
return
|
||
}
|
||
resp.ChannelID = strings.TrimSpace(acc.ChannelID)
|
||
resp.OnlineDBID = strings.TrimSpace(acc.OnlineDBID)
|
||
resp.DatabaseName = strings.TrimSpace(acc.DatabaseName)
|
||
resp.SyncBound = resp.ChannelID != "" && resp.OnlineDBID != ""
|
||
}
|
||
|
||
// fillUserSyncOnToken:人类登录优先从本人 Binding 带回落点。
|
||
func fillUserSyncOnToken(svcCtx *svc.ServiceContext, resp *types.TokenResp, u *userstore.User) {
|
||
if resp == nil || u == nil || svcCtx == nil || svcCtx.DBSync == nil || u.TenantID <= 0 {
|
||
return
|
||
}
|
||
list, err := svcCtx.DBSync.Store().ListBindingsFiltered(u.TenantID, u.UserID, "")
|
||
if err != nil || len(list) == 0 {
|
||
return
|
||
}
|
||
b := list[0]
|
||
for i := range list {
|
||
if list[i].ChannelID != "" && list[i].OnlineDBID != "" {
|
||
b = list[i]
|
||
break
|
||
}
|
||
}
|
||
resp.ChannelID = strings.TrimSpace(b.ChannelID)
|
||
resp.OnlineDBID = strings.TrimSpace(b.OnlineDBID)
|
||
resp.DatabaseName = strings.TrimSpace(b.DatabaseName)
|
||
if resp.DatabaseName == "" {
|
||
resp.DatabaseName = strings.TrimSpace(b.DisplayName)
|
||
}
|
||
resp.SyncBound = resp.ChannelID != "" && resp.OnlineDBID != ""
|
||
}
|
||
|
||
// ensureAgentSyncBind Z12c/Z12h:无通道或通道已删除时,创建/复用默认同步通道并写回智能体。
|
||
func (l *AgentAdminLogic) ensureAgentSyncBind(acc *agentstore.Account) (*agentstore.Account, error) {
|
||
if acc == nil {
|
||
return nil, fmt.Errorf("agent nil")
|
||
}
|
||
if l.svcCtx.DBSync == nil {
|
||
return acc, nil
|
||
}
|
||
alive := channelAlive(l.svcCtx.DBSync.Store(), acc.TenantID, acc.ChannelID)
|
||
if alive && strings.TrimSpace(acc.OnlineDBID) != "" {
|
||
return acc, nil
|
||
}
|
||
if _, err := HealTenantSyncBind(l.ctx, l.svcCtx, acc.TenantID); err != nil {
|
||
return nil, fmt.Errorf("heal sync bind: %w", err)
|
||
}
|
||
st, err := l.store()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
updated, err := st.Get(l.ctx, acc.TenantID, acc.AgentID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// 若 heal 未覆盖该智能体(例如无 Binding 仅 Agent),再显式挂一次
|
||
if !channelAlive(l.svcCtx.DBSync.Store(), updated.TenantID, updated.ChannelID) || strings.TrimSpace(updated.OnlineDBID) == "" {
|
||
cfg := l.svcCtx.Config.DBSync
|
||
driver := dbsync.Driver(strings.TrimSpace(cfg.DefaultRemoteDriver))
|
||
if driver == "" {
|
||
driver = dbsync.DriverPostgres
|
||
}
|
||
ch, err := l.svcCtx.DBSync.EnsureAndStartSystemDefaultChannel(dbsync.DefaultChannelOpts{
|
||
TenantID: acc.TenantID,
|
||
AgentID: acc.AgentID,
|
||
Name: fmt.Sprintf("默认同步 · %s", acc.Name),
|
||
RemoteDriver: driver,
|
||
RemoteDSN: strings.TrimSpace(cfg.DefaultRemoteDSN),
|
||
DatabaseName: acc.DatabaseName,
|
||
})
|
||
if err != nil {
|
||
return nil, fmt.Errorf("ensure default channel: %w", err)
|
||
}
|
||
online := strings.TrimSpace(updated.OnlineDBID)
|
||
if online == "" {
|
||
online = dbsync.ResolveOnlineDBID("", ch.ID)
|
||
}
|
||
dbName := strings.TrimSpace(updated.DatabaseName)
|
||
if dbName == "" {
|
||
dbName = fmt.Sprintf("agent_%d", updated.AgentID)
|
||
}
|
||
updated, err = st.AttachSyncBind(l.ctx, updated.AgentID, updated.TenantID, ch.ID, online, dbName, updated.Status == agentstore.StatusActive || updated.Status == "")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
return updated, nil
|
||
}
|