跳转到内容

开发环境

SyncTV 是 Rust workspace,开发时通常需要:

  • Rust stable toolchain。
  • PostgreSQL。
  • Redis。
  • Node.js 和 npm,用于 docs/ 文档站。
  • Docker 和 Docker Compose,用于快速启动依赖服务。
  • Protobuf/gRPC 相关构建依赖,具体取决于本机平台和 Rust crate 构建过程。

建议先确认:

Terminal window
rustc --version
cargo --version
docker --version
docker compose version
node --version
npm --version
  • synctv 核心二进制和 CLI
  • synctv-core 业务逻辑、配置、服务和 repository
  • synctv-api HTTP/gRPC API
  • synctv-livestream RTMP/HLS/HTTP-FLV
  • synctv-cluster 集群协调
  • synctv-proxy 媒体代理和 slice cache
  • synctv-proto protobuf 定义
  • 文件夹helm
    • synctv Helm chart
  • docs Astro Starlight 文档站

推荐使用 Makefile 入口。make help 会列出所有开发目标。

Terminal window
make dev-up

make dev-up 启动 PostgreSQL 和 Redis,并等待服务就绪。需要完整媒体和认证依赖时:

Terminal window
make dev-stack

make dev-stack 会启动 PostgreSQL、Redis、OpenList、Emby、Jellyfin、RustFS 和 Casdoor,并初始化 Casdoor database、RustFS bucket、OpenList 本地媒体目录、Emby/Jellyfin 管理账号和本地媒体库。常用端口:

服务地址默认账号
SyncTVhttp://127.0.0.1:8080root / LocalDevRootPass2026!
PostgreSQL127.0.0.1:5432synctv / synctv
Redis127.0.0.1:6379无密码
OpenListhttp://127.0.0.1:5244admin / synctv-openlist
Embyhttp://127.0.0.1:8096MyEmbyUser / synctv-emby
Jellyfinhttp://127.0.0.1:8097root / synctv-jellyfin
RustFShttp://127.0.0.1:9000rustfsadmin / rustfsadmin
RustFS Consolehttp://127.0.0.1:9001rustfsadmin / rustfsadmin
Casdoorhttp://127.0.0.1:8000admin / 123

停止容器但保留 volume:

Terminal window
make dev-down

清理容器和 volume:

Terminal window
make dev-clean

开发 Compose 只启动本地依赖服务,SyncTV 后端由宿主机 cargo run 启动。

Casdoor/OAuth2 provider 仍然通过 runtime settings 配置。启动 Casdoor 后,在 Casdoor 控制台创建应用,再用 synctv settings update oauth2 写入 oauth2.providers

Makefile 已经内置本机运行需要的环境变量:

Terminal window
make dev-serve

这个目标会先启动 PostgreSQL 和 Redis,然后用本机 cargo run 启动 SyncTV。需要完整依赖时,先运行 make dev-stack

后台运行使用同一套开发配置:

Terminal window
make dev-start
make dev-stop

make dev-start 会构建 target/debug/synctv、写入 .dev-data/run/synctv.pid,并等待 management socket 和 HTTP readiness。make dev-smoke 也通过这个入口启动 SyncTV。

手动流程:

  1. 确认依赖服务已启动:

    Terminal window
    make dev-up
  2. 为当前 shell 导出本机开发配置:

    Terminal window
    export SYNCTV_DATABASE_URL="postgresql://synctv:synctv@localhost:5432/synctv"
    export SYNCTV_REDIS_URL="redis://localhost:6379"
    export SYNCTV_JWT_SECRET="local-compose-jwt-secret-not-for-production-2026"
    export SYNCTV_CLUSTER_SECRET="local-compose-cluster-secret-2026"
    export SYNCTV_SECURITY_CREDENTIAL_ENCRYPTION_KEY="222102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
    export SYNCTV_SECURITY_OPAQUE_SERVER_SETUP_SECRET="local-compose-opaque-server-setup-secret-not-for-production-2026"
    export SYNCTV_BOOTSTRAP_CREATE_ROOT_USER="true"
    export SYNCTV_BOOTSTRAP_ROOT_PASSWORD="LocalDevRootPass2026!"
  3. 校验配置:

    Terminal window
    cargo run -p synctv --bin synctv -- config validate
  4. 启动服务:

    Terminal window
    cargo run -p synctv --bin synctv -- serve

导出上述环境变量后,也可以直接运行:

Terminal window
cargo run -p synctv --bin synctv -- serve

使用指定配置文件:

Terminal window
cargo run -p synctv --bin synctv -- serve --config synctv.yaml

