① 采集
Provider 概览
随引擎发布的数据源:四个 theta provider、Apple Health 导入通道、各自的开启条件,以及哪些配置键背后并没有 provider。
随仓库发布的内容
Section titled “随仓库发布的内容”启动时注册两个 platform:theta 和 apple。theta 平台从磁盘加载 provider,一个数据源一个目录;apple 平台是内置的导入通道,不接受插件。下面这张表就是仓库里全部的内容,没有别的数据源被接进来。
| 数据源 | Slug | Platform | 连接类型 | 定时拉取 |
|---|---|---|---|---|
| Garmin Connect | theta_garmin | theta | OAUTH1 | 无,只走推送 |
| Whoop | theta_whoop | theta | OAUTH2 | 每 24 小时 |
| Oura | theta_oura | theta | OAUTH2 | 每 5 分钟 |
| PostgreSQL | theta_pgsql | theta | CUSTOMIZED | 无,只做校验 |
| Apple Health | apple_health | apple | NONE | 无,由客户端上传 |
它们实现的契约(BasePullProvider、ProviderInfo、LinkType、拉取排程器)见 Pulse Provider 体系。要连接其中一个,见使用 Provider。
四个 theta provider
Section titled “四个 theta provider”每个都住在 mirobody/pulse/providers/ 下自己的 mirobody_<slug>/ 目录里,目录里恰好一个 provider_*.py,并由自己的 create_provider(config) 工厂方法实例化。工厂返回 None 就等于这个 provider 完全不进注册表:没配好的数据源就是这样自我禁用的。
| 目录 | 类 | 由什么开启 | 拉取任务 |
|---|---|---|---|
mirobody_garmin_connect/ | GarminProvider | GARMIN_CLIENT_ID + GARMIN_CLIENT_SECRET | 不排(只走 webhook) |
mirobody_whoop/ | WhoopProvider | WHOOP_CLIENT_ID + WHOOP_CLIENT_SECRET | 排(基类默认) |
mirobody_oura/ | OuraProvider | OURA_CLIENT_ID + OURA_CLIENT_SECRET | 排 |
mirobody_pgsql/ | PgsqlProvider | ENABLE_PGSQL_DEVICE:任何非空值 | 不排(只做校验) |
每个 provider 对外声明的元数据就是一个普通的 ProviderInfo,构造过程不碰网络。四个里面 Garmin 的最短。
PostgreSQL provider 在两件事上是个例外。它是唯一的 CUSTOMIZED 数据源:声明了五个 connect_info_fields(用户名、密码、host、port、database),而不是把用户送去浏览器;它也是唯一由显式功能开关控制、而非由「有没有配凭据」控制的那个。
它还止步于校验:连一次库、跑一句 SELECT version()、关掉,然后把凭据存下来。取数与格式化都刻意留空,所以连上它并不会产生任何记录 —— 它的用途是让一个部署把某个数据库连接记下来,而不是从里面导数据。
Apple Health
Section titled “Apple Health”Apple Health 不是插件:apple 平台自己注册自己的 provider,PROVIDER_DIRS 里的任何配置都不会生效。
它的两个 provider 的 auth_type 都是 NONE、状态恒为 connected:没有账号需要连接,因为是客户端把数据推进来,不是服务端去拉。接收这些推送的有三条路由:
| 路由 | 请求体 | 说明 |
|---|---|---|
POST /api/v1/pulse/apple/health | metaInfo + healthData[] | 主导入通道;接受 Content-Encoding: gzip |
POST /api/v1/pulse/apple/statistics | metaInfo + statistics[] | 客户端算好的聚合值(sum / average / minimum / maximum / mostRecent),直接作为汇总指标写入 |
POST /api/v1/pulse/apple/cda | metaInfo + cdaData[] | CDA(Clinical Document Architecture)文档 |
三条都需要 JWT,并且 /apple/* 与 /api/v1/pulse/apple/* 两套前缀都会响应,因为上传端可能指向其中任意一套。这条通道接收的类型词表是跨平台的,不限于 Apple 的健康库,见数据流。
没有对应 provider 的配置键
Section titled “没有对应 provider 的配置键”config.yaml 和拉取排程器里都提到了本次检出并不包含的数据源。它们是更大规模部署留下的残留,把键填上也不会让数据源出现:
| 残留 | 出现位置 | 为什么什么都不会发生 |
|---|---|---|
VITAL_API_KEY、VITAL_ENVIRONMENT | config.yaml | setup.py 没注册 vital 平台,因此 POST /api/v1/pulse/vital/generate-sign-in-token 回 503 Vital platform not available |
RENPHO_API_BASE_URL、RENPHO_APP_VERSION、RENPHO_PLATFORM、RENPHO_ENCRYPTION_KEY | config.yaml | 整棵树里既没有 mirobody_renpho/ 目录,也没有任何 Renpho provider 类 |
FRONTIERX_CLIENT_ID、FRONTIERX_USER_POOL_ID | config.yaml,已被注释掉 | 没有任何 provider 读它 |
theta_renpho、theta_vital、theta_cgm | pull_task.py 里的节奏表 | 这些 slug 的执行间隔与锁时长,但没有任何已发布的 provider 认领它们 |
随包发布的 provider 就是上面那四个 theta provider,加上 apple 平台自己那两个。其它来源看到的内容不在这个分支里。
把键填上、连接账号、看着记录进来
完整走读一份已发布的实现
这些 provider 共同实现的契约
加上你自己的第五个数据源