Files
Geliebte 1ea8c9da9c feat: 初始化 Wails + React + Go 桌面应用模板
- Wails v2.16.0 + React 19 + TypeScript + Vite 7
- 插件系统(build tag 控制编译,plugin.json 运行时配置)
- 支付插件(授权、账号、订单、退款、账单)
- 高并发基础设施(任务池、批量处理器、限流器、环形缓冲、管道)
- Windows 系统托盘(Win32 API)
- CodeGraph 索引 + .memory 记忆包
- 默认图标 assets/icon.png
2026-09-17 19:31:17 +08:00

154 lines
3.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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: "高并发工具集,任务池、限流器等"},
},
}
}