5.4 KiB
Rondevu Server
🌐 Topic-based peer discovery and WebRTC signaling
Scalable peer-to-peer connection establishment with topic-based discovery, stateless authentication, and complete WebRTC signaling.
Related repositories:
- @xtr-dev/rondevu-client - TypeScript client library (npm)
- @xtr-dev/rondevu-server - HTTP signaling server (npm, live)
- @xtr-dev/rondevu-demo - Interactive demo (live)
Features
- Topic-Based Discovery: Tag offers with topics (e.g., torrent infohashes) for efficient peer finding
- Stateless Authentication: AES-256-GCM encrypted credentials, no server-side sessions
- Protected Offers: Optional secret field for access-controlled peer connections
- Bloom Filters: Client-side peer exclusion for efficient discovery
- Multi-Offer Support: Create multiple offers per peer simultaneously
- Complete WebRTC Signaling: Offer/answer exchange and ICE candidate relay
- Dual Storage: SQLite (Node.js/Docker) and Cloudflare D1 (Workers) backends
Quick Start
Node.js:
npm install && npm start
Docker:
docker build -t rondevu . && docker run -p 3000:3000 -e STORAGE_PATH=:memory: rondevu
Cloudflare Workers:
npx wrangler deploy
API Endpoints
Public Endpoints
GET /
Returns server version and info
GET /health
Health check endpoint with version
POST /register
Register a new peer and receive credentials (peerId + secret)
Response:
{
"peerId": "f17c195f067255e357232e34cf0735d9",
"secret": "DdorTR8QgSn9yngn+4qqR8cs1aMijvX..."
}
GET /topics?limit=50&offset=0
List all topics with active peer counts (paginated)
Query Parameters:
limit(optional): Maximum number of topics to return (default: 50, max: 200)offset(optional): Number of topics to skip (default: 0)
Response:
{
"topics": [
{"topic": "movie-xyz", "activePeers": 42},
{"topic": "torrent-abc", "activePeers": 15}
],
"total": 123,
"limit": 50,
"offset": 0
}
GET /offers/by-topic/:topic?limit=50&bloom=...
Find offers by topic with optional bloom filter exclusion
Query Parameters:
limit(optional): Maximum offers to return (default: 50, max: 200)bloom(optional): Base64-encoded bloom filter to exclude known peers
Response:
{
"topic": "movie-xyz",
"offers": [
{
"id": "offer-id",
"peerId": "peer-id",
"sdp": "v=0...",
"topics": ["movie-xyz", "hd-content"],
"expiresAt": 1234567890,
"lastSeen": 1234567890,
"hasSecret": true // Indicates if secret is required to answer
}
],
"total": 42,
"returned": 10
}
Notes:
hasSecret: Boolean flag indicating whether a secret is required to answer this offer. The actual secret is never exposed in public endpoints.
GET /peers/:peerId/offers
View all offers from a specific peer
Authenticated Endpoints
All authenticated endpoints require Authorization: Bearer {peerId}:{secret} header.
POST /offers
Create one or more offers
Request:
{
"offers": [
{
"sdp": "v=0...",
"topics": ["movie-xyz", "hd-content"],
"ttl": 300000,
"secret": "my-secret-password" // Optional: protect offer (max 128 chars)
}
]
}
Notes:
secret(optional): Protect the offer with a secret. Answerers must provide the correct secret to connect.
GET /offers/mine
List all offers owned by authenticated peer
PUT /offers/:offerId/heartbeat
Update last_seen timestamp for an offer
DELETE /offers/:offerId
Delete a specific offer
POST /offers/:offerId/answer
Answer an offer (locks it to answerer)
Request:
{
"sdp": "v=0...",
"secret": "my-secret-password" // Required if offer is protected
}
Notes:
secret(optional): Required if the offer was created with a secret. Must match the offer's secret.
GET /offers/answers
Poll for answers to your offers
POST /offers/:offerId/ice-candidates
Post ICE candidates for an offer
Request:
{
"candidates": ["candidate:1 1 UDP..."]
}
GET /offers/:offerId/ice-candidates?since=1234567890
Get ICE candidates from the other peer
Configuration
Environment variables:
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Server port (Node.js/Docker) |
CORS_ORIGINS |
* |
Comma-separated allowed origins |
STORAGE_PATH |
./rondevu.db |
SQLite database path (use :memory: for in-memory) |
VERSION |
0.4.0 |
Server version (semver) |
AUTH_SECRET |
Random 32-byte hex | Secret key for credential encryption |
OFFER_DEFAULT_TTL |
300000 |
Default offer TTL in ms (5 minutes) |
OFFER_MIN_TTL |
60000 |
Minimum offer TTL in ms (1 minute) |
OFFER_MAX_TTL |
3600000 |
Maximum offer TTL in ms (1 hour) |
MAX_OFFERS_PER_REQUEST |
10 |
Maximum offers per create request |
MAX_TOPICS_PER_OFFER |
20 |
Maximum topics per offer |
License
MIT