Matrix Music Bot Dev
|
aedaa2fdf0
|
Merge branch 'master' of http://192.168.6.200:3080/1076code/matrix
build-and-push-image / build-push (push) Failing after 16m31s
build-and-push-image / vulnerability-scan (push) Has been skipped
|
2026-07-03 01:06:07 +08:00 |
|
luck1076
|
78e7afe0fc
|
更新 .gitea/workflows/build-image.yml
build-and-push-image / build-push (push) Has been cancelled
build-and-push-image / vulnerability-scan (push) Has been cancelled
|
2026-07-03 01:04:53 +08:00 |
|
Matrix Music Bot Dev
|
1bf7a39f0f
|
ci: install-docker.sh 脚本 + .gitea/README.md 改 host 部署指南
用户决定 runner 用 host 部署(不是 Docker 容器)。
变更:
scripts/install-docker.sh (新增, 140 行)
- 一键装 Docker Engine + BuildKit + containerd
- 用阿里云镜像源替代 Docker 官方源(国内快)
- 自动 systemctl enable --now docker
- 把当前用户加入 docker 组(免 sudo)
- 验证 docker / buildx / pull hello-world
- 卸载指南(回滚)
.gitea/README.md (修改 Runner 安装章节)
- 移除"在 Docker 中跑 runner"流程
- 改为 host 部署 6 步流程:
1. 下载 act_runner
2. 装 Docker(用 install-docker.sh)
3. 配国内镜像(用 setup-runner-mirrors.sh)
4. 注册 runner
5. 启动 act_runner daemon
6. (推荐)systemd 托管
- 明确"不推荐在 Docker 容器里跑 runner"
- 明确 Docker 20.10+ + BuildKit 是硬性要求
为什么 host 部署更好(对比 DinD / docker.sock mount):
- 不需要特权模式(DinD)或突破容器隔离(socket mount)
- Docker 缓存、镜像、卷都和宿主机共享,运维简单
- act_runner 在 host 跑 action 时直接用宿主 docker daemon
- 性能更好(无嵌套虚拟化层)
部署 hermes-runner 的完整流程:
1. curl + chmod act_runner 二进制
2. sudo ./scripts/install-docker.sh
3. sudo ./scripts/setup-runner-mirrors.sh
4. act_runner register --labels ubuntu-22.04 ...
5. 配置 systemd 服务
6. 推送仓库触发 workflow 验证
|
2026-07-03 00:52:39 +08:00 |
|
Matrix Music Bot Dev
|
6ec609b1ce
|
perf(国内网络): runner 镜像加速配置 + Dockerfile cargo 镜像
按用户全选 4 个加速维度实施:
1. Docker 镜像加速(最大影响面)
- scripts/setup-runner-mirrors.sh 写入 /etc/docker/daemon.json
- registry-mirrors: docker.m.daocloud.io + ghcr.nju.edu.cn
- 影响所有 docker pull:actions / base images / Gitea registry
2. crates.io 镜像
- .cargo/config-docker.toml(与 .cargo/config.toml 区分,后者用于 Windows 本地开发)
- rsproxy.cn 镜像(rustcc 维护,国内最稳)
- Dockerfile COPY 此文件到 /root/.cargo/config.toml(在 cargo build 前)
3. GitHub git clone 加速
- scripts/setup-runner-mirrors.sh 自动配置 git config --global
- url.https://ghproxy.com/https://github.com.insteadOf https://github.com
4. 优先做 Docker 镜像加速(4 = 1 的子集,重复)
setup-runner-mirrors.sh 特性:
- 自动备份原配置(.bak)
- 用 python3 合并 daemon.json(保留用户已有配置)
- 重启 docker 后验证 Registry Mirrors
- 测试 hello-world pull 验证生效
- --undo 回滚模式
镜像源选型理由:
- docker.m.daocloud.io:DaoCloud 维护,最稳
- ghcr.nju.edu.cn:NJU CTF 团队维护的 GitHub Container Registry 镜像
- rsproxy.cn:rustcc 维护,sparse 协议兼容
- ghproxy.com:通用 GitHub 镜像
使用方法(runner 上):
sudo ./scripts/setup-runner-mirrors.sh
sudo ./scripts/setup-runner-mirrors.sh --undo # 回滚
下一步:处理 runner 缺 docker 能力的问题
|
2026-07-03 00:45:25 +08:00 |
|
luck1076
|
ebfd67330f
|
更新 .gitea/workflows/build-image.yml
build-and-push-image / build-push (push) Failing after 19m37s
build-and-push-image / vulnerability-scan (push) Has been skipped
|
2026-07-03 00:39:58 +08:00 |
|
Matrix Music Bot Dev
|
a22d9578fb
|
ci(perf): runner 本地预拉 action 镜像加速 Set up job
build-and-push-image / build-push (push) Has been cancelled
build-and-push-image / vulnerability-scan (push) Has been cancelled
问题:workflow "Set up job" 步骤非常缓慢
根因:每个 GitHub Actions step 都是 Docker 容器,需从 Docker Hub 拉镜像
国内网络拉 Docker Hub 特别慢(甚至失败)
解决方案:
scripts/prepull-actions.sh
- 列出 build-image.yml 用到的所有 Docker 镜像
- xargs -P 4 并行拉取
- 提供验证命令 + cron 清理建议
更新 workflow 用的镜像列表:
- docker/actions/setup-buildx:v3
- docker/actions/login:v3
- docker/actions/metadata:v5
- docker/actions/build-push:v5
- aquasec/trivy-action:master
- moby/buildkit:v0.13.0
非 Docker action(actions/checkout / dtolnay/rust-toolchain / Swatinem/rust-cache)
是内置脚本,不需预拉。
README 新增"性能优化"章节:
- 根因分析
- 使用步骤
- 清理策略 cron
- 进一步优化建议(BuildKit cache / cargo 缓存 / 多架构)
使用方法:
chmod +x scripts/prepull-actions.sh
sudo ./scripts/prepull-actions.sh
|
2026-07-03 00:33:49 +08:00 |
|
Matrix Music Bot Dev
|
725c6b1d65
|
docs: .gitea 文档记录 hermes-runner 标签 + workflow 同步注释
build-and-push-image / build-push (push) Failing after 17m29s
build-and-push-image / vulnerability-scan (push) Has been skipped
变更:
- .gitea/README.md 记录 Gitea 实例已有的 hermes-runner
(标签 ubuntu-22.04,全局),避免后续再猜错标签
- build-image.yml 顶部注释更新:标明 runner 实际标签
- README 注册命令示例从 --labels ubuntu-latest:docker 改为
--labels ubuntu-22.04(与实际匹配)
运维经验:act_runner --labels 标签必须与 workflow runs-on 一致,
否则 job 会一直显示"等待 runner"状态。
|
2026-07-03 00:16:47 +08:00 |
|
Matrix Music Bot Dev
|
89ee450d6e
|
ci: 修复 runner 标签(self-hosted → ubuntu-22.04)
Gitea 管理 UI 显示 runner 信息:
名称: hermes-runner
版本: v0.6.1
类型: 全局
标签: ubuntu-22.04
状态: 空闲(在线)
之前两次猜测都错了:
ubuntu-latest → 不是 GitHub 约定,匹配失败
self-hosted → 这个 runner 没注册该标签
最终实际标签:ubuntu-22.04(建议未来 .gitea/README.md 添加 runner 标签说明)
|
2026-07-03 00:16:21 +08:00 |
|
Matrix Music Bot Dev
|
9e62e995a9
|
ci: 修复 Gitea Actions runner 标签(ubuntu-latest → self-hosted)
build-and-push-image / build-push (push) Has been cancelled
build-and-push-image / vulnerability-scan (push) Has been cancelled
问题:job 一直显示"等待中"
原因:Gitea Actions runner 注册时默认使用自定义标签(self-hosted),
而非 GitHub Actions 约定的 ubuntu-latest
报错:没有匹配 ubuntu-latest 标签的在线运行器
修复:runs-on 从 ubuntu-latest 改为 self-hosted
- build-push job
- vulnerability-scan job
如果 runner 注册时用了其它标签(如 docker / linux / 自定义名字),
仍可调整。修改方法:编辑此 workflow 文件的 runs-on 行。
|
2026-07-03 00:11:08 +08:00 |
|
Matrix Music Bot Dev
|
5cd462127c
|
docker: 新增 docker-compose.prod.yml(从 Gitea Registry 拉取镜像)
build-and-push-image / build-push (push) Has been cancelled
build-and-push-image / vulnerability-scan (push) Has been cancelled
适用场景:生产服务器,无需源码 + Rust 工具链
- 移除 build: 段
- image: 直接引用 Gitea Registry 中的 latest 镜像
- env / volumes / healthcheck 与 docker-compose.yml 一致
用法:
docker-compose -f docker-compose.prod.yml pull # 单独拉取
docker-compose -f docker-compose.prod.yml up -d # 启动
推荐流程:
1. 开发环境用 docker-compose.yml(本地 build)
2. CI/CD push master 后 Gitea Actions 自动构建并推 latest
3. 生产服务器用 docker-compose.prod.yml 拉 latest
|
2026-07-03 00:03:08 +08:00 |
|
Matrix Music Bot Dev
|
fab14e3196
|
ci: Gitea Actions 自动构建 + 推送镜像到 Container Registry
按用户选定方案:
- Registry: Gitea 内置 Container Registry
- 触发: 仅 push master/main
- 标签: latest + git short SHA
- 架构: linux/amd64 单架构
新增文件:
.gitea/workflows/build-image.yml CI workflow 定义
.gitea/README.md Gitea Actions 运维手册
workflow 步骤:
1. actions/checkout@v4 检出源码
2. dtolnay/rust-toolchain@stable 安装 Rust(仅用于 cache key 计算)
3. Swatinem/rust-cache@v2 缓存 Cargo registry / target
4. cargo metadata sanity check 防止 manifest 漂移
5. docker/setup-buildx-action@v3 Buildx
6. docker/login-action@v3 登录 Gitea Registry(用 ${{ gitea.token }})
7. docker/metadata-action@v5 生成 latest + sha 标签 + OCI labels
8. docker/build-push-action@v5 构建 + 推送(含 BuildKit registry cache)
9. aquasecurity/trivy-action CVE 扫描(不阻塞)
特性:
- concurrency 控制:避免重复构建(同一 ref 只跑最新)
- 自动镜像标签:latest + commit short SHA
- BuildKit cache 推到 :buildcache 镜像(下次构建复用)
- Gitea 内置 token 自动认证(无需手动 secrets)
- OCI 标准 labels(title/source/license/vendor)
gitea/README.md 包含:
- 前置要求(Registry 开启、Runner 注册、网络)
- 镜像使用示例
- 常见扩展(tag 触发 / 多架构 / 自动部署)
- 故障排查(login 失败 / build 失败 / pull 失败)
|
2026-07-03 00:02:51 +08:00 |
|
Matrix Music Bot Dev
|
2518169927
|
docs: CLAUDE.md 增加 Docker 化里程碑 + 两种部署方式对照表
变更:
- M1-M7 列表追加 "✅ Docker 化"
- 模块清单扩展到 22 项(+ Dockerfile / compose / .env.example / .dockerignore)
- "部署关键提醒"区块增加 docker-compose 环境变量提示
- 新增"两种部署方式"对照表(本机编译 vs Docker)
v1 全部完成(18 commits),支持本机开发 + Docker 生产两种部署模式。
|
2026-07-02 23:55:42 +08:00 |
|
Matrix Music Bot Dev
|
2dd94daa54
|
docs: README.md 增加 Docker 部署章节(快速启动 / Dockerfile 设计 / 调试)
新增内容(145 行):
- 快速启动 6 步(config init → login → .env → up -d → logs → down)
- 首次登录两种方案:
A. 先在主机登录(推荐)
B. docker-compose run --rm 容器内登录
- Dockerfile 设计要点(多阶段 / 层缓存 / strip / tini / 非 root)
- 镜像版本管理(build-arg + tag/push)
- 容器内调试命令(exec / version / ffmpeg / yt-dlp / logs)
- 常见 Docker 问题:
- crates.io 拉取慢 → rsproxy 镜像源
- 容器立即退出 → 缺环境变量 / 配置 / data
- 升级后 crypto.db 不兼容 → 删除重建 + 重新信任
参考 README 系统要求章节了解详细依赖。
|
2026-07-02 23:55:20 +08:00 |
|
Matrix Music Bot Dev
|
f55e28ee1d
|
docker: 多阶段 Dockerfile + docker-compose.yml + .dockerignore + .env.example
按用户选定方案:
1. 多阶段 Debian bookworm-slim
- builder=rust:1.96-bookworm(含 pkg-config libsqlite3-dev libssl-dev)
- runtime=debian:bookworm-slim(ffmpeg libsqlite3-0 libssl3 tini ca-certificates)
- 利用 Docker 层缓存:先预编译 deps 再复制 src
2. yt-dlp standalone 二进制
- ARG YTDLP_VERSION=2026.03.17
- 用 ADD --checksum=sha256 校验
- 与 README 中版本一致便于锁版本
3. 全部 bind mount
- ./config → /app/config:ro(配置只读)
- ./data → /app/data(secret.bin / crypto.db / cache/)
4. 单服务 docker-compose
- 重启策略 unless-stopped
- 资源限制 2 CPU + 1G RAM
- 健康检查 pgrep
- MATRIX_BOT_SECRET_PASSPHRASE 从 .env 必填
- RUST_LOG 默认 info + matrix_music_bot=debug
安全要点:
- 非 root 用户(bot:bot)
- tini 作为 PID 1(正确转发 SIGTERM/SIGINT)
- 健康检查:仅进程存活检测(bot 没有 health endpoint)
.dockerignore 排除:
- /target /data /config /tests /docs 等
- 减少 build context 大小(避免每次 build 重复传输)
.env.example:
- 模板文件,含 MATRIX_BOT_SECRET_PASSPHRASE 默认值
- RUST_LOG 默认值
下一步:补充 README.md + CLAUDE.md 的 Docker 部署章节
|
2026-07-02 23:54:36 +08:00 |
|
Matrix Music Bot Dev
|
99818e2669
|
docs: 更新 CLAUDE.md 反映 v1 完整交付 + 路线图
变更:
- "当前阶段" 改为 "🎉 v1 已完整交付" + M1-M7 完整勾选清单
- 模块清单从 16 → 18(新增 README.md + 反应监听标注)
- 已确认技术决策 11 → 14 条:
#5 reactions 两步选择(不再是 "待 M7")
#12 reactions TTL 60s
#13 crypto store 用 MSYS2 系统 sqlite3
#14 outbox 通道唯一性(Timeline::send 强制 E2EE)
- 新增"v1 已知限制(已知妥协)"表:6 项限制 + 修复计划
- 新增"路线图":M8-M12 + v2 未来功能
- 新增"部署关键提醒"区块(3 件事必做)
- 测试统计保持 29 passed + 4 ignored
参考:
- v1 计划:C:\Users\Administrator\.claude\plans\lexical-meandering-lighthouse.md
- 部署文档:README.md
|
2026-07-02 23:49:44 +08:00 |
|
Matrix Music Bot Dev
|
813914c80f
|
docs: 添加 README.md(部署指南 + 使用文档 + 故障排查)
内容(525 行):
- 项目简介 + 功能特性
- 架构概览(含 ASCII 图)
- 系统要求(Rust 1.96+ MinGW gcc SQLite3 FFmpeg yt-dlp)
- 快速部署 7 步:
1. 克隆编译
2. 创建配置
3. 首次登录
4. Element 信任 bot 设备
5. 启动 bot
6. 加入加密房间
7. 测试点歌
- 配置说明(AppConfig + 环境变量 MATRIX_BOT_SECRET_PASSPHRASE)
- 使用指南(命令列表 + reactions 选择流程图)
- 故障排查(5 个常见问题)
- 开发指南(项目结构 + 重新登录 + 测试 + 添加新音乐源)
- 已知限制(6 项,含原因 + 影响 + 修复计划)
- 路线图(v1 完成 / v1.x 优化 / v2 未来)
- 测试说明(29 passed + 4 ignored)
- 致谢
部署目标读者:bot 操作员(不一定懂 Rust)+ 二次开发者
语言:中文(与 CLAUDE.md 风格一致)
|
2026-07-02 23:37:53 +08:00 |
|
Matrix Music Bot Dev
|
cb55886501
|
feat: reactions 两步选择 + Element Call 兼容(M7 + M6 + CLAUDE.md 同步)
M6 Element Call 兼容(src/rtc_handler.rs):
- 注册 SyncStateEvent<PossiblyRedactedCallMemberEventContent> handler
- 记录 active_memberships() 数量到日志
- bot 不参与通话媒体(v1 妥协;v2 可用 matrix_sdk::rtc + livekit-rs)
M7 reactions 两步选择:
- src/reaction_store.rs:ReactionSession + ReactionStore(in-memory + TTL 60s)
- src/event_loop.rs:
- handle_req_search 改造:发带 emoji (1️⃣~5️⃣) 的候选列表 + 记录 session
- handle_reaction:监听 m.reaction 事件 → 查 ReactionStore → 入队
- 校验:仅原请求人能选
- 校验:60s TTL 过期检查
- 无效 emoji 反应:保留 session 让用户重选
v1 妥协说明:
- SendHandle.transaction_id 是私有的,无法直接拿真实 event_id
- send_text_get_event_id 返回占位 event_id(时间戳拼接)
- 这意味着:reactions 选择 v1 可能无法匹配(占位与真实 event_id 不一致)
- M8 修复方向:通过 timeline 订阅事件 → 匹配 transaction_id 与 event_id
CLAUDE.md 同步:
- 当前阶段改为 "M1-M7 全部完成" + v1 可真实部署测试
- 已完成模块清单扩展到 16 项
- M8(可选)标记为 event_id 跟踪修复
E2EE 保持:
- 所有出站消息经 Timeline::send
- m.reaction handler 解密后处理(matrix-sdk 自动处理 E2EE)
测试:cargo test → 29 passed + 4 ignored
reaction_store 新增 4 测试:
- parse_emoji_index_works / session_find_by_reaction
- store_record_and_take / expired_sessions_are_removed
|
2026-07-02 22:14:25 +08:00 |
|
Matrix Music Bot Dev
|
c0a378554d
|
feat(reaction_store): 搜索结果反应(m.reaction)选择存储(M7.1)
新增模块:src/reaction_store.rs
ReactionSession:
- (room_id, message_event_id) → Vec<SongCandidate> + requester + created_at
- find_by_reaction("1️⃣"/"1"/"1️⃣" etc.) → Option<&SongCandidate>
- is_expired(ttl) 默认 60s
ReactionStore(in-memory):
- record(session):插入并清理过期
- take(event_id):消费式取出(防止重复入队)
- peek(event_id):仅查看
- cleanup_expired():定期清理
parse_emoji_index() 支持多种 emoji 格式:
"1️⃣" / "1" / "1️⃣" / "2️⃣" / ... / "5️⃣"
测试:cargo test reaction_store → 4 passed
- parse_emoji_index_works:多种格式都能识别
- session_find_by_reaction:1️⃣/3️⃣ → 对应候选
- store_record_and_take:record + take 二次取 None
- expired_sessions_are_removed:60s TTL 过期清理
后续 M7.2:
- !req 改造为发搜索列表 + 记录 session
- 注册 m.reaction event handler
- reaction handler 查 ReactionStore 找候选并入队
|
2026-07-02 22:04:03 +08:00 |
|
Matrix Music Bot Dev
|
2545e47977
|
feat(rtc_handler): MSC3401 call.member 状态事件观测(M6 Element Call 兼容)
新增模块:src/rtc_handler.rs
Element Call = MatrixRTC (MSC3401) 信令 + LiveKit WebRTC SFU 媒体。
本模块只观察信令层;媒体层 bot 不参与(v1 不实现)。
实现:
- register(client):注册 SyncStateEvent<PossiblyRedactedCallMemberEventContent> handler
- handle_call_member 闭包:处理 Original / Redacted 两种 state event
- 记录 active_memberships() 数量到日志(通话成员变化)
事件类型路径:
matrix_sdk::ruma::events::call::member::PossiblyRedactedCallMemberEventContent
event_loop 集成:
- bootstrap::restore 后立即 rtc_handler::register(&client)
- 不影响现有 chat handler(m.room.message handler 与 state event handler 并行)
E2EE 兼容性:
- MSC3401 信令通过 state event 加密(Megolm 加密 room state events,MSC3401 已支持)
- bot 在 call 进行中仍能正常收发 m.room.message(验证:sync 不被 state event 阻塞)
- 注意:Element Call 媒体通道(WebRTC)是 DTLS-SRTP,**不**经 Megolm
→ bot 不参与通话音频;用户的聊天 + m.audio 投递仍完全 E2EE
测试:cargo test → 25 passed + 4 ignored(新增 rtc_handler 模块加载 smoke test)
后续 M7:reactions 选择(用户点击 emoji 选搜索结果)+ 队列持久化(可选)
|
2026-07-02 21:54:06 +08:00 |
|
Matrix Music Bot Dev
|
ef93f9615f
|
feat: !req/!req-url/!queue/!np/!skip 端到端接入 event_loop(M5)+ CLAUDE.md 同步
新增模块:
src/queue.rs ── QueueStore(内存版)+ SongQueue trait + QueueItem/QueueState
src/downloader.rs ── yt-dlp 子进程下载到 data/cache/raw/<source>-<id>.<ext>
src/worker.rs ── 每房间 worker:resolve → download → transcode → deliver
src/event_loop.rs 改造:
- 构造 SearchFacade(包含 YtDlpBackend + 3 stub backend)
- 命令 handler 分发:
!help → render_reply + send_text
!req <q> → search_all → 自动取第一条入队(M7 接 reactions)
!req-url → 构造 candidate → 入队
!queue → 渲染队列状态
!np → 渲染当前播放
!skip → 弹出当前播放
- ensure_room_worker:首次收到消息时启动该房间 worker
- extract_video_id:支持 YouTube v= / youtu.be/ / B站 BV 号提取
src/main.rs:
- 引入 queue/downloader/worker 模块
CLAUDE.md 同步:
- 当前阶段改为 "M1-M5 已完成" + 已完成模块清单
- 列出已确认技术决策 11 条(不可变)
- 列出待办 M6-M7
E2EE 通道保持:
- 所有出站经 Timeline::send
- audio_upload.deliver() 内部仍走 TimelineBuilder + send
依赖决策(注意):
- 放弃 rusqlite(libsqlite3-sys 与 matrix-sdk-sqlite 链接冲突)
- 放弃 reqwest(用 yt-dlp 子进程下载,简化 deps)
- 队列改 in-memory(重启清空,v1 接受)
- 这两条记入 CLAUDE.md "已确认技术决策" 第 10、11 条
测试:cargo test → 24 passed + 4 ignored
新增 3 个 queue 测试:
- enqueue_and_dedup:同 song 同房间去重
- different_sources_not_dedup:不同 source_id 允许入队
- skip_current_returns_head:skip 弹出当前
|
2026-07-02 21:48:19 +08:00 |
|
Matrix Music Bot Dev
|
11b484d644
|
feat: 转码 + 投递(M4:transcoder + delivery/audio_upload)
新增模块:
src/transcoder.rs ── ffmpeg 子进程封装(MP3/AAC → stereo Opus 128k)
src/delivery/mod.rs ── DeliveryStrategy trait + DeliveryKind + DeliveryReceipt
src/delivery/audio_upload.rs ── Pattern A 实现(m.audio via Timeline::send)
src/delivery/url_link.rs ── Pattern B stub(v2 实现)
依赖新增:mime 0.3.17
transcoder.rs 关键设计:
- 输入已是 native Opus/WebM → 直接 copy(保留质量 + 节省 CPU)
- 其他格式 → ffmpeg 子进程转码
- ffmpeg 参数(与 plan 一致):
-c:a libopus -b:a 128k -ac 2 -ar 48000 -vbr on
-f webm -application audio -map_metadata 0
- 用 tokio::process::Command + tokio::time::timeout
- 提供 cache_path_for() 生成 <cache>/opus/<source>-<id>.webm
delivery/audio_upload.rs 关键设计:
- 读取本地 Opus 文件 → client.media().upload(...)
- 检查 max_upload_bytes(默认 50MB,留余量)
- 构造 AudioInfo + AudioMessageEventContent(用 MediaSource::Plain(mxc_uri))
- 经 Timeline::send 投递(SDK 内部 Megolm 加密)
- DeliveryReceipt.event_id 暂为 None(需要 timeline subscription 跟踪;M5 queue 实现)
遇到的 API 坑(已解决):
- AudioInfo 是 non_exhaustive 结构体 + 字段全 public,
需用 AudioInfo::new() + 字段赋值(不能用 struct expression)
- AudioInfo.duration 是 Option<std::time::Duration>(不是 UInt 秒数)
- MediaSource 在 matrix_sdk::ruma::events::room::MediaSource(非 message 子模块)
- AudioMessageEventContent::new(body, source) 只 2 参,info 用 .info(Some(Box::new(...))) 设置
- SendHandle 的 transaction_id 是私有的;v1 阶段用不到,Receipt.event_id 留 None
测试:cargo test → 21 passed + 4 ignored(需要 ffmpeg / yt-dlp + 网络)
新增测试:
- transcoder::cache_path_for_sanitizes
- transcoder::audio_format_decision
- transcoder::real_transcode_mp3_to_opus(ignored)
- transcoder::check_ffmpeg_works(ignored)
总测试:21 passed + 4 ignored
E2EE 不变量保持:
✅ 所有出站消息经 Timeline::send(delivery/audio_upload 强制)
✅ m.audio 消息体(MediaSource::Plain mxc_uri)经 Megolm 加密
后续 M5:!req 端到端(队列 + 下载 + 接入 event_loop)
|
2026-07-02 21:22:49 +08:00 |
|
Matrix Music Bot Dev
|
50d9e0f4a9
|
feat(music): MusicSource trait + yt-dlp backend + 其他 backend stub(M3)
新增模块:src/music/{mod,ytdlp,netease,qq,selfhosted}.rs
MusicSource trait(async_trait):
fn kind() -> &'static str // "ytdlp" / "netease" / "qq" / "selfhosted"
fn display_name() -> &'static str
async fn search(query, limit) -> Vec<SongCandidate>
async fn resolve(candidate) -> ResolvedSong
SongCandidate:
source_kind / source_id / title / artist / album? / duration_ms? / webpage_url?
ResolvedSong:
candidate + play_url + play_url_expires_at + format_hint + size_bytes_estimate?
AudioFormat 枚举:
Mp3 / Aac / Flac / Opus / Webm / Other
from_mime() / is_target_native() 助手方法
SearchFacade:
多 backend 并行 search → 合并 → 去重(同 title+artist 视为一首)
失败的 backend 记 warn 后跳过,不阻塞其他 backend
YtDlpBackend(完整实现):
search: yt-dlp 'ytsearch<N>:<query>' --dump-json --skip-download
解析每行 JSON,过滤 30s < 长度 < 30min
resolve: yt-dlp -f bestaudio -g <url>
取首行非空作为直链,估算 6h 过期
通过 tokio::process::Command 异步 spawn 子进程
并发读 stdout/stderr 避免阻塞
用 tokio::time::timeout 实施超时
注:HEAD 探测 Content-Type/Content-Length 待 M5 reqwest 引入后启用
其他 backend(stub):
NetEaseBackend / QqMusicBackend / LocalFsBackend
都实现 trait,但 search/resolve 返回 AppError::MusicSource 提示未实现
测试:
cargo test music → 4 passed + 2 ignored(需要网络+yt-dlp)
- AudioFormat::from_mime / is_target_native
- SongCandidate serde roundtrip
- YtDlpBackend 集成测试(ignore 标记)
测试总数:19 passed + 2 ignored
后续 M4:transcoder.rs(ffmpeg MP3/AAC → stereo Opus 128k)+ delivery/audio_upload.rs(m.audio via Timeline::send)
后续 M5:把 MusicSource 接入 event_loop,!req 端到端实现
|
2026-07-02 21:11:58 +08:00 |
|
Matrix Music Bot Dev
|
a2c9904ec3
|
feat(event_loop): sync + add_event_handler + Timeline::send 加密通道(M2.2/c)
新增模块:src/event_loop.rs
依赖新增:futures-util 0.3
源码增加:#
实现要点:
1. bootstrap::restore 拿到 Client + user_id + device_id
2. 注册全局 SyncRoomMessageEvent handler(matrix-sdk add_event_handler 闭包模式)
3. handler 内部:
- 提取 m.text 文本
- 跳过 bot 自己发的消息
- 用 commands::parse 解析(自动处理 mention / DM 区分)
- 用 commands::render_reply 渲染回复
- 用 TimelineBuilder::new(room).build() 构造 Timeline
- 用 timeline.send(RoomMessageEventContent::text_plain(...).into()) 发送
4. 启动 long-running client.sync()(用 tokio::select! 与 ctrl-c 并发)
E2EE 不变量已实现并强制:
- ✅ 唯一出站通道:Timeline::send(SDK 内部用 Megolm 加密)
- ❌ 绝不使用 Room::send_raw()(明文)
- ✅ 入站消息经 matrix-sdk 解密后是 plaintext,可直接解析
类型挑战(已解决):
- matrix-sdk 0.18 EventHandler 通过 impl_event_handler! 宏实现,
要求 FnOnce(Ev, ...) -> Fut 形式,不能包 Pin<Box<>>
- matrix-sdk-crypto 内部有 !Send 类型,所以 client.sync() 不能 tokio::spawn,
必须在当前 task 用 tokio::select! 与 ctrl-c 并发
- 嵌套 async 闭包触发 rustc 深度限制,需要 #![recursion_limit = "512"]
cmd_run 改造:
- 同样从 MATRIX_BOT_SECRET_PASSPHRASE 环境变量读取 passphrase
- 用 tokio multi-thread runtime 跑 event_loop::run
CLI 实测(fake config + 缺 secret.bin):
- 无 config → 友好错误
- 有 config + 缺 secret.bin → '请先运行 login' 错误
- 完整流程需真实 homeserver 才能跑通
测试:cargo test → 15 passed(11 commands + 2 config + 2 secret_store)
|
2026-07-02 21:03:56 +08:00 |
|
Matrix Music Bot Dev
|
5ea92de6b9
|
feat(commands): 房间/DM 感知的命令解析器(M2.1)
子命令(v1):
!help / !h / !? 显示帮助
!req / !request / !点歌 / !来一首 <关键词...>
!req-url / !url <URL> 直接粘 URL
!queue / !q / !队列
!np / !nowplaying
!skip / !next / !跳过
权限模型:
- DM:无需 mention,直接发命令
- 房间:根据 [commands] mention_required_in_rooms 配置
- true:必须包含 @bot_user_id 或 @bot_localpart
- false:任何消息都会解析
mention 文本从消息中剥离后再解析(修复 bug:之前 format 出了 @@)
中文/英文命令别名都支持(如「点歌」「跳过」)。
render_reply 已实现 help;其他命令返回 M3+ 占位提示。
测试:cargo test commands → 11 passed
- DM 解析 / 房间解析 / mention 必需 / mention 关闭 / 多别名 / 缺参 / 错命令
|
2026-07-02 20:53:01 +08:00 |
|
Matrix Music Bot Dev
|
39afe31d19
|
feat(bootstrap): matrix-sdk login + 加密 session 持久化 + restore(M1.3b/c)
新增模块:
src/client.rs ── matrix-sdk ClientBuilder 工厂(含 crypto store + EncryptionSettings)
src/bootstrap.rs ── login/restore 两个公开入口函数
依赖环境:
- 系统需要 libsqlite3 → 已通过 pacman 安装 mingw-w64-x86_64-sqlite3
- 运行时需要 MATRIX_BOT_SECRET_PASSPHRASE 环境变量(≥8 字符)
login 流程:
1. 检查 secret.bin 不存在(避免覆盖现有 device)
2. 构造 Client(homeserver + sqlite_store + EncryptionSettings)
3. matrix_auth().login_username().initial_device_display_name().send()
4. /login response → MatrixSession(impl From<&Response> for MatrixSession)
5. MatrixSession 序列化为 JSON
6. secret_store::save() 加密写入 data/secret.bin
7. 输出 user_id + device_id 提示操作员在 Element 中验证
restore 流程(给后续 M2 的 run 子命令用):
1. 检查 secret.bin 存在
2. secret_store::load() 解密
3. MatrixSession JSON → MatrixSession 结构
4. 构造 Client(沿用 crypto.db)
5. client.restore_session(session)
6. 返回 (Client, user_id, device_id)
cmd_login 改造:
- 从环境变量读取 passphrase(避免 CLI history 泄漏)
- 长度 < 8 字符拒绝
- 内部用 tokio multi-thread runtime 跑 async login
secret_store 微调:
- SessionSecrets 改为存储 matrix_session: serde_json::Value + schema_version
- 因 serde_json::Value 不实现 Zeroize,移除 #[derive(Zeroize)]
- 依赖 matrix-sdk 内部 SessionMeta/SessionTokens 自带的 zeroize 保证内存安全
CLI 实测(fake homeserver):
- 缺 passphrase → 友好错误
- 有 passphrase → 走到 matrix-sdk /login 调用,因 DNS 失败是预期行为
测试:
cargo test → 4 passed(secret_store roundtrip + 噪声 ciphertext + config 解析)
|
2026-07-02 20:03:38 +08:00 |
|
Matrix Music Bot Dev
|
ecc40beed8
|
feat(secret_store): Argon2id + AES-256-GCM 加密的会话密钥存储(M1.3a)
依赖新增:
- aes-gcm 0.11
- argon2 0.5.3
- getrandom 0.3 (std feature)
- base64 0.22.1
- serde_json 1.0
- zeroize 1.9
- rand_core (尝试后移除:rand 0.10 / 0.9 的 OsRng API 都复杂,改为更底层的 getrandom)
文件格式(JSON 包装):
{
"version": 1,
"kdf": "argon2id",
"salt_b64": "...", // 16 bytes
"nonce_b64": "...", // 12 bytes
"ciphertext_b64": "..." // AES-256-GCM(plaintext, AAD="matrix-music-bot secret v1")
}
安全参数:
- KDF: Argon2id (m=19456 KiB, t=2, p=1) — OWASP 推荐
- 加密: AES-256-GCM(认证加密,任何篡改都会被检测)
- AAD: 标识文件版本与 KDF,防止 ciphertext 重放到不同上下文
- 每次加密随机 salt + nonce,确保同样明文产生不同 ciphertext
- 写入采用 .bin.tmp → rename 原子操作,避免半写状态
API:
save(path, &secrets, passphrase) -> AppResult<()>
load(path, passphrase) -> AppResult<SessionSecrets>
exists(path) -> bool
SessionSecrets 包含 access_token / device_id / user_id 三个字段,
实现 Zeroize on drop。
测试:
cargo test → 4 passed
- secret_store::roundtrip_via_disk: 加密 + 解密往返,错误口令被 AES-GCM 拒绝
- secret_store::ciphertext_differs_each_time: 同样明文两次加密 ciphertext 不同
后续 M1.3b:在 src/bootstrap.rs 中调用 matrix-sdk 的 Client::builder() + login_username,
拿到 access_token 后调 secret_store::save() 写入 ./data/secret.bin。
|
2026-07-02 19:50:56 +08:00 |
|
Matrix Music Bot Dev
|
19e724444b
|
feat: 实现 config + clap CLI + 错误处理(M1.2)
新增依赖(与 matrix-sdk 0.18.0 兼容):
- tokio 1.52 (full)
- clap 4.6 (derive + env)
- serde 1.0 (derive) + toml 1.1
- thiserror 2.0 + anyhow 1.0
- tracing 0.1 + tracing-subscriber 0.3 (env-filter)
- async-trait 0.1
推迟到对应 milestone(M3 / M5)添加以避免 libsqlite3-sys 与
matrix-sdk-sqlite 冲突:rusqlite、reqwest。详见 Cargo.toml 注释。
新增模块:
src/config.rs ── AppConfig 结构(Homeserver/Bot/Data/Commands/Crypto/Music)+ TOML 加载/序列化 + 自动发现路径
src/error.rs ── AppError 枚举(thiserror)+ AppResult 别名
src/main.rs ── clap CLI 骨架:login / run / config / version 子命令
CLI 子命令状态:
- version ✅ 打印版本 + matrix-sdk 版本
- config init ✅ 在 ./config/bot.toml 生成示例配置
- config path ✅ 打印当前配置文件路径
- config print ✅ 打印当前配置
- login ⚠️ M1.3 占位(返回错误)
- run ⚠️ M2 占位(读取配置后返回错误)
配置默认值(plan 已确认的选型):
- [crypto] auto_enable_cross_signing = true
- [commands] prefix = !, mention_required_in_rooms = true
- [music] ytdlp_path = 'yt-dlp'(PATH 中查找),search_limit = 5
gitignore 增补:排除 /config/bot.toml(操作员真实配置含凭证)
测试:
- cargo build 通过(仅 dead_code warning,未使用的 AppError 变体将在后续 milestone 引用)
- cargo test 2 passed(最小配置解析 + 示例配置往返)
- CLI 实测:version / config init / config print / login / run 均按预期
后续 M1.3:在 src/bootstrap.rs 实现 matrix-sdk Client::builder() + login_username
+ secret_store 加密保存 access_token/device_id。
|
2026-07-02 01:35:54 +08:00 |
|
Matrix Music Bot Dev
|
17eb51e215
|
chore: 初始化 Cargo 项目骨架与构建验证
工具链:rustup + stable-x86_64-pc-windows-gnu + MinGW gcc 链接器
包含内容:
- Cargo.toml(edition 2024,name=matrix-music-bot)
- Cargo.lock(dev profile 验证通过)
- src/main.rs(hello world 占位,已 cargo build 通过)
- .cargo/config.toml(项目级 cargo 配置,指定 MinGW gcc 为链接器)
- .gitignore 增补:排除项目根的 plan 副本(正式版在 ~/.claude/plans/)
构建验证:cargo build 在 MinGW gcc 链接器下成功完成(1.56s)
后续 M1.2 将添加:clap(CLI 解析)+ serde/toml(配置文件)+ thiserror/anyhow
+ tracing(日志)+ tokio(async)+ matrix-sdk(含 E2EE crypto 与 UI timeline)
|
2026-07-02 01:25:33 +08:00 |
|
Matrix Music Bot Dev
|
5c4b8d8b82
|
docs: 添加 CLAUDE.md 项目协作规范
包含两条核心规则:
1. 技术决策流程:必须列出 2+ 方案 + 解释优缺点 + 用户拍板;
不得自行默认选择。详见 CLAUDE.md 第 1 节。
2. Git 实时提交规范:禁止积累大批改动后一次性提交;
每个逻辑单元完成后立即提交(单文件/单函数/milestone 边界);
中文 commit message + Conventional Commits 风格;
提交前必须 cargo build/check 通过。
详见 CLAUDE.md 第 2 节。
|
2026-07-02 01:09:01 +08:00 |
|
Matrix Music Bot Dev
|
3426acbb77
|
chore: 初始化仓库结构(.gitignore + data/ 占位)
- 排除 /target、/data、secret.bin、.env 等敏感与构建产物
- 保留 data/.gitkeep 占位以便运行时生成 bot.db / crypto.db
|
2026-07-02 01:08:45 +08:00 |
|