torrent/CLAUDE.md

153 lines
6.4 KiB
Markdown

# CLAUDE.md — Torrent Faker
## Project Purpose
Torrent Faker is a fake BitTorrent seeder that announces upload stats to real trackers without transferring any actual data. It simulates realistic seeding behavior to satisfy tracker requirements.
## Tech Stack
| Layer | Technology |
|-----------|-------------------------------------|
| Runtime | Bun |
| Language | TypeScript (strict, ESNext) |
| HTTP | Hono 4.x |
| Config | YAML (`js-yaml`) + Zod validation |
| Linting | Biome |
| Frontend | Svelte 5 + Vite (in `ui/`) |
## Project Structure
```
src/
index.ts # Entry point: loads config, starts registry + HTTP server
cli/index.ts # CLI client (talks to running API)
config/Config.ts # Zod schema + config loader
config/config.default.yml # Default config values
api/
server.ts # Hono app, mounts routes, serves UI
SeederRegistry.ts # Central in-memory store for all FakeSeeder instances
response.ts # HTTP response helpers
routes/
torrents.ts # GET/POST/DELETE /api/torrents
status.ts # GET /api/status, GET /api/status/stream (SSE)
config.ts # GET/PATCH /api/config
core/
bencode/ # Bencode decoder + encoder
client/
ClientProfile.ts # Profile interface + peer ID generation
profiles/ # qbittorrent.ts, transmission.ts
seeder/
FakeSeeder.ts # Announce loop, lifecycle (started → running → stopped)
SpeedSimulator.ts # Gaussian noise + burst/stall events
torrent/TorrentFile.ts # Parses .torrent, extracts info hash + tracker list
tracker/
ITracker.ts # Tracker interface
HttpTracker.ts # HTTP/HTTPS tracker (BEP 3)
UdpTracker.ts # UDP tracker (BEP 15)
TrackerResponse.ts # Response types
config/config.yml # Runtime config (gitignored defaults)
torrents/ # Drop .torrent files here
ui/ # Svelte frontend (built to ui/dist/)
```
## TypeScript Path Aliases
```
@core/* → src/core/*
@api/* → src/api/*
@config/* → src/config/*
```
## Dev Commands
```bash
bun run dev # Start server (hot-reload)
bun run start # Start server (production)
bun run cli <cmd> # Run CLI against running server
bun test # Run tests
bun run lint # Biome check
bun run format # Biome format --write
bun run build:ui # Build Svelte UI to ui/dist/
bun run build # Full build (UI only for now)
```
## Architecture
```
SeederRegistry
└── FakeSeeder (one per torrent)
├── SpeedSimulator — random base rate, ±15% jitter, burst/stall
└── Tracker[]
├── HttpTracker (BEP 3)
└── UdpTracker (BEP 15)
```
- `SeederRegistry` is the single source of truth; routes call it, not FakeSeeder directly.
- `FakeSeeder` extends `EventEmitter`; emits `announce`, `stopped`, `stateChange`.
- `SeederRegistry` subscribes to seeder events and pushes SSE updates to connected clients.
- Announce lifecycle: first call sends `event=started`, subsequent calls send `event=` (empty), final call on removal sends `event=stopped`.
## Configuration
Runtime config file: `config/config.yml` (copied from `src/config/config.default.yml`).
| Field | Default | Description |
|---------------------------|-----------|------------------------------------------|
| `port` | 3000 | HTTP server port (UI + API) |
| `announcePort` | 6881 | Port reported to trackers |
| `minUploadRateBytesPerSec`| 524288 | Min simulated speed (512 KB/s) |
| `maxUploadRateBytesPerSec`| 2097152 | Max simulated speed (2 MB/s) |
| `clientProfile` | qbittorrent | Client to impersonate |
| `torrentsDir` | ./torrents | Directory for .torrent files |
| `autoLoad` | true | Load all torrents in dir on startup |
Config is Zod-validated at startup. `PATCH /api/config` persists changes back to `config.yml`.
## API Endpoints
| Method | Path | Description |
|--------|------------------------------|---------------------------------------|
| GET | `/api/torrents` | List all active torrents |
| POST | `/api/torrents` | Upload `.torrent` file (multipart) |
| GET | `/api/torrents/:hash` | Stats + announce history for one |
| DELETE | `/api/torrents/:hash` | Stop seeding and remove |
| GET | `/api/status` | Global stats snapshot |
| GET | `/api/status/stream` | SSE stream (stats, torrent, ping) |
| GET | `/api/config` | Current config |
| PATCH | `/api/config` | Update mutable config fields |
| GET | `/*` | Serve Svelte SPA from `ui/dist/` |
### SSE Event Types
- `stats` — global stats on every change
- `torrent` — per-torrent state update on announce/change
- `torrents` — full list on initial connection
- `ping` — keep-alive every 30s
## CLI
Requires a running server. Reads `TORRENT_FAKER_API` env var (default: `http://localhost:3000`).
```bash
bun run cli add <file.torrent> # Start fake-seeding
bun run cli list # List active torrents
bun run cli remove <hash> # Stop and remove (hash prefix OK)
bun run cli status # Global stats
```
## Client Profiles
| Profile | Peer ID prefix | User-Agent |
|---------------|----------------|-----------------------|
| `qbittorrent` | `-qB4520-` | `qBittorrent/4.5.2` |
| `transmission`| `-TR3000-` | `Transmission/3.00` |
Each seeder generates a unique 20-byte peer ID per session.
## Code Conventions
- Biome enforces formatting; run `bun run format` before committing.
- Zod schemas for all external input (config file, API request bodies).
- No ORM — binary protocols implemented manually (bencode, UDP packets).
- EventEmitter pattern for seeder → registry communication.
- SSE for live UI updates (no WebSockets, no polling).