只验证配置、不真正启动:

Terminal window
cargo run -p synctv --bin synctv -- serve --config synctv.yaml --dry-run

开发时修改配置结构后,先跑:

Terminal window
cargo run -p synctv --bin synctv -- config --config synctv.yaml validate

查看最终合并后的配置,secret 会被隐藏:

Terminal window
cargo run -p synctv --bin synctv -- config --config synctv.yaml show
cargo run -p synctv --bin synctv -- config --config synctv.yaml show --output json

配置来源优先级和环境变量规则见 配置文件如何工作

服务启动阶段会自动执行 embedded SQLx migrations。需要在不启动服务的情况下预检数据库状态时,可以单独执行:

Terminal window
cargo run -p synctv --bin synctv -- db migrate

检查数据库连接和迁移状态:

Terminal window
cargo run -p synctv --bin synctv -- db status

开发中如果数据库状态异常,优先检查:

  • SYNCTV_DATABASE_URLdatabase.url
  • PostgreSQL 容器是否健康。
  • migration 文件是否与代码期望一致。
  • 当前分支是否有未应用的 schema 变更。

迁移只负责持久化结构和稳定的数据完整性。数据库适合表达主键、外键、必要存储列、查询索引、唯一索引,以及很少随产品策略变化的物理约束。

不要把易变业务策略写进 SQL 约束。业务枚举值列表、审核状态、房间/成员角色、Provider 类型、权限规则、runtime settings 白名单、播放限制、房间策略、封禁/审核流程等产品级校验应放在领域层或服务层,用类型和测试约束行为。statusrolesignup_methodmessage_type、审核状态等枚举式字段入库应使用数字码(通常 SMALLINT 足够),不要用字符串或数据库 enum 类型保存。

如果直接写 SQL 可能制造业务非法状态,优先收紧服务写路径、增加一致性巡检或修复工具。

UNIQUE 可以用于稳定身份或几乎不会变化的唯一性不变量,尤其是需要数据库原子性时,例如用户名、邮箱、Provider 实例名、OAuth 账号身份、幂等键,以及“某个稳定作用域只能有一条当前有效记录”这类模式。不要把可能在普通产品迭代中被放宽、改作用域或重新解释的策略写成 UNIQUE。只有当某条规则独立于业务策略、确实是长期存储不变量时,才把它下沉到数据库。

面向用户展示的标签和显示名,例如房间名,默认属于产品策略,除非它们被明确设计成稳定身份标识。需要并发安全时,在服务层用事务锁或其他协调机制保证行为。

CI 等价的非 ignored 测试:

Terminal window
cargo nextest run --workspace --locked --run-ignored default --nff

文档测试:

Terminal window
cargo test --workspace --doc --locked

需要 Docker/PostgreSQL/Redis 的 ignored 测试:

Terminal window
cargo nextest run --workspace --locked --run-ignored only --nff

只跑某个 crate:

Terminal window
cargo nextest run -p synctv-api --locked --run-ignored default --nff

只跑某个测试:

Terminal window
cargo nextest run -p synctv-api test_name --locked --run-ignored default --nff

格式检查:

Terminal window
cargo fmt --all --check

Clippy:

Terminal window
cargo clippy --workspace --all-targets --locked -- -D warnings

不要对整个 workspace 使用 --all-features:部分 feature 组合是刻意互斥的, 例如 mimalloc/jemalloctls-aws-lc/tls-ring。非默认构建应使用显式 feature 组合检查。TLS 的约定是:tls-aws-lc / tls-ring 选择 rustls crypto provider,tls-webpki-roots / tls-native-roots 选择信任根来源;这个约定会在上游 crate 暴露对应开关的地方传播。少数依赖有自己的限制:SQLx 0.8 的 native roots 只能通过 ring 后端启用,reqwest 0.13 使用 platform verifier;基础邮件 TLS 保留 webpki roots,因为 lettre 编译 rustls 时要求至少启用一个 verifier/root feature。 修改 TLS 相关代码时至少检查 provider 与 root 的四个组合:

Terminal window
cargo check -p synctv --no-default-features --locked
cargo check -p synctv --no-default-features --features "tls-aws-lc,tls-webpki-roots" --locked
cargo check -p synctv --no-default-features --features "tls-aws-lc,tls-native-roots" --locked
cargo check -p synctv --no-default-features --features "tls-ring,tls-webpki-roots" --locked
cargo check -p synctv --no-default-features --features "tls-ring,tls-native-roots" --locked
cargo check -p synctv --no-default-features --features "k8s,mimalloc,tls-aws-lc,tls-webpki-roots,tls-native-roots" --locked

