Files
main_plugin_farm/docs/02-architecture.md
T
2026-10-15 17:21:05 +08:00

5.0 KiB

代码设计与目录

原则与当前状态

下列为远期目标设计;第一批核心已按职责实现为独立模块,见09-foundation.md。当前旧代码位于 legacy,未把其全局变量、 数据库管理器和服务定位器直接当作新核心继续复用。

采用一个共享 Python 包,内部按职责划分,避免先建多个互相依赖的 独立发行包。共享源码只维护一份;发布时复制进各插件私有目录。

目标结构

farm/
  src/farm_core/
    domain/                 # 规则、值对象、状态转换,不做 I/O
    application/            # 注册/购买/播种等用例,拥有事务边界
    ports/                  # 必要的仓储事务、时钟、外部钱包契约
    infrastructure/
      sqlite/               # 连接、仓储、schema migration
      resources/            # 作物目录、资源校验与更新
    presentation/           # 框架无关展示数据;可选图片渲染
  integrations/
    zhenxun/                # 真寻命令、配置、金币、数据目录、生命周期
    nonebot/                # 普通 NoneBot 插件,不导入真寻
    astrbot/                # AstrBot 插件,不导入 NoneBot 或真寻
  assets/                   # 经整理、版本化的资源,尚未从 legacy 提取
  tests/
    unit/ integration/ contracts/ migrations/ packaging/
  release/                  # 构建目标、文件白名单、依赖与模板
  scripts/                  # 离线校验、迁移、未来打包工具
  legacy/                   # 旧实现参考;不进入新插件安装包
  docs/

初始化时只创建职责说明;当前已实现第一批核心,不生成大量空模块。 当一个用例实施时,才创建所需模块。

依赖方向

flowchart TD
  Z[真寻接入] --> A[应用用例]
  N[NoneBot 接入] --> A
  B[AstrBot 接入] --> A
  A --> D[领域规则]
  A --> P[必要接口]
  S[SQLite 实现] --> P
  R[资源实现] --> P
  Z --> C[组装与生命周期]
  N --> C
  B --> C
  C --> S
  C --> R
  A --> V[展示数据]
  V --> I[可选图片渲染]

基础设施实现接口,由宿主启动阶段组装并注入;领域与应用代码不能 访问框架全局对象、事件、配置管理器或消息发送 API。 记录日志使用标准 logging,接入层按需桥接宿主日志。

每层的责任

层 应做 禁止混入
命令接入 参数解析、用户上下文、权限、确认、发送回复 再写一套价格/奖励计算
应用用例 业务校验、幂等、事务、调用领域计算 对聊天平台对象直接操作
领域规则 土地/星级/经验计算与状态转换 SQL、网络、图片、框架导入
存储 条件更新、查询、schema 升级 命令文案、签到奖励选择、图片
展示 将结果渲染为文本/图片 修改余额和农场状态
资源 校验、版本、缓存与原子切换 未验证即覆盖线上目录

命令与业务服务返回明确结果,例如成功、余额不足、种子不足、 已处理、状态冲突;结果包含展示所需数值和错误码。 数据库故障不能转换成“没有记录”或“没有农场”。

最小接口建议

  • UnitOfWork:一次用例获取同一事务下的仓储;成功才提交。
  • Clock:提供带时区的当前时间,使跨日、成熟和签到可测试。
  • PlantCatalog:提供带版本的作物定义,已种植实例绑定规则版本。
  • ExternalWallet:仅在真寻金币等外部经济接入时启用,明确幂等与补偿。

不要为字符串工具、日志和每个函数都建接口。 领域对象使用明确数据类型,取代任意 dict[Any, Any]。 注册、库存、地块、货币、收获周期分别建模,枚举及字段有说明。

生命周期和异步模型

导入模块时不启动清理线程、不连接数据库、不发送网络请求。 宿主启动:验证配置→迁移→初始化仓储/资源→就绪; 宿主停止:拒绝新写入→等待在途用例→关闭连接和任务。

首期建议单进程嵌入式部署。不要用 threading.RLock 代替异步业务锁。 事务连接生命周期由 UnitOfWork 管理;即使使用进程内锁,SQL 仍需 条件更新和唯一约束。查询缓存首期可不做;需要时在提交后失效, 不缓存不存在的用户作为有效玩家,不把缓存余额作为扣款依据。

发布时的包隔离

src/farm_core 内部一律采用相对导入。 构建时复制为 <插件包>/_vendor/farm_core,接入层经包内路径导入。 _vendor 必须是普通包且顶层初始化无副作用。 禁止把共享核心作为全局同名 farm_core 安装后又在插件中带另一份, 避免同时安装真寻/NoneBot 包时导入碰撞。

第三方依赖只列核心必需项和当前接入层项;渲染依赖可选。 私有命名空间能隔离源码名称,不能隔离同一 Python 进程的第三方依赖 版本;冲突必须通过兼容测试或分进程解决。