Toru docs

Docs / Architecture

Architecture

How Toru is laid out and what each service does.

Service map

Submit flow

  1. Client → POST /v1/torrents with magnet or URL.
  2. API checks own R2 availability cache → if hit, returns status=ready.
  3. Otherwise: cache-check across the user's connected debrid backends (StremThru fan-out).
  4. If user has Torrin connected, submit there before falling through to the shared pool.
  5. Shared cold-start cascade: Premiumize → Torrin → TorBox → Real-Debrid → AllDebrid (skipping rungs without configured tokens, and skipping shared Torrin if the user already has one). First acceptance wins.
  6. Job row inserted with external_id + external_source so the poller knows where to ask for status.

Stream resolver layers

  1. R2 cachefile.r2_key set → signed Worker URL (source: "r2").
  2. Externalfile.external_url set (Torrin / Premiumize folder link / TorBox requestdl) → URL returned verbatim, optionally proxy-wrapped (source: "external" | "mediaflow" | "stremthru-proxy").
  3. User debrid + proxy — StremThru GenerateLinkForUser wrapped by user's MediaFlow / StremThru proxy if opted in.
  4. Direct upstream — debrid link returned (source: "upstream").

Encryption

Two AES-256-GCM-encrypted columns, both keyed off the same TOKEN_ENCRYPTION_KEY env (chmod 600 on the host, never in repo):

Argon2id hash is also stored on api_keys for fast verify on every authenticated request. Rotation revokes the old key in the same transaction as minting the new one.

RLS posture

Every user-scoped table has Row-Level Security enabled with self-only SELECT/INSERT/UPDATE policies (user_id = auth.uid()). The Realtime publication on public.jobs respects these policies, so the dashboard's job channel only delivers rows the user owns.

Hosting

All Go services run on a single Azure VM behind Traefik (Let's Encrypt-managed certs). Cloudflare DDNS keeps the A/AAAA records in sync. Supabase is reached over IPv6 via a Cloudflare WARP container's network namespace (Supabase's free tier exposes Postgres only over IPv6 and the default Docker bridge is IPv4-only).

Deploy is one command: bash scripts/deploy.sh. It rsyncs the repo, ensures the parent compose includes Toru's apps, builds + restarts the service containers, and optionally brings up the status + docs containers based on env config.

Source: github.com/rrevanth/toru.