diff --git a/api/router.go b/api/router.go index c2ef914..8009031 100644 --- a/api/router.go +++ b/api/router.go @@ -78,10 +78,13 @@ func SetupRouter(searchService *service.SearchService) *gin.Engine { } // 注册插件的Web路由(如果插件实现了PluginWithWebHandler接口) - allPlugins := plugin.GetRegisteredPlugins() - for _, p := range allPlugins { - if webPlugin, ok := p.(plugin.PluginWithWebHandler); ok { - webPlugin.RegisterWebRoutes(r.Group("")) + // 只有当插件功能启用且插件在启用列表中时才注册路由 + if config.AppConfig.AsyncPluginEnabled && searchService != nil && searchService.GetPluginManager() != nil { + enabledPlugins := searchService.GetPluginManager().GetPlugins() + for _, p := range enabledPlugins { + if webPlugin, ok := p.(plugin.PluginWithWebHandler); ok { + webPlugin.RegisterWebRoutes(r.Group("")) + } } } diff --git a/plugin/gying/gying.go b/plugin/gying/gying.go index c47d397..ecd788e 100644 --- a/plugin/gying/gying.go +++ b/plugin/gying/gying.go @@ -52,20 +52,6 @@ var DefaultAccounts = []struct { var StorageDir string // 初始化存储目录 -func init() { - cachePath := os.Getenv("CACHE_PATH") - if cachePath == "" { - cachePath = "./cache" - } - - StorageDir = filepath.Join(cachePath, "gying_users") - - if err := os.MkdirAll(StorageDir, 0755); err != nil { - fmt.Printf("⚠️ 警告: 无法创建Gying存储目录 %s: %v\n", StorageDir, err) - } else { - fmt.Printf("✓ Gying存储目录: %s\n", StorageDir) - } -} // HTML模板 const HTMLTemplate = ` @@ -382,10 +368,11 @@ const HTMLTemplate = ` // GyingPlugin 插件结构 type GyingPlugin struct { *plugin.BaseAsyncPlugin - users sync.Map // 内存缓存:hash -> *User - scrapers sync.Map // cloudscraper实例缓存:hash -> *cloudscraper.Scraper - mu sync.RWMutex + users sync.Map // 内存缓存:hash -> *User + scrapers sync.Map // cloudscraper实例缓存:hash -> *cloudscraper.Scraper + mu sync.RWMutex searchCache sync.Map // 插件级缓存:关键词->model.PluginSearchResult + initialized bool // 初始化状态标记 } // User 用户数据结构 @@ -439,10 +426,25 @@ func init() { BaseAsyncPlugin: plugin.NewBaseAsyncPlugin("gying", 3), } + plugin.RegisterGlobalPlugin(p) +} + +// Initialize 实现 InitializablePlugin 接口,延迟初始化插件 +func (p *GyingPlugin) Initialize() error { + if p.initialized { + return nil + } + + // 初始化存储目录路径 + cachePath := os.Getenv("CACHE_PATH") + if cachePath == "" { + cachePath = "./cache" + } + StorageDir = filepath.Join(cachePath, "gying_users") + // 初始化存储目录 if err := os.MkdirAll(StorageDir, 0755); err != nil { - fmt.Printf("[Gying] 创建存储目录失败: %v\n", err) - return + return fmt.Errorf("创建存储目录失败: %v", err) } // 加载所有用户到内存 @@ -461,7 +463,8 @@ func init() { // 启动session保活任务(防止session超时) go p.startSessionKeepAlive() - plugin.RegisterGlobalPlugin(p) + p.initialized = true + return nil } // ============ 插件接口实现 ============ diff --git a/plugin/plugin.go b/plugin/plugin.go index 04f38c5..83a3c3d 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -52,6 +52,16 @@ type PluginWithWebHandler interface { RegisterWebRoutes(router *gin.RouterGroup) } +// InitializablePlugin 支持延迟初始化的插件接口 +// 插件可以实现此接口,将初始化逻辑延迟到真正被使用时执行 +type InitializablePlugin interface { + AsyncSearchPlugin // 继承搜索插件接口 + + // Initialize 执行插件初始化(创建目录、加载数据等) + // 只会被调用一次,应该是幂等的 + Initialize() error +} + // ============================================================ // 第二部分:全局变量和注册表 // ============================================================ @@ -167,6 +177,14 @@ func NewPluginManager() *PluginManager { // RegisterPlugin 注册异步插件 func (pm *PluginManager) RegisterPlugin(plugin AsyncSearchPlugin) { + // 如果插件支持延迟初始化,先执行初始化 + if initPlugin, ok := plugin.(InitializablePlugin); ok { + if err := initPlugin.Initialize(); err != nil { + fmt.Printf("[PluginManager] 插件 %s 初始化失败: %v,跳过注册\n", plugin.Name(), err) + return + } + } + pm.plugins = append(pm.plugins, plugin) } diff --git a/plugin/qqpd/qqpd.go b/plugin/qqpd/qqpd.go index 693ea3e..c6725d0 100644 --- a/plugin/qqpd/qqpd.go +++ b/plugin/qqpd/qqpd.go @@ -39,24 +39,6 @@ const ( var StorageDir string // 初始化存储目录 -func init() { - // 直接从环境变量读取缓存路径(不依赖config.AppConfig,避免初始化顺序问题) - cachePath := os.Getenv("CACHE_PATH") - if cachePath == "" { - // 如果环境变量未设置,使用默认值 - cachePath = "./cache" - } - - // 构建QQPD用户数据目录路径 - StorageDir = filepath.Join(cachePath, "qqpd_users") - - // 确保目录存在 - if err := os.MkdirAll(StorageDir, 0755); err != nil { - fmt.Printf("⚠️ 警告: 无法创建QQPD存储目录 %s: %v\n", StorageDir, err) - } else { - fmt.Printf("✓ QQPD存储目录: %s\n", StorageDir) - } -} // HTML模板(完整的管理页面) const HTMLTemplate = ` @@ -494,8 +476,9 @@ languan8K115"> // QQPDPlugin 插件结构 type QQPDPlugin struct { *plugin.BaseAsyncPlugin - users sync.Map // 内存缓存:hash -> *User - mu sync.RWMutex + users sync.Map // 内存缓存:hash -> *User + mu sync.RWMutex + initialized bool // 初始化状态标记 } // User 用户数据结构 @@ -530,10 +513,25 @@ func init() { BaseAsyncPlugin: plugin.NewBaseAsyncPlugin("qqpd", 3), } + plugin.RegisterGlobalPlugin(p) +} + +// Initialize 实现 InitializablePlugin 接口,延迟初始化插件 +func (p *QQPDPlugin) Initialize() error { + if p.initialized { + return nil + } + + // 初始化存储目录路径 + cachePath := os.Getenv("CACHE_PATH") + if cachePath == "" { + cachePath = "./cache" + } + StorageDir = filepath.Join(cachePath, "qqpd_users") + // 初始化存储目录 if err := os.MkdirAll(StorageDir, 0755); err != nil { - fmt.Printf("[QQPD] 创建存储目录失败: %v\n", err) - return + return fmt.Errorf("创建存储目录失败: %v", err) } // 加载所有用户到内存 @@ -542,7 +540,8 @@ func init() { // 启动定期清理任务 go p.startCleanupTask() - plugin.RegisterGlobalPlugin(p) + p.initialized = true + return nil } // ============ 插件接口实现 ============ diff --git a/plugin/weibo/weibo.go b/plugin/weibo/weibo.go index 74df2b9..f541d7a 100644 --- a/plugin/weibo/weibo.go +++ b/plugin/weibo/weibo.go @@ -34,20 +34,6 @@ const ( var StorageDir string -func init() { - cachePath := os.Getenv("CACHE_PATH") - if cachePath == "" { - cachePath = "./cache" - } - - StorageDir = filepath.Join(cachePath, "weibo_users") - - if err := os.MkdirAll(StorageDir, 0755); err != nil { - fmt.Printf("⚠️ 警告: 无法创建Weibo存储目录 %s: %v\n", StorageDir, err) - } else { - fmt.Printf("✓ Weibo存储目录: %s\n", StorageDir) - } -} const HTMLTemplate = ` @@ -422,8 +408,9 @@ const HTMLTemplate = ` type WeiboPlugin struct { *plugin.BaseAsyncPlugin - users sync.Map - mu sync.RWMutex + users sync.Map + mu sync.RWMutex + initialized bool } type User struct { @@ -452,15 +439,31 @@ func init() { BaseAsyncPlugin: plugin.NewBaseAsyncPlugin("weibo", 3), } + plugin.RegisterGlobalPlugin(p) +} + +// Initialize 实现 InitializablePlugin 接口,延迟初始化插件 +func (p *WeiboPlugin) Initialize() error { + if p.initialized { + return nil + } + + // 初始化存储目录路径 + cachePath := os.Getenv("CACHE_PATH") + if cachePath == "" { + cachePath = "./cache" + } + StorageDir = filepath.Join(cachePath, "weibo_users") + if err := os.MkdirAll(StorageDir, 0755); err != nil { - fmt.Printf("[Weibo] 创建存储目录失败: %v\n", err) - return + return fmt.Errorf("创建存储目录失败: %v", err) } p.loadAllUsers() go p.startCleanupTask() - plugin.RegisterGlobalPlugin(p) + p.initialized = true + return nil } func (p *WeiboPlugin) RegisterWebRoutes(router *gin.RouterGroup) {