Collabos commited on
Commit
f503196
·
verified ·
1 Parent(s): eccdcb1

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +8 -191
README.md CHANGED
@@ -1,194 +1,11 @@
1
- # P2P Signal Server
2
-
3
- Real-time WebRTC signaling server for 10,000 concurrent users.
4
- Runs on **Hugging Face Spaces Free Tier** (Docker, port 7860).
5
-
6
- ---
7
-
8
- ## Architecture
9
-
10
- ```
11
- Client A ──WS──► HF Space (Signal Server)
12
- │
13
- ├─ Redis Bucket 1 (Presence) uid→socketId, online/offline
14
- ├─ Redis Bucket 2 (Msg Queue) offline_msgs:{uid} list
15
- ├─ MongoDB Atlas user profiles, friend lists
16
- └─ Supabase Storage media files (server sees 0 bytes)
17
-
18
- Client A ◄──────────────────────────────► Client B (WebRTC P2P after handshake)
19
- ◄── WS relay fallback if ICE fails ─────────►
20
- ```
21
-
22
- ---
23
-
24
- ## Quick Start
25
-
26
- ### 1. Clone & install
27
-
28
- ```bash
29
- git clone https://github.com/you/p2p-signal-server
30
- cd p2p-signal-server
31
- npm install
32
- cp .env.example .env
33
- # Fill in all values in .env
34
- npm run dev
35
- ```
36
-
37
- ### 2. Build & run (Docker)
38
-
39
- ```bash
40
- docker build -t p2p-signal .
41
- docker run --env-file .env -p 7860:7860 p2p-signal
42
- ```
43
-
44
  ---
