- Added i18n keys for various error and info messages related to task management, user handling, and storage operations. - Updated error messages in the watch and task handling commands to use i18n for better localization. - Refactored error handling in the database initialization and user synchronization processes to provide clearer messages. - Improved logging messages for better clarity and consistency across the application. - Added comprehensive documentation for AI collaboration and project structure in the repository.
7.1 KiB
7.1 KiB
SaveAny-Bot AI 协作说明
本项目是一个将 Telegram 文件/消息转存到多种存储端的 Bot,主要用 Go 实现,CLI 入口在 cmd/,核心逻辑分布在 client/、core/、config/、database/、storage/ 等目录。下面是针对本仓库的专用约定,供 AI 编码助手参考。
总体架构与入口
- CLI 入口:
- 二进制入口:
main.go调用cmd.Execute(ctx)。 - 根命令:
cmd/root.go使用cobra定义saveany-bot,Run实现在cmd/run.go。
- 二进制入口:
- 应用启动流程(非常重要):
cmd/run.go::Run中按顺序完成:读取配置config.Init→ 初始化缓存common/cache→ 初始化 i18ncommon/i18n→ 初始化数据库database.Init→ 加载存储storage.LoadStorages→ 加载解析器插件parsers.LoadPlugins→ (可选)Userbot 登录 → 启动 Telegram Botclient/bot.Init→ 启动核心任务队列消费core.Run。- 添加新的初始化步骤时,请遵循该顺序并放在
initAll中,而不是分散在各处。
配置与约定
- 配置系统:
- 使用
viper读取config.toml,核心结构体定义在config/viper.go::Config。 - 默认值在
config.Init中通过viper.SetDefault定义,如workers、retry、telegram.*、db.*等。 Config.C()返回的是全局配置副本(值类型),不要在返回值上修改字段;如果需要修改配置流程,应在config.Init内或通过viper进行。- 存储配置通过
config/storage/factory.go::LoadStorageConfigs加载并校验,新增存储类型需:- 在
pkg/enums/storage中增加枚举。 - 在
config/storage/下新增具体StorageConfig实现并实现Validate。 - 在
storageFactories映射中注册工厂方法。
- 在
- 使用
- 环境变量:
- 所有配置键会被
SAVEANY_前缀的环境变量覆盖,.会被_替换(SAVEANY_TELEGRAM_APP_ID等)。
- 所有配置键会被
Telegram 客户端与中间件
- Bot 客户端:
- 入口在
client/bot/bot.go::Init,使用gotgproto.NewClient创建,Session 使用database.GetDialect(config.C().DB.Session),错误处理通过ErrorHandler回调完成。 - Handlers 注册集中在
client/bot/handlers目录,handlers.Register负责统一挂载;新增命令/消息处理逻辑时优先在该目录按功能拆分文件,实现后在handlers.Register中注册。 - Bot 命令列表依赖
handlers.CommandHandlers来自动注册到 Telegram;新增命令时务必更新该切片,以保持/help与 Bot 命令列表一致。
- 入口在
- 中间件:
- 通用中间件位于
client/middleware/,包含 floodwait、防崩溃、重试等;middleware.NewDefaultMiddlewares在client/bot/bot.go中统一挂载。 - 新增跨所有更新生效的行为(如日志、统计)时,应优先实现为中间件。
- 通用中间件位于
核心任务与队列
- 任务接口与队列:
- 核心接口:
core/core.go::Executable,包含Type() TaskType、Title()、TaskID()、Execute(ctx)。 - 任务队列:
pkg/queue.TaskQueue[Executable],由core.Run使用;Workers数量来自配置config.C().Workers。 - 任务类型与实现示例位于
core/tasks/**,例如文件任务、Telegraph 任务等;新增任务类型应放在对应子目录并实现Executable接口,然后通过core.AddTask入队。
- 核心接口:
- 生命周期 Hook:
core.worker在执行任务前后会根据config.C().Hook.Exec调用外部命令(TaskBeforeStart/TaskSuccess/TaskFail/TaskCancel)。- 修改任务执行流程时需保留这些 Hook 调用,以免破坏用户已有集成。
数据库与持久化
- 数据库初始化:
database.Init使用配置config.C().DB.Path创建并连接 SQLite,使用GetDialect抽象驱动(见database/driver_*.go)。- Migration 通过
db.AutoMigrate(&User{}, &Dir{}, &Rule{}, &WatchChat{})完成,模型定义在database/*.go中。
- 用户同步约定:
database.syncUsers会根据config.C().Users同步数据库用户表:在配置中新增/删除用户会自动在 DB 中创建/删除对应记录。- 开发涉及用户表逻辑时,请考虑该同步行为,避免在其他地方直接创建/删除用户记录而与配置冲突。
存储后端
- 存储抽象:
- 抽象接口在
config/storage/types.go与storage/顶层(以及子目录)中;config/storage/*.go处理配置解析,storage/*处理真正的上传/下载实现。 - 现有实现包括
local、alist、s3/minio、webdav、telegram等,每个后端都有对应子目录和配置结构体。
- 抽象接口在
- 新增存储实现的推荐路径:
- 在
config/storage/下添加配置结构体 +Validate。 - 在
storage/下添加具体实现(例如storage/foo/)。 - 在
pkg/enums/storage与storageFactories中注册,并确保storages配置示例被更新(config.example.toml/ 文档)。
- 在
解析器插件(JS)
- 插件运行时:
- 解析器接口和插件文档在
plugins/README.md,Go 端入口为parsers/目录,使用goja与playwright-go。 - 插件通过
registerParser({ metadata, canHandle, parse })注册,使用ghttp/playwright进行 HTTP/浏览器请求。
- 解析器接口和插件文档在
- 与核心交互约定:
- 插件
parse返回的Item/Resource会被转化为内部任务(通常是下载/转存任务)并进入core队列。 - 修改
Item/Resource结构或解析逻辑时,要确保保持向后兼容,或在plugins/README.md中同步更新字段说明和示例。
- 插件
i18n 与日志
- 国际化:
- 所有用户可见字符串(尤其是错误与提示)应使用
common/i18n:i18n.T(i18nk.SomeKey, map[string]any{"Name": name})。 - 语言文件位于
common/i18n/locale/,go:generate指令在main.go中生成i18nk/keys.go;新增文案时需:添加到 YAML、运行go generate ./...、再在代码中引用新 key。
- 所有用户可见字符串(尤其是错误与提示)应使用
- 日志:
- 使用
github.com/charmbracelet/log,在cmd/run.go::Run中通过log.WithContext将 logger 注入context.Context;后续代码优先通过log.FromContext(ctx)获取 logger。 - 编写新代码时,如已有
ctx,请使用log.FromContext(ctx)而不是全局 logger。
- 使用
开发与运行
- 本地运行:
- 直接运行:
go run ./cmd(cmd/root.go+cmd/run.go)。 - 或通过 Docker:参见根目录
README.md中的docker run ...示例及docker-compose.yml。
- 直接运行:
- 代码生成与文档:
- i18n key 生成:
go generate ./...会执行main.go顶部的//go:generate,使用cmd/geni18n/main.go生成common/i18n/i18nk/keys.go。 - 文档站点在
docs/(Hugo),通常不需要在核心代码改动时同步修改,除非涉及文档内容。
- i18n key 生成:
如果你在实现某个功能时发现以上规则不够具体(例如某类任务在 core/tasks 中到底如何落地,或某个存储/解析器的边界不清晰),请在对应章节下扩展更精确的说明,并在 PR 描述中标注。也欢迎你告诉我有哪些部分需要补充或澄清,我可以进一步细化。