Files
lxc-streamutils/docs/architecture.md
T
felis f79852d8e6 add account localization and switchable rooms
Centralize control and OBS copy in a shared TOML catalog, persist the selected locale per account, and broadcast language changes to component streams. Allow account owners to atomically switch their Bilibili room and restart the shared listener without changing component URLs.
2026-07-18 23:28:05 -07:00

4.6 KiB

系统架构

本文描述直播组件服务的运行边界、数据流和扩展点。实现代码分别位于 apps/server-rust 与 apps/overlay。

核心目标

  • 每个账户拥有一个可切换的 Bilibili 直播间、一个 CookieCloud 来源和一条独立监听连接。
  • 组件不绑定或选择直播源;账户事件流会提供给该账户所有启用的组件实例。
  • 平台原始命令先转换成稳定的领域事件,组件不直接依赖 Bilibili CMD。
  • HTTP 会话、直播源、组件、OBS token 和实时通道均以租户为边界。
  • 新组件可以增加设置、投影和持久化副作用,而不修改直播连接核心。

运行时数据流

flowchart LR
  CC[CookieCloud] --> PF[ProviderFactory]
  BL[Bilibili Live] <--> BP[BilibiliProvider]
  PF --> BP
  BP --> LE[LiveEvent]
  LE --> SR[SourceEventRouter]
  PG[(PostgreSQL)] --> CR[Component repository/cache]
  CR --> SR
  SR --> EH[Durable handlers]
  SR --> PJ[Passive projection]
  PJ --> HUB[Component-scoped EventHub]
  HUB --> WS[Authenticated WebSocket]
  WS --> OBS[OBS overlay]
  1. SourceSupervisor 为每个 source_id 保持至多一个 provider task。
  2. BilibiliProvider 使用该用户加密保存的 CookieCloud 凭据构造 libilibili 客户端;crate 负责 WBI、WebSocket 与压缩包解析,adapter 再把强类型命令转换成 LiveEvent。
  3. SourceEventRouter 按 owner_id 取得该账户所有启用组件,再由各组件的订阅声明筛选事件类型;source_id 只标识账户级监听,不存储在组件行中。
  4. 匹配订阅后,路由器先执行可持久化的 EventHandler,再执行无副作用的 EventProjection。
  5. 投影结果只发布到该 component_id 的广播通道。没有全局 WebSocket 事件总线。
  6. OBS 使用组件级只读 token 订阅一个组件,不能读取控制台 API。

状态所有权

状态 权威来源 内存副本 说明
用户、TOTP、会话 PostgreSQL 无 Secret 加密,token 只保存摘要
CookieCloud 凭据 PostgreSQL provider 构建期间解密 每账户一份,不返回浏览器
直播源和房间 PostgreSQL SourceSupervisor 每账户一个可切换房间和连接
组件实例与设置 PostgreSQL InMemoryComponentStore 写入成功后刷新热路径缓存
礼物/表情目录 Bilibili API provider catalog 刷新失败保留最近成功快照
实时消息 provider EventHub 有界广播 不作为业务持久化机制
点歌队列和评分 PostgreSQL OBS revision snapshot handler 事务写入、RLS 隔离
账户语言偏好 PostgreSQL React/OBS runtime TOML 目录验证、RLS 隔离
PWA 静态壳层 Docker 镜像 Cache Storage 不包含 API 或用户数据

启动顺序

AppState::build 按以下顺序启动,避免事件进入未完成的运行时:

  1. 创建 PostgreSQL 连接池并执行嵌入式迁移。
  2. 构造加密和 passwordless 鉴权服务。
  3. 注册内建组件定义。
  4. 从 PostgreSQL hydrate 组件热路径缓存。
  5. 创建有界源事件队列、路由器和每组件广播中心。
  6. 为数据库中所有启用的直播源启动 provider。
  7. 最后由 main.rs 绑定 HTTP 监听端口。

关机时先停止接收 HTTP,再取消所有 provider task,防止容器退出期间继续拉取上游事件。

进程与部署边界

  • Node 只存在于 Docker 的前端构建阶段。
  • 最终镜像仅运行 Rust 可执行文件,并从 /app/web 同域托管静态资源。
  • 容器使用 host network,但默认只监听 127.0.0.1:9719。
  • Nginx 负责公网 TLS、域名和 WebSocket upgrade。
  • CookieCloud 与 PostgreSQL 是外部服务,不由本项目 Compose 创建。
  • libilibili 是源码树中的相邻 crate,由 Compose named build context 注入 Rust 构建阶段。
  • resources/i18n.toml 同时输入 Vite 和 Rust 构建;缺少默认语言键的 locale 会使后端测试失败。

代码导航