45
-
46
- ## Required Secrets
47
-
48
- Add all of these to **HF Spaces → Settings → Repository Secrets**.
49
-
50
- | Variable | How to get it |
51
- |---|---|
52
- | `JWT_SECRET` | `node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"` |
53
- | `REDIS_PRESENCE_URL` | [Upstash](https://upstash.com) → Create Redis DB #1 → Copy Redis URL |
54
- | `REDIS_MESSAGE_URL` | Upstash → Create Redis DB **#2** (separate!) → Copy Redis URL |
55
- | `MONGO_URI` | [MongoDB Atlas](https://cloud.mongodb.com) → M0 Free → Connect → Driver URL |
56
- | `SUPABASE_URL` | [Supabase](https://supabase.com) → Project Settings → API → Project URL |
57
- | `SUPABASE_SERVICE_KEY` | Supabase → Project Settings → API → `service_role` key |
58
- | `SUPABASE_BUCKET` | Create a bucket named `media` in Supabase Storage, set to **public** |
59
- | `TURN_URL` | [metered.ca/tools/openrelay](https://www.metered.ca/tools/openrelay/) free TURN |
60
- | `TURN_USERNAME` | From the same TURN provider |
61
- | `TURN_CREDENTIAL` | From the same TURN provider |
62
- | `ALLOWED_ORIGINS` | Your frontend domain(s), comma-separated e.g. `https://myapp.vercel.app` |
63
-
64
- Optional (have defaults):
65
-
66
- | Variable | Default | Notes |
67
- |---|---|---|
68
- | `PORT` | `7860` | Must stay 7860 for HF Spaces |
69
- | `STUN_SERVERS` | Google STUN | Comma-separated stun: URIs |
70
- | `PRESENCE_TTL_S` | `60` | Redis TTL for online status |
71
- | `OFFLINE_MSG_TTL_S` | `604800` | 7 days — how long to hold queued msgs |
72
- | `HEARTBEAT_INTERVAL_MS` | `30000` | Client sends ping every 30s |
73
- | `MAX_FILE_SIZE_MB` | `99` | Max single file size |
74
- | `MAX_FILE_COUNT` | `10` | Max files per upload request |
75
-
76
  ---
77
 
78
- ## HF Spaces Deploy
79
-
80
- 1. Create a new Space → **Docker** SDK
81
- 2. Push this repo to the Space's git remote
82
- 3. Add all secrets in Space settings
83
- 4. The Space will auto-build via the Dockerfile
84
-
85
- Health check: `GET /health` → `{ status: 'ok', connections: N, ts: epoch }`
86
-
87
- ---
88
-
89
- ## WebSocket Protocol
90
-
91
- Connect: `wss://your-space.hf.space?token=<JWT>`
92
-
93
- ### Client → Server
94
-
95
- ```jsonc
96
- // Heartbeat (every 30s)
97
- { "type": "heartbeat", "payload": {} }
98
-
99
- // Send a text message
100
- { "type": "message", "payload": { "toUid": "bob", "type": "text", "content": "Hello" } }
101
-
102
- // Send a media message (after uploading to Supabase)
103
- { "type": "message", "payload": { "toUid": "bob", "type": "media", "content": "https://...", "mediaType": "image/jpeg" } }
104
-
105
- // Request signed upload URLs
106
- { "type": "get-upload-url", "requestId": "abc123",
107
- "payload": { "files": [{ "fileName": "photo.jpg", "mimeType": "image/jpeg", "sizeBytes": 1048576 }] } }
108
-
109
- // WebRTC offer
110
- { "type": "offer", "payload": { "toUid": "bob", "sdp": { ...RTCSessionDescription } } }
111
-
112
- // WebRTC answer
113
- { "type": "answer", "payload": { "toUid": "alice", "sdp": { ...RTCSessionDescription } } }
114
-
115
- // ICE candidate
116
- { "type": "ice-candidate", "payload": { "toUid": "bob", "candidate": { ...RTCIceCandidate } } }
117
-
118
- // WS relay fallback (when ICE fails)
119
- { "type": "relay", "payload": { "toUid": "bob", "data": { ...anything } } }
120
-
121
- // Friend actions
122
- { "type": "friend", "payload": { "action": "send-request", "targetUid": "bob" } }
123
- { "type": "friend", "payload": { "action": "accept", "targetUid": "alice" } }
124
- { "type": "friend", "payload": { "action": "reject", "targetUid": "alice" } }
125
- { "type": "friend", "payload": { "action": "remove", "targetUid": "bob" } }
126
- { "type": "friend", "payload": { "action": "list" } }
127
- { "type": "friend", "payload": { "action": "status", "targetUid": "bob" } }
128
- ```
129
-
130
- ### Server → Client
131
-
132
- ```jsonc
133
- { "type": "connected", "payload": { "uid": "...", "socketId": "..." } }
134
- { "type": "ice-servers", "payload": { "iceServers": [...] } }
135
- { "type": "offline-flush", "payload": { "messages": [...], "count": N } }
136
- { "type": "message", "payload": { "fromUid": "...", "content": "...", ... } }
137
- { "type": "peer-online", "payload": { "uid": "bob" } }
138
- { "type": "peer-offline", "payload": { "uid": "bob" } }
139
- { "type": "upload-url", "payload": { "urls": [{ "signedUrl", "objectPath", "publicUrl" }] } }
140
- { "type": "offer", "payload": { "fromUid": "...", "sdp": {...} } }
141
- { "type": "answer", "payload": { "fromUid": "...", "sdp": {...} } }
142
- { "type": "ice-candidate", "payload": { "fromUid": "...", "candidate": {...} } }
143
- { "type": "relay", "payload": { "fromUid": "...", "data": {...} } }
144
- { "type": "error", "payload": { "message": "..." } }
145
- ```
146
-
147
- ---
148
-
149
- ## File Upload Flow
150
-
151
- ```
152
- 1. Client → server: { type: 'get-upload-url', payload: { files: [...] } }
153
- 2. Server → Supabase: createSignedUploadUrl (no bytes transferred)
154
- 3. Server → client: { type: 'upload-url', payload: { urls: [...] } }
155
- 4. Client → Supabase: PUT file directly (server sees 0 bytes, HF RAM unaffected)
156
- 5. Client → server: { type: 'message', payload: { type: 'media', content: publicUrl } }
157
- 6. Server → recipient: deliver or queue offline
158
- ```
159
-
160
- ---
161
-
162
- ## File Structure
163
-
164
- ```
165
- src/
166
- ├── index.ts # Entry point, HTTP+WS server
167
- ├── config.ts # All env vars, ICE server builder
168
- ├── db/
169
- │ └── mongo.ts # MongoDB connection, User + Message models
170
- ├── redis/
171
- │ ├── presenceClient.ts # Bucket 1: uid→socketId, online/offline
172
- │ └── messageClient.ts # Bucket 2: offline message queue
173
- ├── services/
174
- │ ├── connectionRegistry.ts # In-process socket map + zombie pruner
175
- │ ├── supabaseService.ts # Signed URL generation, file validation
176
- │ └── friendService.ts # Friend request/accept/remove logic
177
- ├── handlers/
178
- │ ├── connectionHandler.ts # WS connect/disconnect, message router
179
- │ ├── signalingHandler.ts # WebRTC SDP/ICE forwarding
180
- │ ├── messageHandler.ts # Text/media delivery + offline queue
181
- │ ├── fileHandler.ts # Upload URL generation
182
- │ └── friendHandler.ts # Friend CRUD over WS
183
- ├── middleware/
184
- │ └── rateLimiter.ts # Token bucket, 20 conn/IP/60s
185
- ├── models/
186
- │ └── friend.ts # FriendRequest mongoose model
187
- └── utils/
188
- ├── jwt.ts # Token verification (uid always from JWT)
189
- ├── logger.ts # Structured JSON logger
190
- └── protocol.ts # WS message types + safe serialization
191
-
192
- client-reference/
193
- └── client.ts # Browser client (copy into your frontend)
194
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Chatapi
3
+ emoji: 🏆
4
+ colorFrom: red
5
+ colorTo: purple
6
+ sdk: docker
7
+ pinned: false
8
+ short_description: A simple chatting api
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  ---
10
 
11
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference