initial commit
This commit is contained in:
		
						commit
						e6a8e4795a
					
				
							
								
								
									
										34
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| # dependencies (bun install) | ||||
| node_modules | ||||
| 
 | ||||
| # output | ||||
| out | ||||
| dist | ||||
| *.tgz | ||||
| 
 | ||||
| # code coverage | ||||
| coverage | ||||
| *.lcov | ||||
| 
 | ||||
| # logs | ||||
| logs | ||||
| _.log | ||||
| report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json | ||||
| 
 | ||||
| # dotenv environment variable files | ||||
| .env | ||||
| .env.development.local | ||||
| .env.test.local | ||||
| .env.production.local | ||||
| .env.local | ||||
| 
 | ||||
| # caches | ||||
| .eslintcache | ||||
| .cache | ||||
| *.tsbuildinfo | ||||
| 
 | ||||
| # IntelliJ based IDEs | ||||
| .idea | ||||
| 
 | ||||
| # Finder (MacOS) folder config | ||||
| .DS_Store | ||||
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| # arca-signaling | ||||
| 
 | ||||
| To install dependencies: | ||||
| 
 | ||||
| ```bash | ||||
| bun install | ||||
| ``` | ||||
| 
 | ||||
| To run: | ||||
| 
 | ||||
| ```bash | ||||
| bun run index.ts | ||||
| ``` | ||||
| 
 | ||||
