English | 中文
通用信息转发平台 — 数据 → 解析 → 路由 → 推送
接收任意 HTTP 请求,经解析器提取结构化字段,按条件路由到多个推送渠道。
一键部署(推荐):
curl -O https://raw.githubusercontent.com/codename-test/EverywhereYouGo/main/deploy/init.sh
chmod +x init.sh
./init.sh
# 按提示选择部署模式支持 5 种部署模式:default(快速起步)、t1-host(host 网络)、t2-bridge(bridge 网络)、t3-nginx(Nginx + 手动证书)、t4-acme(Nginx + Let's Encrypt 全自动证书)。
更多部署形态说明见 deploy/README.md。
启动后:管理页面 https://<主机IP>:5001(自签名证书,浏览器需放行);Webhook 接收与健康检查走 http://<主机IP>:5000。
HTTP POST → 数据源 → 解析器 → 路由匹配 → 模板渲染 → 推送渠道
| 组件 | 说明 |
|---|---|
| 数据源 | 监听端口接收 HTTP POST |
| 解析器 | Python 脚本,提取字段并定义变量名 |
| 路由 | 条件表达式匹配渠道-模板对 |
| 模板 | Simple / Jinja2 渲染标题和内容 |
| 渠道 | 企业微信、钉钉、飞书、Telegram、Bark、邮件 (SMTP) |
设置 EGO_AUTH_TOKEN 环境变量后开启访问控制:
EGO_AUTH_TOKEN=your-secret-token python3 main.py- Web 页面需通过登录页输入 Token
- API 调用需携带
Authorization: Bearer your-secret-token请求头 - 健康检查
/api/health无需认证
可选设置 EGO_SECRET_KEY 自定义 Flask session 密钥。
配置有两份,角色不同:
| 存储 | 角色 |
|---|---|
SQLite(ego.db) |
运行时真相源 —— 所有读写以库内数据为准 |
config/*.json |
导出 / 备份介质 —— 便于备份、版本管理与迁移 |
| 文件 | 内容 |
|---|---|
config/parsers.json |
解析器元信息 |
config/sources.json |
数据源定义 |
config/channels.json |
推送通道配置 |
config/templates.json |
推送模板 |
config/bindings.json |
渠道绑定(含条件表达式) |
启动时的加载规则:
- 数据库已有配置 → 以数据库为准,不读 JSON,并把当前配置刷写回
config/*.json - 数据库为空且有 JSON → 从 JSON 导入(首次启动 / 迁移 / 恢复)
- 数据库为空且无 JSON → 导出初始配置到 JSON
因此 日常改配置请用 WebUI(改完即时生效)。直接编辑 config/*.json 只在
「数据库为空」的首次导入场景才会被读取,不是常规生效路径。
系统设置(DND、日志级别等)、消息日志与队列同样存储在 SQLite。
配置备份 / 恢复请用「系统设置 → 备份」,会打包 config/*.json + 用户上传的 parsers/*.py 与 channels/*.py。
恢复(Restore)与启动加载不是同一条路径:恢复时把备份里的配置写入数据库
(config/*.json → SQLite),随后重载插件并重启各数据源监听。
恢复是"部分恢复":只把备份里存在的配置文件写入数据库,未包含的配置保持原样
(不会被清空),并在结果里给出提示。所以手搓/截断的 ZIP 不会把没带上的数据弄丢。
需要把某张表恢复成空,请在 ZIP 里放一个内容为 [] 的文件,而不是删掉它
(文件存在且为 [] → 清空该表;文件不存在 → 该表不动)。
⚠️ 升级前请先备份:任何版本 / 镜像升级前,请先在「系统设置 → 备份」导出 ZIP。 备份文件含完整推送凭据(SMTP 密码 / 授权码 / token 等),请妥善保管。
内置插件与用户上传的插件分开放:
| 目录 | 内容 | Docker |
|---|---|---|
parsers_builtin/ |
内置解析器 | 随镜像发布,不打卷 |
parsers/ |
你上传的解析器 | 挂 ego_parsers 卷,容器重建不丢 |
channels_builtin/ |
内置通道插件 | 随镜像发布,不打卷 |
channels/ |
你上传的通道插件 | 挂 ego_channels 卷,容器重建不丢 |
规则:
- 解析顺序:用户目录优先,其次内置目录
- 与内置插件同名不允许上传(返回明确错误)—— 内置插件随镜像更新, 同名文件不会生效,不如一开始就说清楚
- 内置插件只读:WebUI 里可以查看,但不能改、不能删
- 确实要改内置插件的行为:把改好的文件换个名字放进用户目录, 或直接改源码重建镜像
为什么必须分开:如果把卷挂在放内置插件的目录上,named volume 首次创建会把 镜像里该目录的内容拷进卷里,之后就以卷为准 —— 镜像升级再也更新不到内置插件。 两者同目录无解:要么丢用户文件,要么内置永远升不上去。
从旧版本升级(v1.3.0 → v1.3.1+) 旧版本把用户上传的插件直接写在内置目录里,而该目录没有持久化——容器重建 就会丢失。升级到 v1.3.1+ 前,请先把用户插件备份出来:
- 导出(二选一):
- 旧容器里「系统设置 → 备份」导出 ZIP(若旧版支持);
- 或直接
docker cp导出旧容器里的插件目录(旧版用户插件与内置混在同一 未挂载卷的目录里,具体路径看你的旧版部署):docker cp <ego-container>:/app/parsers_builtin /tmp/old-parsers docker cp <ego-container>:/app/channels_builtin /tmp/old-channels
- 升级镜像:v1.3.1+ 起用户插件落在用户目录并挂 named volume
(
ego_parsers/ego_channels),普通镜像升级(拉新镜像、重建容器)无需 重传插件——插件随卷保留。 - 恢复(仅从旧版迁移时需要):恢复会写进新的用户目录,并自动跳过与内置 同名的条目(避免用旧副本遮蔽新版内置插件)。
卷操作语义(
ego_parsers/ego_channels):
docker compose up(或重建容器)→ 保留卷,插件不丢docker compose down→ 默认保留 named volume,插件不丢docker compose down -v→ 删除卷,用户插件全部丢失,操作前先确认
放在 parsers/ 目录下的 .py 文件,定义一个 parse() 函数:
def parse(raw_body: bytes, headers: dict, query_params: dict) -> dict:
data = json.loads(raw_body)
event = data.get("Event", "")
name = data.get("Item", {}).get("Name", "")
return {
"title": name,
"event": event,
"name": name,
}返回 dict 中除 title 外的字段同时用于:
- 路由条件匹配:
event == 'library.new' and media_type == 'Movie' - 模板变量引用:
{name}/{{ msg.name }}
支持 and、or、括号分组:
| 示例 | 说明 |
|---|---|
event == 'library.new' |
仅新入库 |
event == 'library.new' and media_type == 'Movie' |
仅新入库电影 |
event == 'library.new' or event == 'test' |
新入库或测试消息 |
设置免打扰时段后,消息进入队列等待,结束后自动刷新。紧急路由不受 DND 影响。
去重粒度是 消息 × 通道:每个渠道绑定各自配置 dedup_key_expr 与 dedup_window
(默认 3600 秒),互不影响。命中的渠道被跳过,其余渠道照常发送;
只有全部渠道命中时,整条消息才标记为 DISCARDED。
多渠道匹配时线程池并行发送,总延迟取决于最慢的单个渠道。
每个数据源自动保存最近 20 条请求样本,可在 WebUI 中选取样本进行测试解析和推送。
失败消息支持原始重发(使用已解析的 msg_json)或重新解析后重发。
默认只重发上次失败的渠道,不会把已经成功的渠道重复推送一遍;
需要整体重推时可用 scope=all。
- 备份:下载 ZIP 包(
config/*.json+parsers/*.py+channels/*.py) - 恢复:上传 ZIP 包,备份中的配置写入数据库(JSON → DB),插件文件同步恢复并热重载。 备份未包含的配置保持原样,并在结果里提示缺了哪些文件
- 预览:点「预览」会先跑一遍与真实恢复相同的校验(体积 / 完整性 / JSON 结构 / 插件可加载), 校验不通过(如 JSON 结构非法)时不会给出"确认恢复"按钮
- JSON 导入:支持 dry_run 预览、insert/overwrite 两种模式、依赖检查
安全提示
- 备份 ZIP 内含完整推送凭据(SMTP 密码 / 授权码 / token 等),需妥善保管,勿外泄。
- JSON 导出已对敏感字段(
password/token/secret/webhook/device_key等)脱敏为***,仅用于展示与归档;完整凭据仅经备份 ZIP 保留并恢复。
第三方渠道持续故障时自动隔离,避免拖垮整条发送链路:
- 滑动窗口(默认 60s)内失败率 > 50%,或连续失败 ≥ 5 次 → 熔断
- 冷却时间指数退避 30 → 60 → 120 → … → 600 秒(封顶 10 分钟)
- 冷却结束后进入半开探测,连续 3 次成功才恢复
- 4xx 不计失败(业务侧拒绝不等于服务故障),只对 5xx / 超时 / 连接类错误计数
- 熔断期间消息留在队列等待:不消耗重试次数、不丢弃;状态持久化,重启后仍生效
按通道独立限流(条/分钟),防止发送过快被对方封禁。重试解决不了 429—— 限流必须发生在发送之前。拿不到令牌的消息会排队等待,而不是被丢弃。
令牌桶(Token Bucket):每个通道独立令牌桶,桶容量(burst)等于配置的分钟
额度,按 额度 ÷ 60 每秒补充令牌;发一条消息需取 1 个令牌,桶空时不立即
丢弃而是排队直到有令牌(最长等 EGO_RATE_MAX_WAIT 秒,超时则延迟重排)。
| 位置 | 能做什么 |
|---|---|
| 通道列表 → 「韧性」列 | 查看限流徽章与熔断倒计时;熔断时可一键「手工恢复」 |
| 通道编辑弹窗 | 设置该通道的出站限流(留空/0 = 不限流) |
| 系统设置 → 韧性(通道熔断) | 手工调整滑动窗口、连续失败阈值、冷却基数/上限、探测次数等参数 |
参数取值优先级:system_config(设置页 / 直接改库) > 环境变量 > 内置默认,
改完即时生效、无需重启。
| 端点 | 说明 |
|---|---|
GET /api/metrics |
队列深度、死信总数、各通道成功率、端到端延迟、熔断与限流状态;?hours=N 调整统计窗口(默认 24h) |
GET /api/resilience |
当前处于熔断 / 限流状态的通道 |
GET /api/queue/stats |
队列与死信计数 |
GET /api/health |
健康检查(SQLite / 磁盘 / 配置 / 队列) |
收到 SIGTERM 时先停止接收新消息,再等待在途任务完成(最长 30 秒),
超时未完成的转入死信队列——容器重启不会丢消息。
内置中英文双语支持,通过导航栏右上角语言切换按钮随时切换。
| 通道 | 方式 | 类型标识 |
|---|---|---|
| 企业微信 Bot | Webhook | wechat_work_bot |
| 企业微信 API | 应用消息 | wechat_work_api |
| 钉钉 | Webhook | dingtalk |
| 飞书 | Webhook | feishu |
| Telegram | Bot API | telegram_bot |
| Bark | API | bark |
| 邮件 (SMTP) | SMTP | smtp_email |
| 变量 | 默认值 | 说明 |
|---|---|---|
WEB_PORT |
5000 |
HTTP 端口(Webhook 接收 / 健康检查) |
WEB_SSL_PORT |
5001 |
HTTPS 端口(管理页面,证书缺失时不启用) |
EGO_SSL_ENABLED |
1 |
设为 0 完全关闭内置 HTTPS(仅 HTTP,不跳转、不生成证书) |
EGO_SSL_DIR |
./certs |
SSL 证书目录,ego.crt 和 ego.key 存放位置 |
EGO_SSL_CERT |
./certs/ego.crt |
证书文件路径(覆盖 EGO_SSL_DIR) |
EGO_SSL_KEY |
./certs/ego.key |
私钥文件路径(覆盖 EGO_SSL_DIR) |
DB_PATH |
ego.db |
数据库路径 |
LOG_LEVEL |
INFO |
日志等级 |
EGO_AUTH_TOKEN |
(空) | 访问控制 Token |
EGO_SECRET_KEY |
(自动) | Flask session 密钥 |
EGO_INGRESS_WORKERS |
8 |
每个端口数据源的入口工作线程数 |
EGO_INGRESS_MAX_QUEUE |
200 |
入口等待队列上限,超出返回 503(背压) |
EGO_CLEANUP_INTERVAL |
600 |
旧消息 / 去重键的清理间隔(秒) |
EGO_BREAKER_WINDOW |
60 |
熔断滑动窗口(秒) |
EGO_BREAKER_MIN_SAMPLES |
5 |
窗口内触发失败率判定的最少样本数 |
EGO_BREAKER_FAILURE_RATIO |
0.5 |
窗口失败率阈值(超过则熔断) |
EGO_BREAKER_CONSECUTIVE |
5 |
连续失败阈值(照顾低频通道) |
EGO_BREAKER_OPEN_BASE |
30 |
熔断冷却基数(秒),逐次翻倍 |
EGO_BREAKER_OPEN_MAX |
600 |
熔断冷却上限(秒) |
EGO_BREAKER_HALF_OPEN_OK |
3 |
恢复所需连续探测成功次数 |
EGO_RATE_MAX_WAIT |
1.0 |
限流取令牌的最长等待(秒),超时改为延迟重排 |
EGO_RATE_MISS_TTL |
30 |
未配置限流的通道,回查数据库的间隔(秒) |
MIT