18c9354095
- 注入数据库、运行时配置、统一响应、文件存储和平台 AI 能力,补充业务读写工具与客户快捷操作契约。 - 移除模块内重复的组织、客户、工单、标签、技能、旧工作流、MCP 和迁移实现,将身份权限与业务主体交由宿主管理。 - 使用 libSQL 重构向量存储,并完善图片消息、访客身份、排队调度、企业微信和支持聊天页面。 - 统一 HTTP、DTO 与 WebSocket 的 snake_case 协议,补齐模块初始化、业务动作和公共载荷等回归测试。
110 lines
2.5 KiB
Go
110 lines
2.5 KiB
Go
package wxwork
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"reflect"
|
|
"strings"
|
|
"sync"
|
|
|
|
"code.tczkiot.com/wlw/ai-agent/internal/pkg/config"
|
|
|
|
"github.com/silenceper/wechat/v2/cache"
|
|
"github.com/silenceper/wechat/v2/work"
|
|
wxconfig "github.com/silenceper/wechat/v2/work/config"
|
|
)
|
|
|
|
type SettingsLoader func(ctx context.Context, prefix string) (map[string]string, error)
|
|
|
|
var runtime = struct {
|
|
sync.RWMutex
|
|
loader SettingsLoader
|
|
client *work.Work
|
|
config config.WxWorkConfig
|
|
}{}
|
|
|
|
// SetSettingsLoader enables demand-driven settings reads for embedded mode.
|
|
// No save hook or hot-reload process is required: each enterprise WeChat
|
|
// business call observes the latest values in the host settings table.
|
|
func SetSettingsLoader(loader SettingsLoader) {
|
|
runtime.Lock()
|
|
runtime.loader = loader
|
|
runtime.Unlock()
|
|
}
|
|
|
|
func Init() {
|
|
if err := refresh(); err != nil {
|
|
slog.Error("init enterprise WeChat settings failed", "error", err)
|
|
}
|
|
}
|
|
|
|
func refresh() error {
|
|
runtime.RLock()
|
|
loader := runtime.loader
|
|
runtime.RUnlock()
|
|
|
|
wxCfg := config.Current().WxWork
|
|
if loader != nil {
|
|
settings, err := loader(context.Background(), config.SettingsPrefix)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cfg, err := config.FromSettings(settings)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
wxCfg = cfg.WxWork
|
|
}
|
|
|
|
runtime.Lock()
|
|
defer runtime.Unlock()
|
|
if reflect.DeepEqual(runtime.config, wxCfg) {
|
|
return nil
|
|
}
|
|
runtime.config = wxCfg
|
|
runtime.client = nil
|
|
if !wxCfg.Enabled || strings.TrimSpace(wxCfg.CorpID) == "" || strings.TrimSpace(wxCfg.CorpSecret) == "" {
|
|
return nil
|
|
}
|
|
runtime.client = work.NewWork(&wxconfig.Config{
|
|
CorpID: wxCfg.CorpID,
|
|
CorpSecret: wxCfg.CorpSecret,
|
|
AgentID: wxCfg.AgentID,
|
|
RasPrivateKey: wxCfg.RSAPrivateKey,
|
|
Token: wxCfg.Token,
|
|
EncodingAESKey: wxCfg.EncodingAESKey,
|
|
Cache: cache.NewMemory(),
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func Enabled() bool {
|
|
if err := refresh(); err != nil {
|
|
slog.Error("read enterprise WeChat settings failed", "error", err)
|
|
return false
|
|
}
|
|
runtime.RLock()
|
|
defer runtime.RUnlock()
|
|
return runtime.client != nil && runtime.config.Enabled
|
|
}
|
|
|
|
func GetWorkCli() *work.Work {
|
|
if err := refresh(); err != nil {
|
|
slog.Error("read enterprise WeChat settings failed", "error", err)
|
|
return nil
|
|
}
|
|
runtime.RLock()
|
|
defer runtime.RUnlock()
|
|
return runtime.client
|
|
}
|
|
|
|
// CurrentConfig returns the latest enterprise WeChat settings from the host.
|
|
func CurrentConfig() (config.WxWorkConfig, error) {
|
|
if err := refresh(); err != nil {
|
|
return config.WxWorkConfig{}, err
|
|
}
|
|
runtime.RLock()
|
|
defer runtime.RUnlock()
|
|
return runtime.config, nil
|
|
}
|