153 lines
6.4 KiB
Markdown
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).
|