Open signaling and tracking server for peer discovery in distributed P2P applications. Features: - REST API for WebRTC peer discovery and signaling - Origin-based session isolation - Multiple storage backends (SQLite, in-memory, Cloudflare KV) - Docker and Cloudflare Workers deployment support - Automatic session cleanup and expiration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
7.1 KiB
Rondevu
An open signaling and tracking server for peer discovery. Enables peers to find each other through a topic-based HTTP API with Origin isolation for organizing peer-to-peer applications.
Features
- 🚀 Fast & Lightweight - Built with Hono framework
- 📂 Topic-Based Organization - Group sessions by topic for easy peer discovery
- 🔒 Origin Isolation - Sessions are isolated by HTTP Origin header to group topics by domain
- 🏷️ Peer Identification - Info field prevents duplicate connections to same peer
- 🔌 Pluggable Storage - Storage interface supports SQLite and in-memory adapters
- 🐳 Docker Ready - Minimal Alpine-based Docker image
- ⏱️ Session Timeout - Configurable session expiration from initiation time
- 🔐 Type Safe - Written in TypeScript with full type definitions
Quick Start
Using Node.js
# Install dependencies
npm install
# Run in development mode
npm run dev
# Build and run in production
npm run build
npm start
Using Docker
# Build the image
docker build -t rondevu .
# Run with default settings (SQLite database)
docker run -p 3000:3000 rondevu
# Run with in-memory storage
docker run -p 3000:3000 -e STORAGE_TYPE=memory rondevu
# Run with custom timeout (10 minutes)
docker run -p 3000:3000 -e SESSION_TIMEOUT=600000 rondevu
Using Cloudflare Workers
# Install Wrangler CLI
npm install -g wrangler
# Login to Cloudflare
wrangler login
# Create KV namespace
wrangler kv:namespace create SESSIONS
# Update wrangler.toml with the KV namespace ID
# Deploy to Cloudflare's edge network
npx wrangler deploy
See DEPLOYMENT.md for detailed instructions.
Configuration
Configuration is done through environment variables:
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 3000 |
STORAGE_TYPE |
Storage backend: sqlite or memory |
sqlite |
STORAGE_PATH |
Path to SQLite database file | ./data.db |
SESSION_TIMEOUT |
Session timeout in milliseconds | 300000 |
CORS_ORIGINS |
Comma-separated list of allowed origins | * |
Example .env file
PORT=3000
STORAGE_TYPE=sqlite
STORAGE_PATH=./sessions.db
SESSION_TIMEOUT=300000
CORS_ORIGINS=https://example.com,https://app.example.com
API Documentation
See API.md for complete API documentation.
Quick Overview
List all active topics (with pagination):
curl -X GET http://localhost:3000/ \
-H "Origin: https://example.com"
# Returns: {"topics":[{"topic":"my-room","count":3}],"pagination":{...}}
Create an offer (announce yourself as available):
curl -X POST http://localhost:3000/my-room/offer \
-H "Content-Type: application/json" \
-H "Origin: https://example.com" \
-d '{"info":"peer-123","offer":"<SIGNALING_DATA>"}'
# Returns: {"code":"550e8400-e29b-41d4-a716-446655440000"}
List available peers in a topic:
curl -X GET http://localhost:3000/my-room/sessions \
-H "Origin: https://example.com"
# Returns: {"sessions":[...]}
Connect to a peer:
curl -X POST http://localhost:3000/answer \
-H "Content-Type: application/json" \
-H "Origin: https://example.com" \
-d '{"code":"550e8400-...","answer":"<SIGNALING_DATA>","side":"answerer"}'
# Returns: {"success":true}
Architecture
Storage Interface
The storage layer is abstracted through a simple interface, making it easy to implement custom storage backends:
interface Storage {
createSession(origin: string, topic: string, info: string, offer: string, expiresAt: number): Promise<string>;
listSessionsByTopic(origin: string, topic: string): Promise<Session[]>;
getSession(code: string, origin: string): Promise<Session | null>;
updateSession(code: string, origin: string, update: Partial<Session>): Promise<void>;
deleteSession(code: string): Promise<void>;
cleanup(): Promise<void>;
close(): Promise<void>;
}
Built-in Storage Adapters
SQLite Storage (sqlite.ts)
- For Node.js/Docker deployments
- Persistent file-based or in-memory
- Automatic session cleanup
- Simple and reliable
Cloudflare KV Storage (kv.ts)
- For Cloudflare Workers deployments
- Global edge storage
- Automatic TTL-based expiration
- Distributed and highly available
Custom Storage Adapters
You can implement your own storage adapter by implementing the Storage interface:
import { Storage, Session } from './storage/types';
export class CustomStorage implements Storage {
async createSession(offer: string, expiresAt: number): Promise<string> {
// Your implementation
}
// ... implement other methods
}
Development
Project Structure
rondevu/
├── src/
│ ├── index.ts # Node.js server entry point
│ ├── app.ts # Hono application
│ ├── config.ts # Configuration
│ └── storage/
│ ├── types.ts # Storage interface
│ ├── sqlite.ts # SQLite adapter
│ └── codeGenerator.ts # Code generation utility
├── Dockerfile # Docker build configuration
├── build.js # Build script
├── API.md # API documentation
└── README.md # This file
Building
# Build TypeScript
npm run build
# Run built version
npm start
Docker Build
# Build the image
docker build -t rondevu .
# Run with volume for persistent storage
docker run -p 3000:3000 -v $(pwd)/data:/app/data rondevu
How It Works
- Discover topics (optional): Call
GET /to see all active topics and peer counts - Peer A announces availability by posting to
/:topic/offerwith peer identifier and signaling data - Server generates a unique UUID code and stores the session (bucketed by Origin and topic)
- Peer B discovers available peers using
GET /:topic/sessions - Peer B filters out their own session using the info field to avoid self-connection
- Peer B selects a peer and posts their connection data to
POST /answerwith the session code - Both peers exchange signaling data through
POST /answerendpoint - Both peers poll for updates using
POST /pollto retrieve connection information - Sessions automatically expire after the configured timeout
This allows peers in distributed systems to discover each other without requiring a centralized registry, while maintaining isolation between different applications through Origin headers.
Origin Isolation
Sessions are isolated by the HTTP Origin header, ensuring that:
- Peers can only see sessions from their own origin
- Session codes cannot be accessed cross-origin
- Topics are organized by application domain
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.