| This project was created using `bun init` in bun v1.2.12. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. | ||||
							
								
								
									
										36
									
								
								bun.lock
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								bun.lock
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| { | ||||
|   "lockfileVersion": 1, | ||||
|   "workspaces": { | ||||
|     "": { | ||||
|       "name": "arca-signaling", | ||||
|       "dependencies": { | ||||
|         "ulid": "^3.0.0", | ||||
|         "ws": "^8.18.2", | ||||
|       }, | ||||
|       "devDependencies": { | ||||
|         "@types/bun": "latest", | ||||
|         "@types/ws": "^8.18.1", | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "typescript": "^5", | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   "packages": { | ||||
|     "@types/bun": ["@types/bun@1.2.12", "", { "dependencies": { "bun-types": "1.2.12" } }, "sha512-lY/GQTXDGsolT/TiH72p1tuyUORuRrdV7VwOTOjDOt8uTBJQOJc5zz3ufwwDl0VBaoxotSk4LdP0hhjLJ6ypIQ=="], | ||||
| 
 | ||||
|     "@types/node": ["@types/node@22.15.17", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw=="], | ||||
| 
 | ||||
|     "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], | ||||
| 
 | ||||
|     "bun-types": ["bun-types@1.2.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-tvWMx5vPqbRXgE8WUZI94iS1xAYs8bkqESR9cxBB1Wi+urvfTrF1uzuDgBHFAdO0+d2lmsbG3HmeKMvUyj6pWA=="], | ||||
| 
 | ||||
|     "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], | ||||
| 
 | ||||
|     "ulid": ["ulid@3.0.0", "", { "bin": { "ulid": "dist/cli.js" } }, "sha512-yvZYdXInnJve6LdlPIuYmURdS2NP41ZoF4QW7SXwbUKYt53+0eDAySO+rGSvM2O/ciuB/G+8N7GQrZ1mCJpuqw=="], | ||||
| 
 | ||||
|     "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], | ||||
| 
 | ||||
|     "ws": ["ws@8.18.2", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ=="], | ||||
|   } | ||||
| } | ||||
							
								
								
									
										95
									
								
								index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | ||||
| import { WebSocket, WebSocketServer } from 'ws'; | ||||
| import { ulid } from 'ulid'; | ||||
| 
 | ||||
| const wss = new WebSocketServer({ port: 8080 }); | ||||
| 
 | ||||
| const rooms = new Map<string, Set<string>>(); | ||||
| const sockets = new Map<string, WebSocket>(); | ||||
| 
 | ||||
| wss.on('connection', (ws) => { | ||||
|     let peerId = ulid(); | ||||
| 
 | ||||
|     const join = (room: string) => { | ||||
|         if (!rooms.has(room)) { | ||||
|             rooms.set(room, new Set([peerId])); | ||||
|         } else { | ||||
|             rooms.get(room)!.add(peerId); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     const unjoinAll = () => { | ||||
|         rooms.entries().forEach(([room, peers]) => { | ||||
|             peers.delete(peerId); | ||||
|             if (!peers.size) rooms.delete(room); | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     ws.on('message', (message) => { | ||||
|         try { | ||||
|             const text = message.toString('utf8'); | ||||
|             const data = JSON.parse(text); | ||||
| 
 | ||||
|             if (data.type === 'self') { | ||||
|                 ws.send(JSON.stringify({ | ||||
|                     type: 'self', | ||||
|                     id: peerId.toString(), | ||||
|                 })); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (data.type === 'join' && typeof data.room === 'string') { | ||||
|                 unjoinAll(); | ||||
|                 join(data.room); | ||||
| 
 | ||||
|                 const peers = rooms.get(data.room) ?? []; | ||||
|                 peers.forEach((peer) => { | ||||
|                     sockets.get(peer)!.send(JSON.stringify({ | ||||
|                         type: 'peers', | ||||
|                         peers: peers, | ||||
|                     })); | ||||
|                 }); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (data.type === 'offer' && typeof data.peer === 'string' && typeof data.offer === 'object') { | ||||
|                 const otherWS = sockets.get(data.peer); | ||||
|                 if (!otherWS) return; | ||||
| 
 | ||||
|                 otherWS.send(JSON.stringify({ | ||||
|                     type: 'offer', | ||||
|                     from: peerId, | ||||
|                     offer: data.offer, | ||||
|                 })); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (data.type === 'accept' && typeof data.peer === 'string' && typeof data.counterOffer === 'object') { | ||||
|                 const otherWS = sockets.get(data.peer); | ||||
|                 if (!otherWS) return; | ||||
| 
 | ||||
|                 otherWS.send(JSON.stringify({ | ||||
|                     type: 'accept', | ||||
|                     from: peerId, | ||||
|                     counterOffer: data.counterOffer, | ||||
|                 })); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             throw 0; | ||||
|         } catch (e) { | ||||
|             ws.send(JSON.stringify({ | ||||
|                 type: 'error', | ||||
|                 message: 'Bad Request', | ||||
|             })); | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     ws.on('close', () => { | ||||
|         unjoinAll(); | ||||
|         sockets.delete(peerId); | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										17
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| { | ||||
|   "name": "arca-signaling", | ||||
|   "module": "index.ts", | ||||
|   "type": "module", | ||||
|   "private": true, | ||||
|   "devDependencies": { | ||||
|     "@types/bun": "latest", | ||||
|     "@types/ws": "^8.18.1" | ||||
|   }, | ||||
|   "peerDependencies": { | ||||
|     "typescript": "^5" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "ulid": "^3.0.0", | ||||
|     "ws": "^8.18.2" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										28
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     // Environment setup & latest features | ||||
|     "lib": ["ESNext"], | ||||
|     "target": "ESNext", | ||||
|     "module": "ESNext", | ||||
|     "moduleDetection": "force", | ||||
|     "jsx": "react-jsx", | ||||
|     "allowJs": true, | ||||
| 
 | ||||
|     // Bundler mode | ||||
|     "moduleResolution": "bundler", | ||||
|     "allowImportingTsExtensions": true, | ||||
|     "verbatimModuleSyntax": true, | ||||
|     "noEmit": true, | ||||
| 
 | ||||
|     // Best practices | ||||
|     "strict": true, | ||||
|     "skipLibCheck": true, | ||||
|     "noFallthroughCasesInSwitch": true, | ||||
|     "noUncheckedIndexedAccess": true, | ||||
| 
 | ||||
|     // Some stricter flags (disabled by default) | ||||
|     "noUnusedLocals": false, | ||||
|     "noUnusedParameters": false, | ||||
|     "noPropertyAccessFromIndexSignature": false | ||||
|   } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user