251 lines
7.8 KiB
Markdown
251 lines
7.8 KiB
Markdown
# every.channel
|
|
|
|
A global, disaggregated mesh of relays that turns local ATSC antennas into a coherent, worldwide stream. The stack is Rust-first, MoQ-native, and designed for deterministic chunking so identical broadcasts yield identical data.
|
|
|
|
## Goals
|
|
|
|
- Free, global access to broadcast TV through user-run relays.
|
|
- Deterministic encoding and chunking to make availability a coordination problem.
|
|
- Clean layering: capture -> transcode -> MoQ publish -> relay -> client playback.
|
|
- Cross-platform clients: Tauri app, CLI, and a static web UI.
|
|
|
|
## Repository layout
|
|
|
|
- `crates/ec-core`: shared types and determinism profiles.
|
|
- `crates/ec-hdhomerun`: HDHomeRun discovery and lineup scaffolding.
|
|
- `crates/ec-linux-iptv`: Linux DVB ingest scaffolding.
|
|
- `crates/ec-iroh`: iroh transport scaffolding.
|
|
- `crates/ec-crypto`: stream key derivation helpers.
|
|
- `crates/ec-eth`: Ethereum-compatible protocol representations and commitments.
|
|
- `crates/ec-ts`: MPEG-TS timing and table parsing.
|
|
- `crates/ec-chopper`: deterministic ffmpeg chunking scaffolding.
|
|
- `crates/ec-moq`: MoQ data model and relay scaffolding.
|
|
- `crates/ec-node`: node runner (ingest + publish).
|
|
- `crates/ec-cli`: CLI for discovery and node control.
|
|
- `apps/tauri`: desktop client shell.
|
|
- `apps/tauri/ui`: Dioxus web frontend embedded in the Tauri app.
|
|
- `docs/USAGE.md`: runbook for viewer and ingest pipelines.
|
|
- `docs/IROH_EXAMPLES.md`: summary of iroh repos/examples used for design.
|
|
- `docs/`: architecture, roadmap, and MoQ notes.
|
|
- `contracts/`: Solidity contracts for compact private-chain settlement rails.
|
|
|
|
## Development
|
|
|
|
Nix:
|
|
|
|
```sh
|
|
nix develop
|
|
```
|
|
|
|
Rust:
|
|
|
|
```sh
|
|
cargo build
|
|
```
|
|
|
|
Runbook:
|
|
|
|
```sh
|
|
cat docs/USAGE.md
|
|
```
|
|
|
|
Git hosting topology:
|
|
|
|
```sh
|
|
cat docs/GIT_HOSTING.md
|
|
```
|
|
|
|
Sovereign forge deploy:
|
|
|
|
```sh
|
|
cat docs/DEPLOY_ECP_FORGE.md
|
|
```
|
|
|
|
OP Stack `ecp-forge` runbook:
|
|
|
|
```sh
|
|
cat docs/OP_STACK_ECP_FORGE.md
|
|
```
|
|
|
|
NUC PXE rollout (UniFi-only or ProxyDHCP):
|
|
|
|
```sh
|
|
cat docs/NUC_UNIFI_NETBOOT.md
|
|
```
|
|
|
|
## WebTransport Watch (MoQ)
|
|
|
|
Publish (node -> Cloudflare relay):
|
|
|
|
```sh
|
|
cargo run -p ec-node -- wt-publish \
|
|
--url https://cdn.moq.dev/anon \
|
|
--name la-nbc \
|
|
--input http://<hdhr-host>/auto/v4.1 \
|
|
--control-announce \
|
|
--control-endpoint-addr-out /tmp/la-nbc-control-endpoint.json
|
|
```
|
|
|
|
`wt-publish` defaults to `--passthrough=true` so relay and archive retain exact CMAF fragment bytes.
|
|
|
|
Watch (web):
|
|
|
|
```txt
|
|
https://every.channel/watch?url=https%3A%2F%2Fcdn.moq.dev%2Fanon&name=la-nbc
|
|
```
|
|
|
|
Archive (relay -> CAS objects + JSONL manifests):
|
|
|
|
```sh
|
|
cargo run -p ec-node -- wt-archive \
|
|
--url https://cdn.moq.dev/anon \
|
|
--name la-nbc \
|
|
--output-dir /tank/every-channel/archive \
|
|
--manifest-dir /var/lib/every-channel/manifests
|
|
```
|
|
|
|
Replay server (archive -> HLS DVR endpoints):
|
|
|
|
```sh
|
|
cargo run -p ec-node -- wt-archive-serve \
|
|
--output-dir /tank/every-channel/archive \
|
|
--manifest-dir /var/lib/every-channel/manifests \
|
|
--listen 0.0.0.0:7788
|
|
```
|
|
|
|
Control protocol (iroh gossip, relay + direct transport discovery):
|
|
|
|
```sh
|
|
# Listener (on node A)
|
|
cargo run -p ec-node -- control-listen --gossip-peer <node-b-endpoint-addr-json>
|
|
|
|
# Announcer (on node B)
|
|
cargo run -p ec-node -- control-announce \
|
|
--stream-id la-nbc \
|
|
--relay-url https://cdn.moq.dev/anon \
|
|
--relay-broadcast la-nbc \
|
|
--gossip-peer <node-a-endpoint-addr-json>
|
|
|
|
# Resolver (consumer picks best announced path)
|
|
cargo run -p ec-node -- control-resolve \
|
|
--stream-id la-nbc \
|
|
--prefer direct-first \
|
|
--gossip-peer <node-a-endpoint-addr-json>
|
|
|
|
# Bridge iroh control announcements to every.channel public web list
|
|
EVERY_CHANNEL_WEB_UPSERT_TOKEN=<token> \
|
|
cargo run -p ec-node -- control-bridge-web \
|
|
--directory-url https://every.channel \
|
|
--gossip-peer <node-a-endpoint-addr-json>
|
|
```
|
|
|
|
`wt-publish`, `control-announce`, `control-listen`, `control-resolve`, and `control-bridge-web` print both
|
|
`control endpoint id` and `control endpoint addr` on startup. Use the `endpoint addr` JSON for
|
|
`--gossip-peer` when bootstrapping.
|
|
|
|
Default discovery identity:
|
|
|
|
- If you pass `--stream-id`, that exact value is announced.
|
|
- If you do not pass `--stream-id`, `ec-node` now prefers a broadcast-scoped ID when the selected
|
|
channel exposes usable broadcast metadata. HDHomeRun sources also probe early TS packets to fill
|
|
missing `tsid` / `program_number`, and raw TS inputs can derive identity directly from PAT data.
|
|
- ATSC PSIP parsing now covers `MGT`, `TVCT/CVCT`, `STT`, `RRT`, `EIT`, and `ETT`. `EIT` and `ETT`
|
|
are accepted on the PIDs advertised by `MGT`, not only on the base PSIP PID `0x1FFB`.
|
|
- Discovery identity currently consumes `PAT` plus `VCT` data. `RRT`, `EIT`, `ETT`, and full `STT`
|
|
parsing are available for inspection and future policy, but they do not currently change the
|
|
default dedupe key beyond the existing broadcast identity fields.
|
|
- PAT-derived promotion is intentionally conservative: only single-program streams are promoted. If
|
|
the probe sees multiple non-zero programs, `ec-node` does not guess and keeps the stream
|
|
source-scoped.
|
|
- Sources without usable broadcast metadata still fall back to source-scoped IDs.
|
|
|
|
Ethereum rails:
|
|
|
|
- `ec-node` keeps BLAKE3 `manifest_id`s and `merkle+blake3` object proofs on the wire, and also
|
|
emits Ethereum-compatible ABI commitments for settlement.
|
|
- Manifests can now carry both local Ed25519 signatures and optional secp256k1 EIP-712 signatures
|
|
over `ManifestBody`. Set `EVERY_CHANNEL_MANIFEST_SIGNING_KEY` for the local signer and
|
|
`EVERY_CHANNEL_ETH_MANIFEST_SIGNING_KEY` for the Ethereum-native signer.
|
|
- Stream descriptors and iroh control announcements now carry Keccak commitments so broadcast
|
|
identity, discovery, and manifest settlement share one vocabulary.
|
|
- The new `contracts/EveryChannelRail.sol` contract is intentionally storage-light: it stores only
|
|
latest commitment pointers, while full manifests and media stay off-chain on iroh/relays/archive.
|
|
- Observation consensus now has dedicated Solidity surfaces:
|
|
`contracts/EveryChannelWitnessRegistry.sol` and
|
|
`contracts/EveryChannelObservationLedger.sol`.
|
|
- `scripts/op-stack/anvil-reality-smoke.sh` validates the observation rail against real archive
|
|
data pulled from `ecp-forge`, not only synthetic fixtures.
|
|
- `nix/modules/ec-op-stack.nix` and `docs/OP_STACK_ECP_FORGE.md` define the repo-owned OP Stack
|
|
operator path for `ecp-forge`.
|
|
- The dev shell now includes `forge`, `cast`, `anvil`, and `solc`, and the repo ships a
|
|
top-level `foundry.toml`.
|
|
|
|
Real-capture PSIP checks:
|
|
|
|
```sh
|
|
git clone --depth 1 https://github.com/tsduck/tsduck-test /tmp/tsduck-test
|
|
EC_REAL_ATSC_SAMPLE=/tmp/tsduck-test/input/test-040.ts \
|
|
cargo test -p ec-ts real_atsc_sample_matches_known_psip_shape -- --ignored --nocapture
|
|
EC_REAL_RRT_SAMPLE=/tmp/tsduck-test/input/test-052.ts \
|
|
cargo test -p ec-ts real_rrt_sample_matches_known_reference -- --ignored --nocapture
|
|
```
|
|
|
|
Ethereum commitment checks:
|
|
|
|
```sh
|
|
cargo test -p ec-eth -p ec-node -- --nocapture
|
|
nix develop -c bash -lc 'which forge cast anvil solc && solc --bin contracts/EveryChannelRail.sol >/dev/null'
|
|
```
|
|
|
|
Observation rail / OP Stack checks:
|
|
|
|
```sh
|
|
nix shell .#foundry .#solc -c forge test -vv
|
|
nix shell .#foundry .#solc nixpkgs#jq nixpkgs#openssh nixpkgs#curl -c ./scripts/op-stack/anvil-reality-smoke.sh
|
|
```
|
|
|
|
Coverage:
|
|
|
|
```sh
|
|
./scripts/coverage.sh
|
|
```
|
|
|
|
Build static web:
|
|
|
|
```sh
|
|
./scripts/build-web.sh
|
|
```
|
|
|
|
Deploy to Cloudflare Workers (static site):
|
|
|
|
```sh
|
|
./scripts/deploy-workers.sh
|
|
```
|
|
|
|
Remote website E2E (local publisher -> deployed every.channel web):
|
|
|
|
```sh
|
|
./scripts/e2e-remote-website-direct.sh
|
|
```
|
|
|
|
Remote website E2E (public list/signaling -> website selects stream automatically):
|
|
|
|
```sh
|
|
./scripts/e2e-remote-website-directory.sh
|
|
```
|
|
|
|
Tauri viewer (Dioxus + Trunk):
|
|
|
|
```sh
|
|
cd apps/tauri/ui
|
|
trunk serve --port 1420 --public-url /
|
|
```
|
|
|
|
```sh
|
|
cd ../
|
|
cargo run
|
|
```
|
|
|
|
## Status
|
|
|
|
This repository is intentionally minimal. It captures the initial architecture and scaffold for a MoQ-first network and will expand as proposals are accepted.
|