Files
sub-provider/docs/改造方案.md
2026-04-20 10:35:03 +08:00

977 lines
17 KiB
Markdown
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.
下面这份你可以直接丢给 Codex。
我把我们刚刚聊出来的**最终拍板结论**和**完整实现方案**都整理进去了。
---
# sub-provider 重构方案(最终版,完整 YAML 路线)
## 1. 最终结论
本项目后续重构,采用以下最终选择:
### 对外输出
* **统一输出单个完整 YAML**
* 不强依赖客户端支持 `rule-providers` / `proxy-providers`
* 目标是优先保证:
* 兼容性
* 可调试性
* 易分发
* 易维护
### 对内实现
* 内部仍然采用**模块化**设计
* 在 sub-provider 内部完成:
* 源拉取与缓存
* 节点解析与标准化
* 节点筛选、重命名、去重
* 规则模块组合
* 策略组装配
* DNS / TUN / 通用配置拼装
* 最终完整 YAML 渲染
### 规则存储方式
* **规则正文继续放项目文件**
* 采用类似 ACL4SSR 的维护方式:
* 一个类别的规则放一个文件
* 规则文件便于 Git 管理、diff、回滚、手工维护
* 不把 ACL4SSR 大量规则逐条入库
### 规则组合与面板配置
* **规则的组合关系、启用状态、绑定的策略组、顺序、参数等放 SQLite**
* 面板配置的是:
* 选哪些规则模块
* 每个模块绑定哪个策略组
* 模块顺序
* 模块参数
* profile 配置
* 源配置
* 少量 prepend / append 自定义规则
### 数据库选择
* **默认数据库SQLite**
* 原因:
* 当前项目是单服务、轻量配置中心、生成器型应用
* SQLite 部署和迁移成本最低
* 最适合当前阶段快速落地
* 代码层要保留未来切 PostgreSQL 的能力:
* 使用 SQLAlchemy
* 使用 Alembic
*`DATABASE_URL` 配置数据库连接
* 当前不推荐 Mongo 作为主库
* 当前不优先推荐 MySQL
---
## 2. 目标
将现有 Python sub-provider 项目重构为一个:
* 可面板管理
* 配置解耦
* 规则模块化
* 输出完整 YAML
* 可缓存
* 可预览
* 可追踪生成结果
的配置生成系统。
---
## 3. 项目边界
### 本阶段要做
1. 面板化管理订阅源
2. 规则模块化
3. 规则组合关系数据库化
4. 支持多个输出 Profile
5. 服务端拼装生成完整 YAML
6. 做缓存和快照
7. 支持预览和下载
### 本阶段不做
1. 不强制对外输出 provider 模式
2. 不做“在线全文编辑 ACL4SSR 大规则文件”为主交互方式
3. 不做复杂多用户权限系统
4. 不做重型前后端分离
5. 不把所有规则全文放 SQLite
6. 不引入 Mongo 做主存储
---
## 4. 架构原则
### 原则 1外部简单内部灵活
客户端只拿一个完整 YAML。
服务端内部怎么拆、怎么缓存、怎么组合,都由 sub-provider 负责。
### 原则 2规则内容文件化组合关系数据库化
规则正文属于“资产”,继续放文件。
面板管理的是“配置和组合关系”,放 SQLite。
### 原则 390% 的配置修改通过“选模块 + 改参数”完成
不要把面板做成“大文本框配置编辑器”。
### 原则 4优先可维护而不是一开始就追求炫技
先把结构跑顺,再考虑高级模式。
---
## 5. 总体架构
```text
输入源
-> 拉取缓存
-> 原始内容缓存
-> 解析节点
-> 节点标准化
-> 节点处理(过滤/去重/重命名/分类)
-> 策略组生成
-> 规则模块加载
-> 规则模块参数渲染
-> 规则按顺序拼接
-> 插入 prepend/append 自定义规则
-> 渲染完整 YAML
-> 结果缓存 / 生成快照
-> 提供下载 / 预览 / HEAD 信息
```
---
## 6. 推荐技术栈
### 后端
* FastAPI
### 数据库
* SQLite默认
* SQLAlchemy ORM
* Alembic migration
### 模板
* Jinja2
### 前端
* 优先服务端渲染
* 可用 Jinja2 + HTMX 或简单模板页
* 先不要求 React/Vue 前后端分离
### 缓存
* 轻量场景下可先用:
* SQLite 表
* 本地文件缓存
* 不必一上来引入 Redis
---
## 7. 目录结构建议
```text
app/
api/
routes_sources.py
routes_profiles.py
routes_rules.py
routes_preview.py
core/
config.py
database.py
cache.py
db/
base.py
session.py
models/
source.py
profile.py
rule_module.py
policy_group.py
artifact.py
schemas/
source.py
profile.py
rule_module.py
services/
source_fetcher.py
source_parser.py
proxy_normalizer.py
proxy_processor.py
policy_group_builder.py
rule_loader.py
rule_renderer.py
profile_renderer.py
artifact_service.py
templates/
base.html
sources.html
profiles.html
rules.html
preview.html
main.py
rules/
modules/
lan.list
private.list
cn_domain.list
cn_ip.list
apple.list
microsoft.list
github.list
telegram.list
openai.list
streaming.list
ads.list
final_proxy.list
final_direct.list
presets/
minimal.yaml
daily.yaml
router.yaml
group_templates/
basic.yaml
ai.yaml
streaming.yaml
data/
app.db
cache/
raw_sources/
parsed_sources/
generated/
artifacts/
migrations/
tests/
```
---
## 8. 规则系统设计
## 8.1 规则正文:继续放文件
规则正文文件继续按 ACL4SSR 风格维护。
例如:
* `rules/modules/apple.list`
* `rules/modules/openai.list`
* `rules/modules/telegram.list`
* `rules/modules/cn_domain.list`
* `rules/modules/final_proxy.list`
### 推荐格式
规则文件使用模板变量,不直接写死策略组:
```text
DOMAIN-SUFFIX,openai.com,{{ target_group }}
DOMAIN-SUFFIX,chatgpt.com,{{ target_group }}
DOMAIN-SUFFIX,oaistatic.com,{{ target_group }}
DOMAIN-SUFFIX,auth0.openai.com,{{ target_group }}
```
这样同一个规则模块可复用到不同策略组。
---
## 8.2 规则模块:放 SQLite
SQLite 里存规则模块元数据,而不是规则全文。
### 表:`rule_modules`
字段建议:
* `id`
* `key`
* `name`
* `description`
* `file_path`
* `category`
* `default_enabled`
* `default_order`
* `default_target_policy`
* `params_schema_json`
* `created_at`
* `updated_at`
### 示例
```json
{
"key": "openai",
"name": "OpenAI",
"file_path": "rules/modules/openai.list",
"category": "service",
"default_enabled": true,
"default_order": 80,
"default_target_policy": "🤖 AI",
"params_schema_json": {
"target_group": {
"type": "string",
"default": "🤖 AI"
}
}
}
```
---
## 8.3 Profile 中的规则组合:放 SQLite
### 表:`profile_rule_modules`
字段建议:
* `id`
* `profile_id`
* `module_id`
* `enabled`
* `order_index`
* `target_policy`
* `params_json`
含义:
* 这个 profile 是否启用这个模块
* 顺序是什么
* 最终绑定到哪个策略组
* 参数是什么
---
## 8.4 规则预设
可选支持“预设”。
例如:
* `minimal`
* `daily`
* `router`
但预设只作为**初始化模板**,最终仍落到具体 profile 配置里。
不要求上线初期就把预设做得很复杂。
---
## 9. 策略组系统设计
策略组不要硬编码死在一个大 YAML 模板里。
也要做成可配置对象。
### 表:`policy_groups`
字段建议:
* `id`
* `profile_id`
* `name`
* `type`
* `order_index`
* `config_json`
### `config_json` 示例
```json
{
"proxies": ["DIRECT", "REJECT", "香港节点", "日本节点"],
"include_all_nodes": false,
"filter": "HK|Hong Kong"
}
```
### 支持的策略组类型
* `select`
* `url-test`
* `fallback`
* `load-balance`
### 建议的默认组
* `🚀 节点选择`
* `🤖 AI`
* `📺 流媒体`
* `🍎 苹果服务`
* `📲 Telegram`
* `🌍 国外网站`
* `🇨🇳 国内网站`
---
## 10. 源管理设计
### 表:`sources`
字段建议:
* `id`
* `name`
* `type`
值可为:
* `base64`
* `url`
* `link`
* `static`
* `content`
* `headers_json`
* `enabled`
* `priority`
* `update_interval_sec`
* `rename_rules_json`
* `filter_rules_json`
* `dedupe_policy`
* `last_sync_at`
* `last_sync_status`
* `last_error`
* `created_at`
* `updated_at`
### 说明
这里的源是原始输入源,不是给客户端的 provider。
---
## 11. Profile 设计
Profile 是最终对外输出的配置单元。
例如:
* iPhone 配置
* Windows 配置
* OpenWrt 配置
* Apple TV 配置
* 精简版配置
* 完整版配置
### 表:`profiles`
字段建议:
* `id`
* `name`
* `description`
* `source_ids_json`
* `dns_template`
* `tun_enabled`
* `udp_enabled`
* `append_subscription_info`
* `expose_head_info`
* `enabled`
* `created_at`
* `updated_at`
---
## 12. 自定义覆盖设计
为了兼容高级用户需求,支持少量覆盖,但不做全文编辑器。
### 表:`profile_overrides`
字段建议:
* `id`
* `profile_id`
* `custom_rules_prepend`
* `custom_rules_append`
* `custom_proxy_groups`
* `custom_dns_patch`
* `custom_yaml_patch`
### 原则
只提供:
* prepend rules
* append rules
* 少量 patch
不鼓励直接在面板里手写全部 YAML。
---
## 13. 缓存设计
## 13.1 原始源缓存
缓存拉回来的原始内容。
目的:
* 避免频繁请求订阅源
* 降低上游压力
* 出问题可复现
---
## 13.2 解析结果缓存
把原始内容解析为统一节点模型后缓存。
目的:
* 多 profile 复用解析结果
* 避免重复解析
---
## 13.3 最终 YAML 缓存
同一个 profile 在以下内容不变时,直接返回缓存:
* 订阅源内容未变
* profile 配置未变
* 规则模块未变
* 策略组未变
缓存键建议基于 hash
* 源快照 hash
* 规则快照 hash
* profile 配置 hash
---
## 14. 生成快照设计
### 表:`generated_artifacts`
字段建议:
* `id`
* `profile_id`
* `version`
* `content`
* `content_hash`
* `source_snapshot_json`
* `rule_snapshot_json`
* `generated_at`
### 用途
* 预览
* diff
* 回滚
* 调试
* 追踪“为什么这次生成结果变了”
---
## 15. 内部统一节点模型
建议在解析层统一成一个内部对象。
### Python 草案
```python
from pydantic import BaseModel
from typing import Any
class ProxyNode(BaseModel):
name: str
type: str
server: str
port: int
udp: bool = True
tags: list[str] = []
raw: dict[str, Any] = {}
```
对不同类型协议ss、vmess、vless、trojan、hysteria 等)额外字段可放在 `raw` 里。
---
## 16. 生成流水线
## 第 1 步:拉取源
* 读取启用的 sources
* 获取原始订阅内容
* 更新缓存
* 记录同步状态
## 第 2 步:解析源
* 解析 base64
* 解析单链接
* 解析远程订阅
* 标准化成统一节点模型
## 第 3 步:节点处理
* 去重
* 重命名
* 按国家/协议/标签分类
* 过滤无效节点
* 应用 profile 的筛选逻辑
## 第 4 步:生成策略组
* 读取 profile 绑定的 policy groups
* 根据节点分类与过滤规则生成 `proxy-groups`
## 第 5 步:加载规则模块
* 读取 profile 启用的规则模块
* 按顺序加载规则文件
* 渲染模板变量(如 `target_group`
## 第 6 步:组装规则
* 拼接所有规则模块
* 插入 prepend rules
* 插入 append rules
* 保证 `MATCH` 规则最后输出
## 第 7 步:生成完整 YAML
输出包含:
* mixed-port / socks-port / redir-port / tproxy-port按需
* mode
* log-level
* dns
* tun
* proxies
* proxy-groups
* rules
## 第 8 步:缓存与快照
* 计算 hash
* 命中缓存则复用
* 否则生成新 artifact
---
## 17. 输出设计
### 对外输出接口
* `/profiles/{id}/clash.yaml`
* `/profiles/{id}/download`
* `/profiles/{id}/preview`
* `/profiles/{id}/head`
### 输出原则
* 默认返回完整 YAML
* 对客户端透明
* 客户端无需理解内部模块化结构
### 可选响应头
支持将源站订阅信息透传到最终响应头,例如:
* `subscription-userinfo`
* 其他流量额度相关头
如果多个源混合:
* 默认只透传第一个主源的额度信息
* 或后续设计聚合策略,但不是当前必做
---
## 18. API 草案
## 源管理
* `GET /api/sources`
* `POST /api/sources`
* `PUT /api/sources/{id}`
* `DELETE /api/sources/{id}`
* `POST /api/sources/{id}/test`
* `POST /api/sources/{id}/sync`
## 规则模块
* `GET /api/rule-modules`
* `GET /api/rule-modules/{id}`
* `PUT /api/rule-modules/{id}`
## Profile
* `GET /api/profiles`
* `POST /api/profiles`
* `PUT /api/profiles/{id}`
* `DELETE /api/profiles/{id}`
## Profile 规则配置
* `GET /api/profiles/{id}/rules`
* `PUT /api/profiles/{id}/rules`
## Profile 策略组配置
* `GET /api/profiles/{id}/policy-groups`
* `PUT /api/profiles/{id}/policy-groups`
## 预览与生成
* `POST /api/profiles/{id}/preview`
* `POST /api/profiles/{id}/generate`
* `GET /api/profiles/{id}/artifacts`
* `GET /api/artifacts/{id}`
---
## 19. 面板设计原则
### 普通模式
允许:
* 配源
* 选 profile
* 勾选规则模块
* 选择规则模块绑定的策略组
* 调模块顺序
* 加 prepend / append 规则
* 预览生成结果
### 高级模式
允许:
* 编辑少量覆盖配置
* 自定义组模板
* 导入自定义规则模块
### 不建议
* 直接在线编辑整份 ACL4SSR 规则大文件作为主要操作方式
---
## 20. 示例规则模块
## `rules/modules/openai.list`
```text
DOMAIN-SUFFIX,openai.com,{{ target_group }}
DOMAIN-SUFFIX,chatgpt.com,{{ target_group }}
DOMAIN-SUFFIX,oaistatic.com,{{ target_group }}
DOMAIN-SUFFIX,auth0.openai.com,{{ target_group }}
```
## `rules/modules/apple.list`
```text
DOMAIN-SUFFIX,apple.com,{{ target_group }}
DOMAIN-SUFFIX,icloud.com,{{ target_group }}
DOMAIN-SUFFIX,itunes.apple.com,{{ target_group }}
DOMAIN-SUFFIX,apps.apple.com,{{ target_group }}
```
---
## 21. 示例最终输出 YAML 骨架
```yaml
mixed-port: 7890
allow-lan: true
mode: rule
log-level: info
dns:
enable: true
ipv6: false
nameserver:
- 223.5.5.5
- 119.29.29.29
proxies:
- name: 香港节点 01
type: ss
server: 1.2.3.4
port: 443
cipher: aes-128-gcm
password: xxxx
proxy-groups:
- name: 🚀 节点选择
type: select
proxies:
- 香港节点 01
- 日本节点 01
- DIRECT
- name: 🤖 AI
type: select
proxies:
- 🚀 节点选择
- 香港节点 01
- 日本节点 01
rules:
- DOMAIN-SUFFIX,openai.com,🤖 AI
- DOMAIN-SUFFIX,chatgpt.com,🤖 AI
- DOMAIN-SUFFIX,apple.com,🍎 苹果服务
- GEOIP,CN,DIRECT
- MATCH,🚀 节点选择
```
---
## 22. 数据库配置要求
### 默认
```env
DATABASE_URL=sqlite:///./data/app.db
```
### 未来切 PostgreSQL
```env
DATABASE_URL=postgresql+psycopg://user:pass@postgres:5432/subprovider
```
### 要求
* 所有数据库访问都走 SQLAlchemy
* migration 走 Alembic
* 不写死 SQLite 特性到业务逻辑中
---
## 23. 开发阶段建议
## 第一阶段:解耦与最小可用
目标:
* 先跑通结构
任务:
1. 引入 SQLAlchemy + Alembic
2. 建 sources / profiles / rule_modules / profile_rule_modules / policy_groups / artifacts 表
3. 将现有规则整理为 `rules/modules/*.list`
4. 将现有单体生成逻辑拆成 service
5. 支持生成一个完整 YAML
6. 提供最简预览页面
---
## 第二阶段:面板化
目标:
* 基础可用
任务:
1. 源管理页面
2. Profile 管理页面
3. 规则模块勾选和排序页面
4. 策略组配置页面
5. 预览和下载页面
---
## 第三阶段:增强能力
目标:
* 更稳定、更可追踪
任务:
1. 快照与 diff
2. 生成缓存优化
3. 同步日志和错误展示
4. 自定义规则导入
5. 自定义组模板
---
## 24. 明确不推荐的方向
1. 不推荐把 ACL4SSR 规则逐条入 SQLite
2. 不推荐面板主交互是“编辑一万条规则文本”
3. 不推荐一开始就做 rule-provider / proxy-provider 对外发布
4. 不推荐 Mongo 作为主配置库
5. 不推荐先做复杂权限系统
6. 不推荐先做重前端再补业务逻辑
---
## 25. 给 Codex 的明确执行要求
请按以下要求重构项目:
1. 保留对外输出为单个完整 YAML
2. 将内部生成逻辑改为模块化流水线
3. 规则正文继续使用文件存储
4. 使用 SQLite 存储:
* 源配置
* profile 配置
* 规则模块元数据
* profile 与规则模块的绑定关系
* 策略组配置
* 生成快照
5. 使用 SQLAlchemy + Alembic数据库 URL 可配置
6. 代码结构按 service 分层,避免单文件堆逻辑
7. 首先实现最小可运行版本:
* 能配置 source
* 能配置 profile
* 能选择规则模块
* 能选择目标策略组
* 能生成并预览完整 YAML
8. 不要实现对外 provider 模式作为默认路线
9. 不要将规则正文全文入库
10. 不要将面板设计成规则全文编辑器
---
## 26. 最终一句话总结
本项目的最终路线是:
> **内部模块化、缓存化、可配置化**
> **对外输出完整单文件 YAML**
> **规则正文继续文件维护**
> **规则组合关系和面板配置放 SQLite**
这条路线最符合当前项目阶段,也最稳。
---
如果你要,我下一条可以继续给你一份**更像任务单的 Codex 执行拆分版**,我会按“先改哪些文件、再改哪些文件、每步验收什么”来写。