|
| 1 | +# fast-rtc-swarm |
| 2 | + |
| 3 | +A full-mesh WebRTC swarm built on top of WebSockets & fast-rtc-peer |
| 4 | + |
| 5 | +## Installation |
| 6 | + |
| 7 | +`yarn add @mattkrick/fast-rtc-swarm` |
| 8 | + |
| 9 | +## What is it |
| 10 | + |
| 11 | +[fast-rtc-peer](https://github.com/mattkrick/fast-rtc-peer) offers a great API to connect 2 peers. |
| 12 | +If you'd like to connect more than 2 peers, you're on your own. |
| 13 | +That's why this exists. |
| 14 | +It uses a full mesh (vs. partial mesh) network so every client is connected to every other client. |
| 15 | +A full mesh is great for up to ~100 connections. |
| 16 | +After that, you'll probably want to move to a partial mesh & trade a little latency for memory |
| 17 | + |
| 18 | +## How's it different from webrtc-swarm? |
| 19 | + |
| 20 | +fast-rtc-swarm is different. |
| 21 | +- The signaling server doesn't have to be server sent events. It can be anything (reference implementation is websockets) |
| 22 | +- It doesn't bother the signaling server with a heartbeat. The swarm can give us that info. |
| 23 | +- It only connects to 1 signaling server (IMO multiple servers is a proxy problem, not a client problem) |
| 24 | +- No unauthenticated-by-default signaling server CLI, It's forcing you to implement your own in hopes you implement auth. |
| 25 | +- No multiplexing streams. If you need a new data channel, open another one natively, not with expensive streams. |
| 26 | +- It uses the fast-rtc protocol for the fastest connection possible |
| 27 | + |
| 28 | +## What makes it so fast? |
| 29 | + |
| 30 | +the fast-rtc normally completes a WebRTC handshake in only 2 round trips. |
| 31 | +Most other implementations take 3 (or even 4!) |
| 32 | +It does this by keeping a 1-length cache of offers and candidates. |
| 33 | +Think of it like "pay-it-forward". |
| 34 | +You pay for the coffee for the person behind you, so they buy the coffee of the person behind them. |
| 35 | + |
| 36 | +Here's how it works: |
| 37 | + |
| 38 | +Alice is the first peer to join the swarm: |
| 39 | +- She gives the server an OFFER that can be used by the next person to join |
| 40 | +- As CANDIDATES trickle in, she forwards those to the signaling server |
| 41 | +- If the OFFER has been accepted, the server forwards the CANDIDATE to them, else it stores it with her OFFER |
| 42 | +- When someone takes her OFFER, the server REQUESTS another from her |
| 43 | + |
| 44 | +When Bob joins the swarm: |
| 45 | +- He follows the same protocol as Alice |
| 46 | +- He takes all the unclaimed OFFERS and CANDIDATES on the server |
| 47 | +- On the client, Bob creates an ANSWER to each OFFER and forwards it to the signaling server |
| 48 | +- The signaling server forwards Bob's ANSWER to Alice |
| 49 | +- Alice uses Bob's ANSWER to initiate the connection |
| 50 | + |
| 51 | +That's it! See `server.js` for a reference implementation or an example below to see how to add it to your own server. |
| 52 | + |
| 53 | +## Usage |
| 54 | + |
| 55 | +```js |
| 56 | +// client |
| 57 | +import FastRTCSwarm from '@mattkrick/fast-rtc-swarm' |
| 58 | + |
| 59 | +const socket = new WebSocket('ws://localhost:3000'); |
| 60 | +socket.addEventListener('open', () => { |
| 61 | + const swarm = new FastRTCSwarm() |
| 62 | + // send the signal to the signaling server |
| 63 | + swarm.on('signal', (signal) => { |
| 64 | + socket.send(JSON.stringify(signal)) |
| 65 | + }) |
| 66 | + // when the signal come back, dispatch it to the swarm |
| 67 | + socket.addEventListener('message', (event) => { |
| 68 | + const payload = JSON.parse(event.data) |
| 69 | + swarm.dispatch(payload) |
| 70 | + }) |
| 71 | + // when the connection is open, say hi to your new peer |
| 72 | + swarm.on('dataOpen', (peer) => { |
| 73 | + console.log('data channel open!') |
| 74 | + peer.send('hi') |
| 75 | + }) |
| 76 | + // when your peer says hi, log it |
| 77 | + swarm.on('data', (data, peer) => { |
| 78 | + console.log('data received', data, peer) |
| 79 | + }) |
| 80 | +}) |
| 81 | + |
| 82 | + |
| 83 | +// server |
| 84 | +import handleOnMessage from '@mattkrick/fast-rtc-swarm/server' |
| 85 | + |
| 86 | +wss.on('connection', (ws) => { |
| 87 | + ws.on('message', (message) => { |
| 88 | + const payload = JSON.parse(message) |
| 89 | + // Check your perms here! |
| 90 | + if (handleOnMessage(wss.clients, ws, payload)) return |
| 91 | + // your other websocket handlers here |
| 92 | + }) |
| 93 | +}) |
| 94 | +``` |
| 95 | + |
| 96 | +## API |
| 97 | + |
| 98 | +Options: A superset of `RTCConfiguration`. |
| 99 | +To add a TURN server to the default list of ICE candidates, see [fast-rtc-peer](https://github.com/mattkrick/fast-rtc-peer). |
| 100 | +- `id`: An ID to assign to the peer, defaults to a v4 uuid |
| 101 | +- `wrtc`: pass in [node-webrtc](https://github.com/js-platform/node-webrtc) if using server side |
| 102 | + |
| 103 | +Methods on FastRTCSwarm |
| 104 | +- `dispatch(signal)`: receive an incoming signal from the signal server |
| 105 | +- `broadcast(message)`: send a string or buffer to all connected peers |
| 106 | +- `close()`: destroy all peer connections |
| 107 | + |
| 108 | +## Events |
| 109 | + |
| 110 | +- `swarm.on('dataOpen', (peer) => {})`: fired when a peer connects |
| 111 | +- `swarm.on('dataClose', (peer) => {})`: fired when a peer disconnects |
| 112 | +- `swarm.on('data', (data, peer) => {})`: fired when a peer sends data |
| 113 | +- `swarm.on('signal', (signal, peer) => {})`: fired when a peer creates an offer, ICE candidate, or answer. |
| 114 | + |
| 115 | +## License |
| 116 | + |
| 117 | +MIT |
0 commit comments