如果修改了特定功能,优先跑对应的聚焦测试,再跑更大的测试集。编译通过只是最低检查。

修改 Provider、播放 URL 签名、proxy、manifest、字幕、danmaku、thumbnail、RTMP、live proxy、播放后台任务或资源生命周期时,需要在单元测试之外做真实服务验证:

  • 使用构建出的 synctv 二进制启动服务,覆盖真实启动、配置、migration 和路由;
  • 使用 synctv CLI 创建用户、房间、Provider、媒体、动态播放列表、RTMP publish key 和播放状态;
  • 使用真实 WebSocket 让房间进入 active 状态;
  • 使用 curl 请求每个返回的 direct/proxy URL、manifest、indexed segment、字幕、danmaku、thumbnail 和 Range URL;
  • 覆盖 Direct URL、Alist、Emby、Jellyfin、Bilibili 匿名播放、RTMP、live proxy、HLS、FLV、cache MISS/HIT、URL 过期和资源清理;
  • 覆盖动态 playlist 的路径返回、媒体解析、播放、切换、封面/thumbnail 路由和自动切换后的 target 变化;
  • RTMP/live proxy 使用真实上游推流,验证 stream info、HLS playlist/segment、FLV、断开后的 idle cleanup;
  • CLI 缺少某个工作流时,先补 synctv CLI,再把该工作流纳入手动 E2E。

Provider 返回的 PlaybackResult 是验证清单。每个 mode 和辅助 URL 都要实际请求,包含动态 playlist 解析出的媒体项。播放后台任务使用当前进程 ConnectionRuntime::active_room_ids(),验证时通过真实 WebSocket 驱动 active room,避免用数据库写入替代连接生命周期。

数据库查询如果使用 SQLx macros,会在编译期检查 SQL,并把 metadata 缓存在 .sqlx/。修改 SQL、migration 或查询返回类型后需要刷新。

需要编译期校验的 repository 查询应继续使用 SQLx checked macros。更新 .sqlx 是正常开发流程,metadata 变更属于 SQL 改动的一部分。

播放后台任务相关查询还需要保留 room-scoped 过滤和当前 room_playback_progress.target_hash 绑定。修改这些 SQL 时,代码、.sqlx metadata 和 active-room E2E 证据一起更新。

刷新流程:

Terminal window
make dev-clean
make dev-up
local_database_url="postgresql://synctv:synctv@localhost:5432/synctv"
SYNCTV_DATABASE_URL="$local_database_url" \
cargo run -p synctv --bin synctv -- db migrate
DATABASE_URL="$local_database_url" \
cargo sqlx prepare --workspace
SQLX_OFFLINE=true cargo check --workspace --all-targets

内置 OpenAPI 文档由 openapi feature 启用。开发者获取方式见 OpenAPI 文档入口

常用检查:

Terminal window
cargo check --workspace --all-targets --features openapi

启动带 Swagger UI 的服务:

Terminal window
cargo run -p synctv --features openapi --bin synctv -- serve

文档站在 docs/ 目录,是独立的 Astro Starlight 项目。

首次安装依赖:

Terminal window
cd docs
npm install

本地预览:

Terminal window
cd docs
npm run dev

构建:

Terminal window
cd docs
npm run build

如果文档站部署在域名子路径下,构建时指定 SYNCTV_DOCS_BASE。如果需要正确生成 canonical URL 和 sitemap,同时指定 SYNCTV_DOCS_SITE

Terminal window
cd docs
SYNCTV_DOCS_SITE=https://example.com SYNCTV_DOCS_BASE=/synctv npm run build

SYNCTV_DOCS_BASE 只表示路径前缀,例如 /synctv/docs。部署在域名根路径时不需要设置。

构建输出在 docs/dist,它是生成产物,不需要提交。

CLI 定义在 synctv/src/cli/。修改命令或参数后至少检查:

Terminal window
cargo run -p synctv --bin synctv -- --help
cargo run -p synctv --bin synctv -- user --help
cargo run -p synctv --bin synctv -- provider --help

如果新增命令,也要更新 CLI 参考

Helm:

Terminal window
helm lint ./helm/synctv
helm template synctv ./helm/synctv
helm template synctv ./helm/synctv --set ingress.grpc.enabled=true

Compose:

Terminal window
docker compose -f docker-compose.dev.yml config
docker compose config

注意:渲染成功只说明 YAML 语法和模板基本可用,不代表业务配置安全。还要运行 SyncTV 配置校验或实际启动验证。