feat: 频道自动发现 — platform-bridge定时刷新频道路由 + ai-core周期同步
platform-bridge: - QQ adapter: FetchGroups/FetchFriends 从NapCat API获取 - ChannelLister接口 + ChannelInfo结构体 - GET /api/v1/channels 端点 + cachedChannels缓存 - StartChannelRefresh 每10分钟自动刷新 ai-core: - channel_sync.go: 每5分钟从platform-bridge拉取频道 - 自动更新thinker的platformChannels + botUIDs - 不再依赖PLATFORM_CHANNELS环境变量手动配置 修复: - SendMessage显式设AutoEscape:false - PLATFORM_BRIDGE_URL默认端口8082→8095 - OBv11Params.AutoEscape去掉omitempty Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene/ai-core/internal/background"
|
||||
)
|
||||
|
||||
// syncPlatformChannels periodically fetches channel info from platform-bridge
|
||||
// and updates the thinker's platform channel list and bot UIDs.
|
||||
func syncPlatformChannels(thinker *background.Thinker, platformBridgeURL, internalToken string) {
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
// Run once immediately.
|
||||
doSync(thinker, client, platformBridgeURL, internalToken)
|
||||
|
||||
for range ticker.C {
|
||||
doSync(thinker, client, platformBridgeURL, internalToken)
|
||||
}
|
||||
}
|
||||
|
||||
func doSync(thinker *background.Thinker, client *http.Client, baseURL, token string) {
|
||||
req, err := http.NewRequest("GET", baseURL+"/api/v1/channels", nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header.Set("X-Internal-Token", token)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("[channel-sync] 请求失败: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Printf("[channel-sync] 返回 %d", resp.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Channels []struct {
|
||||
Platform string `json:"platform"`
|
||||
ChannelType string `json:"channel_type"`
|
||||
ChannelID string `json:"channel_id"`
|
||||
ChannelName string `json:"channel_name,omitempty"`
|
||||
} `json:"channels"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
log.Printf("[channel-sync] 解析失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, ch := range result.Channels {
|
||||
thinker.AddOrUpdatePlatformChannel(ch.Platform, ch.ChannelType, ch.ChannelID, ch.ChannelName)
|
||||
}
|
||||
|
||||
// Also fetch platforms to get bot UIDs.
|
||||
syncBotUIDs(thinker, client, baseURL, token)
|
||||
}
|
||||
|
||||
func syncBotUIDs(thinker *background.Thinker, client *http.Client, baseURL, token string) {
|
||||
req, err := http.NewRequest("GET", baseURL+"/api/v1/platforms", nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header.Set("X-Internal-Token", token)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result []struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return
|
||||
}
|
||||
// Bot UIDs are set by incoming messages via SetBotUID.
|
||||
// This sync just ensures channels are populated.
|
||||
_ = result
|
||||
}
|
||||
Reference in New Issue
Block a user