DEEP 20 · 第二辑 · 感知与系统服务 · LEARN NOTES

收进学习手册 · 2026-09-11 · duck.whatled.com

解读 20 · configd + duckctl + duck-ipc-proto:配置、命令行与 IPC

解读对象:duck-ipc-proto/src/lib.rs(5643 行)+ configd/src/(10 个文件共 4071 行)+ duckctl/src/main.rs(3069 行)
需要的前置:解读 18、解读 19 里 update.* 的来历。

duck-ipc-proto:一条线,一套契约

板子上多个守护进程(robotd/configd/updaterd/btd/tofd)与所有客户端说同一种话:JSON-RPC 2.0、一行一个对象(NDJSON)、unix socket、换行分帧(lib.rs:9-13);进度以无 id 的通知推送,断线重连的客户端重新订阅即可跟上。5643 行几乎全是类型,但三处值得专程来看:

configd:配置必须是活的

为什么单开一个守护进程(configd/src/lib.rs:1-6):配 wifi 恰恰是 robotd 死掉时最需要的能力,配置不能住在控制守护进程里;它也不存凭据——NetworkManager 持有密码并自行重连(configd/src/lib.rs:16-18)。

store.rs 是"文件,不是服务"(store.rs:1-9)的范本:普通 JSON 文件 + flock 串行化写者 + 临时文件 rename(2) 原子替换,还补上最常被忘的一步——目录 fsync(store.rs:182),否则 rename 可能熬不过断电,而"拔墙上的电"是机器人的常态而非例外。处处是硬件约束:MAX_NAME = 24 来自 BLE 传统广播总共 31 字节载荷(store.rs:20-26);配对 PIN 恰好六位(store.rs:40-45)——蓝牙规范就是六位,"12345 还是 012345"的分歧是没人能诊断的客服电话。访问控制两层(main.rs:77-114):socket 组决定谁能说话,--allow-user/--allow-group(按用户名而非 uid,因 sysusers 动态分配 uid)决定谁能改;只读调用不设门,支持才能检查一台它无权重配的机器人。

duckctl:超时即文档

duckctl 是手机 app 的替身,走 BLE(btleplug,为跨 macOS/Linux/Windows 选型,main.rs:15-18);板上没有任何东西依赖它,所以这个 BLE 库进不了发布件(main.rs:10-13)。最值得读的是超时常量组(main.rs:53-117):REPLY_TIMEOUT = 15s 是空闲预算而非总预算——每个进度通知都证明机器人活着并重置时钟,所以 apply 想跑多久跑多久,卡死的机器人几秒露馅;UPDATE_IDLE_TIMEOUT 直接由 UPDATE_MAX_SILENCE_SECONDS + 60 推导(main.rs:87-88),注释记着教训:它曾是 180 s,协议静默上限涨到 600 s 后,预算低于上限的客户端会把正常更新报成"机器人停止应答"。

你带走的收获

延伸

什么鸭 WHATDUCK · 复刻学习笔记 ← 全部手册 · 首页