package plugins import ( "encoding/json" "os" "path/filepath" "sync" ) // Config 插件配置文件结构 type Config struct { Version string `json:"version"` Plugins map[string]PluginOption `json:"plugins"` } // PluginOption 单个插件配置项 type PluginOption struct { Enabled bool `json:"enabled"` Description string `json:"description"` // Params 插件专用参数,由插件自己解析 Params map[string]interface{} `json:"params,omitempty"` } // Loader 插件配置加载器 type Loader struct { mu sync.RWMutex cfg *Config path string } // NewLoader 创建配置加载器 func NewLoader(path string) *Loader { return &Loader{path: path} } // Load 从文件加载配置 func (l *Loader) Load() (*Config, error) { l.mu.Lock() defer l.mu.Unlock() data, err := os.ReadFile(l.path) if err != nil { return nil, err } var cfg Config if err := json.Unmarshal(data, &cfg); err != nil { return nil, err } // 环境变量覆盖优先级最高 if v := os.Getenv("PLUGIN_ICONFONT"); v == "false" || v == "0" { tmp := cfg.Plugins["iconfont"]; tmp.Enabled = false; cfg.Plugins["iconfont"] = tmp } if v := os.Getenv("PLUGIN_AI"); v == "true" || v == "1" { tmp := cfg.Plugins["ai"]; tmp.Enabled = true; cfg.Plugins["ai"] = tmp } if v := os.Getenv("PLUGIN_CONCURRENT"); v == "false" || v == "0" { tmp := cfg.Plugins["concurrent"]; tmp.Enabled = false; cfg.Plugins["concurrent"] = tmp } l.cfg = &cfg return l.cfg, nil } // IsEnabled 查询插件启用状态 func (l *Loader) IsEnabled(name string) bool { l.mu.RLock() defer l.mu.RUnlock() if l.cfg == nil { return false } pc, ok := l.cfg.Plugins[name] return ok && pc.Enabled } // GetEnabledNames 返回所有已启用插件名 func (l *Loader) GetEnabledNames() []string { l.mu.RLock() defer l.mu.RUnlock() if l.cfg == nil { return nil } result := make([]string, 0) for name, pc := range l.cfg.Plugins { if pc.Enabled { result = append(result, name) } } return result } // Save 保存配置 func (l *Loader) Save(cfg *Config) error { l.mu.Lock() defer l.mu.Unlock() data, err := json.MarshalIndent(cfg, "", " ") if err != nil { return err } dir := filepath.Dir(l.path) if err := os.MkdirAll(dir, 0755); err != nil { return err } return os.WriteFile(l.path, data, 0644) } // LoadOrDefault 加载配置,找不到则返回默认值 func LoadOrDefault() (*Config, error) { paths := []string{"config/plugin.json", "./plugin.json"} exe, _ := os.Executable() if exe != "" { dir := filepath.Dir(exe) paths = append([]string{ filepath.Join(dir, "config", "plugin.json"), filepath.Join(dir, "plugin.json"), }, paths...) } for _, p := range paths { if _, err := os.Stat(p); err == nil { loader := NewLoader(p) if cfg, err := loader.Load(); err == nil { return cfg, nil } } } return defaultConfig(), nil } // EnsureConfig 确保配置文件存在 func EnsureConfig() error { _, err := os.Stat("config/plugin.json") if err == nil { return nil } cfg, _ := LoadOrDefault() loader := NewLoader("config/plugin.json") if mkErr := os.MkdirAll("config", 0755); mkErr != nil { return mkErr } return loader.Save(cfg) } func defaultConfig() *Config { return &Config{ Version: "1.0.0", Plugins: map[string]PluginOption{ "iconfont": {Enabled: false, Description: "阿里IconFont图标库,支持字体图标"}, "ai": {Enabled: false, Description: "AI大模型集成,支持对话、分析等功能"}, "concurrent": {Enabled: true, Description: "高并发工具集,任务池、限流器等"}, }, } }