├── .gitignore ├── .travis.yml ├── README.md ├── docs.json ├── docs ├── custom-handlers.md └── logging.md ├── examples ├── custom-handlers.js ├── express.js ├── handlers │ └── img.js ├── override-primus.js ├── simple-logging.js └── try-switchboard.js ├── index.js ├── loadtest ├── runner.js └── simple.js ├── package.json ├── server.js └── test ├── all.js ├── disconnect-quick.js ├── helpers ├── announce.js ├── cleanup.js ├── connect.js ├── server.js └── socket.js ├── peer-events.js ├── reset.js ├── room-changes.js ├── room-events.js ├── room-info.js ├── room-isolation.js ├── room-leave.js ├── room-reuse.js ├── signaller-durability.js └── to-messaging.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | - 0.12 5 | - 4.1 6 | - stable 7 | 8 | notifications: 9 | email: 10 | - damon.oehlman@gmail.com 11 | irc: "irc.freenode.org#rtc.io" 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rtc-switchboard 2 | 3 | This is an rtc.io signalling server (counterpart to 4 | [rtc-signaller](https://github.com/rtc-io/rtc-signaller)) uses websockets to 5 | communicate with signalling clients. It has been designed and built 6 | primarily as a _reference implementation_ for a signalling server and is 7 | not designed to be deployed at scale. 8 | 9 | 10 | [![NPM](https://nodei.co/npm/rtc-switchboard.png)](https://nodei.co/npm/rtc-switchboard/) 11 | 12 | [![unstable](https://img.shields.io/badge/stability-unstable-yellowgreen.svg)](https://github.com/dominictarr/stability#unstable) [![Build Status](https://api.travis-ci.org/rtc-io/rtc-switchboard.svg?branch=master)](https://travis-ci.org/rtc-io/rtc-switchboard) [![bitHound Score](https://www.bithound.io/github/rtc-io/rtc-switchboard/badges/score.svg)](https://www.bithound.io/github/rtc-io/rtc-switchboard) 13 | 14 | ## Try it out 15 | 16 | If you would like to use our test signalling server (no uptime guaranteed) then 17 | you can use [rtc-quickconnect](https://github.com/rtc-io/rtc-quickconnect) 18 | and take it for a spin: 19 | 20 | ```js 21 | var quickconnect = require('rtc-quickconnect'); 22 | 23 | quickconnect('//switchboard.rtc.io/', { room: 'switchboard-test' }) 24 | .createDataChannel('test') 25 | .once('channel:opened:test', function(peerId, dc) { 26 | dc.onmessage = function(evt) { 27 | console.log('received data: ', evt.data); 28 | }; 29 | 30 | dc.send('hello'); 31 | }); 32 | 33 | ``` 34 | 35 | Other examples are available in the [guidebook](http://guidebook.rtc.io) 36 | 37 | ## Usage: Standalone 38 | 39 | If you wish to use `rtc-switchboard` on its own to test signalling, 40 | then you can simply clone this repository, install dependencies and start 41 | the server: 42 | 43 | ``` 44 | git clone https://github.com/rtc-io/rtc-switchboard.git 45 | cd rtc-switchboard 46 | npm install && npm start 47 | ``` 48 | 49 | If you wish to run the server on a specific port, then set the `NODE_PORT` 50 | environment variable prior to execution: 51 | 52 | ``` 53 | NODE_PORT=8997 node server.js 54 | ``` 55 | 56 | ## Usage: API 57 | 58 | To create an application using switchboard signalling, see the following 59 | examples: 60 | 61 | ### Pure Node HTTP 62 | 63 | ```js 64 | var server = require('http').createServer(); 65 | var switchboard = require('rtc-switchboard/')(server, { servelib: true }); 66 | var port = parseInt(process.env.NODE_PORT || process.env.PORT || process.argv[2], 10) || 3000; 67 | var replify = require('replify'); 68 | 69 | server.on('request', function(req, res) { 70 | if (req.url === '/') { 71 | res.writeHead(302, { 72 | 'Location': 'https://github.com/rtc-io/rtc-switchboard' 73 | }); 74 | res.end('switchboard available from: https://github.com/rtc-io/rtc-switchboard'); 75 | } 76 | }); 77 | 78 | // start the server 79 | server.listen(port, function(err) { 80 | if (err) { 81 | return console.log('Encountered error starting server: ', err); 82 | } 83 | 84 | console.log('server running at http://localhost:' + port + '/'); 85 | }); 86 | 87 | // add the repl 88 | replify({ 89 | name: 'switchboard', 90 | app: switchboard, 91 | contexts: { 92 | server: server 93 | } 94 | }); 95 | 96 | switchboard.on('room:create', function(room) { 97 | console.log('room ' + room + ' created, now have ' + switchboard.rooms.length + ' active rooms'); 98 | }); 99 | 100 | switchboard.on('room:destroy', function(room) { 101 | console.log('room ' + room + ' destroyed, ' + switchboard.rooms.length + ' active rooms remain'); 102 | 103 | if (typeof gc == 'function') { 104 | console.log('gc'); 105 | gc(); 106 | } 107 | }); 108 | 109 | 110 | ``` 111 | 112 | ### Using Express 113 | 114 | ```js 115 | var express = require('express'); 116 | var app = express(); 117 | var server = require('http').Server(app); 118 | var port = process.env.PORT || 3000; 119 | 120 | // create the switchboard 121 | var switchboard = require('rtc-switchboard')(server); 122 | 123 | server.listen(port, function(err) { 124 | if (err) { 125 | return; 126 | } 127 | 128 | console.log('server listening on port: ' + port); 129 | }); 130 | 131 | ``` 132 | 133 | ## Usage: Docker 134 | 135 | If you are interested in deploying an instance of `rtc-switchboard` using 136 | [docker](https://www.docker.com/) then the following is a great place to 137 | start: 138 | 139 | 140 | 141 | ## Logging and Analytics using the `data` event 142 | 143 | Every message that flows through the switchboard (whether handled or not) can be logged through tapping into the `data` event. The example below demonstrates how this can be done with a node logging module like [bunyan](https://github.com/trentm/node-bunyan): 144 | 145 | ```js 146 | var express = require('express'); 147 | var app = express(); 148 | var server = require('http').Server(app); 149 | var port = process.env.PORT || 3000; 150 | var bunyan = require('bunyan'); 151 | var log = bunyan.createLogger({ name: 'rtc-switchboard' }); 152 | 153 | // create the switchboard 154 | var switchboard = require('rtc-switchboard')(server); 155 | 156 | server.listen(port, function(err) { 157 | if (err) { 158 | return; 159 | } 160 | 161 | console.log('server running at: http://localhost:' + port + '/'); 162 | }); 163 | 164 | switchboard.on('data', function(data, peerId, spark) { 165 | log.info({ peer: peerId }, 'received: ' + data); 166 | }); 167 | 168 | ``` 169 | 170 | As can be seen in the example above, the handlers of the `data` event can expect to receive three arguments to the handler function, as per the code snippet below: 171 | 172 | ```js 173 | switchboard.on('data', function(data, peerId, spark) { 174 | }); 175 | ``` 176 | 177 | The `data` is the raw data of that has been sent from the client, the `peerId` is the id of the peer sending the data (this will be `undefined` if it is a message received prior to an `/announce` command). 178 | 179 | 180 | ## License(s) 181 | 182 | ### Apache 2.0 183 | 184 | Copyright 2015 National ICT Australia Limited (NICTA) 185 | 186 | Licensed under the Apache License, Version 2.0 (the "License"); 187 | you may not use this file except in compliance with the License. 188 | You may obtain a copy of the License at 189 | 190 | http://www.apache.org/licenses/LICENSE-2.0 191 | 192 | Unless required by applicable law or agreed to in writing, software 193 | distributed under the License is distributed on an "AS IS" BASIS, 194 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 195 | See the License for the specific language governing permissions and 196 | limitations under the License. 197 | -------------------------------------------------------------------------------- /docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": { 3 | "holder": "National ICT Australia Limited (NICTA)" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /docs/custom-handlers.md: -------------------------------------------------------------------------------- 1 | ## Writing Custom Command Handlers 2 | 3 | When you initialize the switchboard, you are able to provide custom handlers specific commands that you want handled by the switchboard. Imagine instance, that we want our switchboard to do something clever when a sends an `/img` command. 4 | 5 | We would create our server to include the custom `img` command handler: 6 | 7 | <<< examples/custom-handlers.js 8 | 9 | And then we would write a small module for the handler: 10 | 11 | <<< examples/handlers/img.js 12 | 13 | __NOTE:__ This feature has not yet been implemented in the `3.x` release of rtc-switchboard. 14 | -------------------------------------------------------------------------------- /docs/logging.md: -------------------------------------------------------------------------------- 1 | ## Logging and Analytics using the `data` event 2 | 3 | Every message that flows through the switchboard (whether handled or not) can be logged through tapping into the `data` event. The example below demonstrates how this can be done with a node logging module like [bunyan](https://github.com/trentm/node-bunyan): 4 | 5 | <<< examples/simple-logging.js 6 | 7 | As can be seen in the example above, the handlers of the `data` event can expect to receive three arguments to the handler function, as per the code snippet below: 8 | 9 | ```js 10 | switchboard.on('data', function(data, peerId, spark) { 11 | }); 12 | ``` 13 | 14 | The `data` is the raw data of that has been sent from the client, the `peerId` is the id of the peer sending the data (this will be `undefined` if it is a message received prior to an `/announce` command). 15 | -------------------------------------------------------------------------------- /examples/custom-handlers.js: -------------------------------------------------------------------------------- 1 | var server = require('http').createServer(); 2 | var Primus = require('primus'); 3 | 4 | // create the signaller, providing our own primus instance (using engine.io) 5 | var switchboard = require('../')(server, { 6 | servelib: true, 7 | handlers: { 8 | img: require('./handlers/img') 9 | } 10 | }); 11 | 12 | // start the server 13 | server.listen(3000); -------------------------------------------------------------------------------- /examples/express.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | var server = require('http').Server(app); 4 | var port = process.env.PORT || 3000; 5 | 6 | // create the switchboard 7 | var switchboard = require('..')(server); 8 | 9 | server.listen(port, function(err) { 10 | if (err) { 11 | return; 12 | } 13 | 14 | console.log('server listening on port: ' + port); 15 | }); 16 | -------------------------------------------------------------------------------- /examples/handlers/img.js: -------------------------------------------------------------------------------- 1 | module.exports = function(mgr, spark, data, payload) { 2 | console.log('received an img command with payload: ', payload); 3 | }; -------------------------------------------------------------------------------- /examples/override-primus.js: -------------------------------------------------------------------------------- 1 | var server = require('http').createServer(); 2 | var Primus = require('primus'); 3 | 4 | // create the signaller, providing our own primus instance (using engine.io) 5 | var switchboard = require('../')(server, { 6 | primus: new Primus(server, { transformer: 'engine.io' }) 7 | }); 8 | 9 | // start the server 10 | server.listen(3000); -------------------------------------------------------------------------------- /examples/simple-logging.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | var server = require('http').Server(app); 4 | var port = process.env.PORT || 3000; 5 | var bunyan = require('bunyan'); 6 | var log = bunyan.createLogger({ name: 'rtc-switchboard' }); 7 | 8 | // create the switchboard 9 | var switchboard = require('..')(server); 10 | 11 | server.listen(port, function(err) { 12 | if (err) { 13 | return; 14 | } 15 | 16 | console.log('server running at: http://localhost:' + port + '/'); 17 | }); 18 | 19 | switchboard.on('data', function(data, peerId, spark) { 20 | log.info({ peer: peerId }, 'received: ' + data); 21 | }); 22 | -------------------------------------------------------------------------------- /examples/try-switchboard.js: -------------------------------------------------------------------------------- 1 | var quickconnect = require('rtc-quickconnect'); 2 | 3 | quickconnect('//switchboard.rtc.io/', { room: 'switchboard-test' }) 4 | .createDataChannel('test') 5 | .once('channel:opened:test', function(peerId, dc) { 6 | dc.onmessage = function(evt) { 7 | console.log('received data: ', evt.data); 8 | }; 9 | 10 | dc.send('hello'); 11 | }); 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 'use strict'; 3 | 4 | var debug = require('debug')('rtc-switchboard'); 5 | 6 | /** 7 | # rtc-switchboard 8 | 9 | This is an rtc.io signalling server (counterpart to 10 | [rtc-signaller](https://github.com/rtc-io/rtc-signaller)) uses websockets to 11 | communicate with signalling clients. It has been designed and built 12 | primarily as a _reference implementation_ for a signalling server and is 13 | not designed to be deployed at scale. 14 | 15 | ## Try it out 16 | 17 | If you would like to our test signalling server (no uptime guaranteed) then 18 | you can use [rtc-quickconnect](https://github.com/rtc-io/rtc-quickconnect) 19 | and take it for a spin: 20 | 21 | <<< examples/try-switchboard.js 22 | 23 | Other examples are available in the [guidebook](http://guidebook.rtc.io) 24 | 25 | ## Usage: Standalone 26 | 27 | If you wish to use `rtc-switchboard` on it's own to test signalling, 28 | then you can simply clone this repository, install dependencies and start 29 | the server: 30 | 31 | ``` 32 | git clone https://github.com/rtc-io/rtc-switchboard.git 33 | cd rtc-switchboard 34 | npm install && npm start 35 | ``` 36 | 37 | If you wish to run the server on a specific port, then set the `NODE_PORT` 38 | environment variable prior to execution: 39 | 40 | ``` 41 | NODE_PORT=8997 node server.js 42 | ``` 43 | 44 | ## Usage: API 45 | 46 | To create an application using switchboard signalling, see the following 47 | examples: 48 | 49 | ### Pure Node HTTP 50 | 51 | <<< server.js 52 | 53 | ### Using Express 54 | 55 | <<< examples/express.js 56 | 57 | ## Usage: Docker 58 | 59 | If you are interested in deploying an instance of `rtc-switchboard` using 60 | [docker](https://www.docker.com/) then the following is a great place to 61 | start: 62 | 63 | 64 | 65 | <<< docs/logging.md 66 | 67 | **/ 68 | 69 | module.exports = function(server, opts) { 70 | var WebSocketServer = require('ws').Server; 71 | var wss = new WebSocketServer({ server: server }); 72 | var board = require('rtc-switch')(); 73 | var connections = []; 74 | 75 | wss.on('connection', function connection(ws) { 76 | var peer = board.connect(); 77 | 78 | // add the socket to the connection list 79 | connections.push(ws); 80 | 81 | ws.on('message', peer.process); 82 | peer.on('data', function(data) { 83 | if (ws.readyState === 1) { 84 | debug('<== %s %s', peer.id, data); 85 | ws.send(data); 86 | } 87 | }); 88 | 89 | ws.on('close', function() { 90 | // trigger the peer leave 91 | peer.leave(); 92 | 93 | // splice out the connection 94 | connections = connections.filter(function(conn) { 95 | return conn !== ws; 96 | }); 97 | }); 98 | }); 99 | 100 | // add a reset helper 101 | board.reset = function() { 102 | connections.splice(0).forEach(function(conn) { 103 | conn.close(); 104 | }); 105 | }; 106 | 107 | return board; 108 | }; 109 | -------------------------------------------------------------------------------- /loadtest/runner.js: -------------------------------------------------------------------------------- 1 | var times = require('whisk/times'); 2 | var uuid = require('uuid'); 3 | var fork = require('child_process').fork; 4 | var nopt = require('nopt'); 5 | var knownOpts = { 6 | 'test': [ String ], 7 | 'count': [ Number ] 8 | }; 9 | var shorthands = { 10 | 't': [ '--test' ], 11 | 'c': [ '--count' ] 12 | }; 13 | var parsed = nopt(knownOpts, shorthands, process.argv, 2); 14 | 15 | var procs = times(parsed.count || 1).map(function() { 16 | var room = uuid.v4(); 17 | var proc = fork(__dirname + '/' + (parsed.test || 'simple') + '.js', { 18 | env: { 19 | SWITCHBOARD: process.env.SWITCHBOARD, 20 | ROOM: room 21 | }, 22 | 23 | silent: false 24 | }); 25 | 26 | proc.room = room; 27 | return proc; 28 | }); 29 | 30 | function cleanupOnExit(proc) { 31 | proc.on('exit', function(code) { 32 | procs.splice(procs.indexOf(proc), 1); 33 | console.log('process ' + proc.pid + ' (room: ' + proc.room + ') exited with errcode: ' + code + ', ' + procs.length + ' remaining'); 34 | }); 35 | } 36 | 37 | procs.forEach(function(proc) { 38 | proc 39 | .on('error', function(err) { 40 | console.log('captured error from proc: ', err); 41 | }); 42 | 43 | cleanupOnExit(proc); 44 | }); 45 | -------------------------------------------------------------------------------- /loadtest/simple.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var room = process.env.ROOM || require('uuid').v4(); 3 | var switchboard = process.env.SWITCHBOARD || 'ws://localhost:3000/primus'; 4 | var signallers = []; 5 | 6 | // require('cog/logger').enable('*'); 7 | 8 | function addSignaller(callback) { 9 | var signaller; 10 | var pending = signallers.length + 1; 11 | 12 | function checkPending() { 13 | if (pending <= 0) { 14 | callback(); 15 | } 16 | } 17 | 18 | signallers.forEach(function(s) { 19 | s.once('peer:announce', function(data) { 20 | if (data.id === signaller.id) { 21 | pending--; 22 | checkPending(); 23 | } 24 | }); 25 | }) 26 | 27 | signaller = require('rtc-signaller')(switchboard, { autoreply: false }); 28 | 29 | signallers.push(signaller); 30 | signaller 31 | .once('error', callback) 32 | .once('connected', function() { 33 | pending--; 34 | checkPending(); 35 | }); 36 | 37 | signaller.announce({ room: room }); 38 | console.log(signallers.length); 39 | } 40 | 41 | async.forever(addSignaller, function(err) { 42 | console.log('failed with err: ', err); 43 | }); 44 | 45 | setInterval(function() { 46 | signallers[0].send('/ping'); 47 | }, 5000); 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rtc-switchboard", 3 | "version": "3.2.0", 4 | "description": "Signalling for rtc-io components using primus", 5 | "main": "index.js", 6 | "stability": "unstable", 7 | "scripts": { 8 | "start": "node --nouse-idle-notification server.js", 9 | "test": "node test/all.js | tap-spec", 10 | "gendocs": "gendocs > README.md" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/rtc-io/rtc-switchboard.git" 15 | }, 16 | "keywords": [ 17 | "rtc.io", 18 | "webrtc", 19 | "signalling", 20 | "primus" 21 | ], 22 | "author": "Damon Oehlman ", 23 | "license": "Apache-2.0", 24 | "bugs": { 25 | "url": "https://github.com/rtc-io/rtc-switchboard/issues" 26 | }, 27 | "dependencies": { 28 | "cog": "^1.0.0", 29 | "debug": "^2.0.0", 30 | "rtc-switch": "^1.3.0", 31 | "ws": "^1.0.0" 32 | }, 33 | "devDependencies": { 34 | "async": "^0.9.0", 35 | "bunyan": "^1.1.3", 36 | "cuid": "^1.2.4", 37 | "express": "^4", 38 | "nopt": "^3.0.1", 39 | "replify": "^1.2.0", 40 | "rtc-quickconnect": "^4.1.0", 41 | "rtc-signaller": "^6.3.0", 42 | "rtc-switchboard-messenger": "^2.0.0", 43 | "tap-spec": "^4.1.1", 44 | "tape": "^4.2.0", 45 | "uuid": "^2.0.1", 46 | "whisk": "^1.0.0" 47 | }, 48 | "optionalDependencies": { 49 | "bufferutil": "^1.2.1", 50 | "utf-8-validate": "^1.2.1" 51 | } 52 | } -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var server = require('http').createServer(); 2 | var switchboard = require('./')(server, { servelib: true }); 3 | var port = parseInt(process.env.NODE_PORT || process.env.PORT || process.argv[2], 10) || 3000; 4 | var host = process.env.NODE_HOST || process.env.HOST || 'localhost'; 5 | // var replify = require('replify'); 6 | 7 | server.on('request', function(req, res) { 8 | if (req.url === '/') { 9 | res.writeHead(302, { 10 | 'Location': 'https://github.com/rtc-io/rtc-switchboard' 11 | }); 12 | res.end('switchboard available from: https://github.com/rtc-io/rtc-switchboard'); 13 | } 14 | }); 15 | 16 | // start the server 17 | server.listen(port, host, function(err) { 18 | if (err) { 19 | return console.log('Encountered error starting server: ', err); 20 | } 21 | 22 | console.log('server running at http://' + host + ':' + port + '/'); 23 | }); 24 | 25 | // // add the repl 26 | // replify({ 27 | // name: 'switchboard', 28 | // app: switchboard, 29 | // contexts: { 30 | // server: server 31 | // } 32 | // }); 33 | // 34 | // switchboard.on('room:create', function(room) { 35 | // console.log('room ' + room + ' created, now have ' + switchboard.rooms.length + ' active rooms'); 36 | // }); 37 | // 38 | // switchboard.on('room:destroy', function(room) { 39 | // console.log('room ' + room + ' destroyed, ' + switchboard.rooms.length + ' active rooms remain'); 40 | // 41 | // if (typeof gc == 'function') { 42 | // console.log('gc'); 43 | // gc(); 44 | // } 45 | // }); 46 | -------------------------------------------------------------------------------- /test/all.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | 3 | server.start(function(test, board) { 4 | require('./disconnect-quick')(test, board); 5 | require('./room-isolation')(test, board); 6 | require('./room-leave')(test, board); 7 | require('./room-reuse')(test, board); 8 | require('./room-info')(test, board); 9 | require('./room-changes')(test, board); 10 | require('./room-events')(test, board); 11 | require('./to-messaging')(test, board); 12 | require('./signaller-durability')(test, board); 13 | require('./peer-events')(test, board); 14 | require('./reset')(test, board); 15 | }); 16 | -------------------------------------------------------------------------------- /test/disconnect-quick.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var signaller = require('rtc-signaller'); 3 | var messenger = require('rtc-switchboard-messenger'); 4 | 5 | var start = module.exports = function(test, board) { 6 | var socket; 7 | var sig; 8 | 9 | test('create a signaller', function(t) { 10 | t.plan(2); 11 | t.ok(sig = signaller(messenger('http://localhost:3001')), 'signaller created'); 12 | sig.announce({ name: 'Fred', room: require('uuid').v4() }); 13 | sig.once('connected', t.pass.bind(t, 'signaller open')); 14 | }); 15 | 16 | test('disconnect signaller', function(t) { 17 | t.plan(1); 18 | sig.once('disconnected', t.pass.bind(t, 'disconnected')); 19 | sig.leave(); 20 | }); 21 | }; 22 | 23 | if (! module.parent) { 24 | server.start(start); 25 | } 26 | -------------------------------------------------------------------------------- /test/helpers/announce.js: -------------------------------------------------------------------------------- 1 | module.exports = function(board, clients, idx, data) { 2 | return function(t) { 3 | t.plan(1); 4 | board.once('announce', function(payload, peer, sender, d) { 5 | // give time for the client announce to come back 6 | setTimeout(function() { 7 | t.equal(d.id, clients[idx].id, 'client connected'); 8 | }, 500); 9 | }); 10 | 11 | clients[idx].announce(data); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /test/helpers/cleanup.js: -------------------------------------------------------------------------------- 1 | module.exports = function(board, clients) { 2 | return function(t) { 3 | var count = 0; 4 | 5 | t.plan(clients.length); 6 | 7 | function handleLeave() { 8 | t.pass('captured leave'); 9 | } 10 | 11 | t.on('result', function() { 12 | count += 1; 13 | if (count >= clients.length) { 14 | board.removeListener('leave', handleLeave); 15 | } 16 | }); 17 | 18 | board.on('leave', handleLeave); 19 | 20 | clients.forEach(function(client) { 21 | client.leave(); 22 | }); 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /test/helpers/connect.js: -------------------------------------------------------------------------------- 1 | var signaller = require('rtc-signaller'); 2 | var messenger = require('rtc-switchboard-messenger'); 3 | 4 | module.exports = function(board, clients, index, opts) { 5 | return function(t) { 6 | var socket; 7 | 8 | // only set the plan if not already done 9 | if (! t._plan) { 10 | t.plan(2); 11 | } 12 | 13 | // create the socket 14 | t.ok(clients[index] = signaller(messenger('http://localhost:3001/')), 'created client ' + index); 15 | clients[index].once('connected', t.pass.bind(t, 'connected')); 16 | 17 | // patch the socket into the signaller 18 | clients[index].socket = socket; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /test/helpers/server.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var http = require('http'); 3 | var server = http.createServer(); 4 | var switchboard = require('../../'); 5 | 6 | function testClose() { 7 | var quitTimer; 8 | 9 | test('close the server', function(t) { 10 | t.plan(1); 11 | server.close(function() { 12 | clearTimeout(quitTimer); 13 | console.log('closed'); 14 | }); 15 | 16 | t.pass('server closed'); 17 | 18 | // force quit 19 | quitTimer = setTimeout(process.exit.bind(process, 0), 1000); 20 | }); 21 | } 22 | 23 | exports.start = function(innerTests) { 24 | test('start the test server', function(t) { 25 | var board; 26 | 27 | t.plan(1); 28 | board = switchboard(server); 29 | 30 | // listen 31 | server.listen(3001, function(err) { 32 | t.ifError(err, 'test server started'); 33 | 34 | // run the inner tests 35 | innerTests(test, board); 36 | testClose(); 37 | }); 38 | }); 39 | }; 40 | -------------------------------------------------------------------------------- /test/helpers/socket.js: -------------------------------------------------------------------------------- 1 | module.exports = function(board, clients, index) { 2 | return function(t) { 3 | t.plan(2); 4 | t.ok(clients[index] = board.createSocket('http://localhost:3001'), 'created client ' + index); 5 | clients[index].once('open', t.pass.bind(t, 'connected')); 6 | }; 7 | } -------------------------------------------------------------------------------- /test/peer-events.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var cleanup = require('./helpers/cleanup'); 4 | var uuid = require('uuid'); 5 | 6 | var start = module.exports = function(test, board) { 7 | var clients = []; 8 | 9 | test('peer:connect event is emitted when a new peer connects', function(t) { 10 | t.plan(3); 11 | 12 | var failTimer = setTimeout(function() { 13 | t.fail('peer:connect should have been fired.'); 14 | }, 100); 15 | 16 | board.once('peer:connect', function(name) { 17 | clearTimeout(failTimer); 18 | t.pass('peer:connect was indeed fired.'); 19 | }); 20 | 21 | connect(board, clients, 0)(t); 22 | }); 23 | 24 | test('peer:disconnect event is emitted when a peer packs up.', function(t) { 25 | t.plan(1); 26 | 27 | var failTimer = setTimeout(function() { 28 | t.fail('peer:disconnect should have been fired.'); 29 | }, 100); 30 | 31 | board.once('peer:disconnect', function(name) { 32 | clearTimeout(failTimer); 33 | t.pass('peer:disconnect was indeed fired.'); 34 | }); 35 | 36 | clients[0].leave(); 37 | }); 38 | 39 | }; 40 | 41 | if (! module.parent) { 42 | server.start(start); 43 | } 44 | -------------------------------------------------------------------------------- /test/reset.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var cleanup = require('./helpers/cleanup'); 4 | var uuid = require('uuid'); 5 | 6 | var start = module.exports = function(test, board) { 7 | var clients = []; 8 | var roomId = uuid.v4(); 9 | 10 | test('connect 0', connect(board, clients, 0)); 11 | test('connect 1', connect(board, clients, 1)); 12 | test('connect 2', connect(board, clients, 2)); 13 | 14 | test('announce 0', function(t) { 15 | t.plan(2); 16 | 17 | board.once('announce', function(payload, peer, sender, data) { 18 | t.equal(data.id, clients[0].id); 19 | t.equal(data.room, roomId); 20 | }); 21 | 22 | clients[0].announce({ room: roomId }); 23 | }); 24 | 25 | test('announce 1 - in same room as 0', function(t) { 26 | 27 | function checkData(data) { 28 | t.equal(data.id, clients[1].id); 29 | t.equal(data.room, roomId); 30 | } 31 | 32 | t.plan(4); 33 | clients[0].once('peer:announce', checkData); 34 | board.once('announce', function(payload, peer, sender, data) { 35 | checkData(data); 36 | }); 37 | 38 | clients[1].announce({ room: roomId }); 39 | }); 40 | 41 | test('check that peer 0 responds to peer 0', function(t) { 42 | t.plan(2); 43 | clients[1].once('peer:announce', function(data) { 44 | t.equal(data.id, clients[0].id); 45 | t.equal(data.room, roomId); 46 | }); 47 | }); 48 | 49 | test('a peer disconnect event is triggered when we reset the switchboard', function(t) { 50 | t.plan(1); 51 | 52 | var failTimer = setTimeout(function() { 53 | t.fail('peer:disconnect should have been fired.'); 54 | }, 100); 55 | 56 | board.once('peer:disconnect', function(name) { 57 | clearTimeout(failTimer); 58 | t.pass('peer:disconnect was indeed fired.'); 59 | }); 60 | 61 | board.reset(); 62 | }); 63 | 64 | test('announce 2', function(t) { 65 | t.plan(2); 66 | 67 | board.once('announce', function(payload, peer, sender, data) { 68 | t.equal(data.id, clients[2].id); 69 | t.equal(data.room, roomId); 70 | }); 71 | 72 | clients[2].announce({ room: roomId }); 73 | }); 74 | 75 | test('peer:0 and peer:1 successfully learn about peer:2', function(t) { 76 | var remaining = 2; 77 | var timeout = setTimeout(t.fail.bind(t, 'did not find peers'), 5000); 78 | 79 | function handleAnnounce(data) { 80 | t.equal(data.id, clients[2].id, 'found peer:2'); 81 | remaining -= 1; 82 | 83 | if (remaining === 0) { 84 | clearTimeout(timeout); 85 | t.pass('all peers found'); 86 | } 87 | } 88 | 89 | t.plan(remaining + 1); 90 | clients.slice(0,2).forEach(function(client) { 91 | client.once('peer:announce', handleAnnounce); 92 | }); 93 | }); 94 | }; 95 | 96 | if (! module.parent) { 97 | server.start(start); 98 | } 99 | -------------------------------------------------------------------------------- /test/room-changes.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var cleanup = require('./helpers/cleanup'); 4 | var uuid = require('uuid'); 5 | 6 | var start = module.exports = function(test, board) { 7 | var clients = []; 8 | var roomIds = [uuid.v4(), uuid.v4(), uuid.v4()]; 9 | 10 | test('connect 0', connect(board, clients, 0)); 11 | test('connect 1', connect(board, clients, 1)); 12 | test('connect 2', connect(board, clients, 2)); 13 | 14 | test('client:0 announce (room:0)', function(t) { 15 | t.plan(2); 16 | 17 | clients[0].announce({ room: roomIds[0] }); 18 | board.once('announce', function(payload, peer, sender, data) { 19 | t.equal(data.id, clients[0].id); 20 | t.equal(data.room, roomIds[0]); 21 | }); 22 | }); 23 | 24 | test('client:1 announce (room:1)', function(t) { 25 | t.plan(2); 26 | 27 | clients[1].announce({ room: roomIds[1] }); 28 | board.once('announce', function(payload, peer, sender, data) { 29 | t.equal(data.id, clients[1].id); 30 | t.equal(data.room, roomIds[1], 'room === room1'); 31 | }); 32 | }); 33 | 34 | test('client:2 announce (room:0)', function(t) { 35 | t.plan(4); 36 | 37 | clients[2].announce({ room: roomIds[0] }); 38 | board.once('announce', function(payload, peer, sender, data) { 39 | t.equal(data.id, clients[2].id); 40 | t.equal(data.room, roomIds[0]); 41 | }); 42 | 43 | clients[0].once('peer:announce', function(data) { 44 | t.equal(data.id, clients[2].id, 'client:0 got peer:announce for client:2'); 45 | }); 46 | 47 | clients[1].once('peer:announce', function(data) { 48 | t.fail('client:1 received peer announce but should not have'); 49 | }); 50 | 51 | setTimeout(function() { 52 | t.pass('client:1 did not receive peer:announce'); 53 | clients[1].removeAllListeners(); 54 | }, 500); 55 | }); 56 | 57 | test('client:2 send hello, client:0 receives, client:1 does not', function(t) { 58 | t.plan(2); 59 | clients[2].send('/hello'); 60 | 61 | clients[0].once('message:hello', function() { 62 | t.pass('client:0 got message'); 63 | }); 64 | 65 | clients[1].once('message:hello', function() { 66 | t.fail('client:1 got message'); 67 | }); 68 | 69 | setTimeout(function() { 70 | t.pass('client:1 did not receive message'); 71 | clients[1].removeAllListeners(); 72 | }, 500); 73 | }); 74 | 75 | test('client:2 reannounce (room:1)', function(t) { 76 | t.plan(3); 77 | 78 | clients[2].announce({ room: roomIds[1] }); 79 | board.once('announce', function(payload, peer, sender, data) { 80 | t.equal(data.id, clients[2].id); 81 | t.equal(data.room, roomIds[1]); 82 | }); 83 | 84 | clients[1].on('peer:announce', function(data) { 85 | t.equal(data.id, clients[2].id, 'client:1 got announce for client:2'); 86 | }); 87 | }); 88 | 89 | test('client:2 send hello, client:1 receives, client:0 does not', function(t) { 90 | t.plan(2); 91 | clients[2].send('/hello'); 92 | 93 | clients[0].once('message:hello', function() { 94 | t.fail('client:0 got message'); 95 | }); 96 | 97 | clients[1].once('message:hello', function() { 98 | t.pass('client:1 got message'); 99 | }); 100 | 101 | setTimeout(function() { 102 | t.pass('client:0 did not receive message'); 103 | clients[0].removeAllListeners(); 104 | }, 500); 105 | }); 106 | 107 | test('client:0 reannounce (room:2)', function(t) { 108 | t.plan(3); 109 | 110 | clients[0].announce({ room: roomIds[2] }); 111 | board.once('announce', function(payload, peer, sender, data) { 112 | t.equal(data.id, clients[0].id); 113 | t.equal(data.room, roomIds[2]); 114 | }); 115 | 116 | clients[0].once('message:roominfo', function(data) { 117 | t.equal(data.memberCount, 1, 'room has one member'); 118 | }); 119 | }); 120 | 121 | test('client:2 reannounce (room:2)', function(t) { 122 | t.plan(4); 123 | 124 | clients[2].announce({ room: roomIds[2] }); 125 | clients[2].once('message:roominfo', function(data) { 126 | t.equal(data.memberCount, 2, 'room has two members'); 127 | }); 128 | 129 | board.once('announce', function(payload, peer, sender, data) { 130 | t.equal(data.id, clients[2].id); 131 | t.equal(data.room, roomIds[2]); 132 | }); 133 | 134 | clients[0].once('peer:update', function(data) { 135 | t.equal(data.id, clients[2].id, 'client:0 got update for client:2'); 136 | }); 137 | }); 138 | 139 | test('client:2 send hello, client:0 receives, client:1 does not', function(t) { 140 | t.plan(2); 141 | clients[2].send('/hello'); 142 | 143 | clients[0].once('message:hello', function() { 144 | t.pass('client:0 got message'); 145 | }); 146 | 147 | clients[1].once('message:hello', function() { 148 | t.fail('client:1 got message'); 149 | }); 150 | 151 | setTimeout(function() { 152 | t.pass('client:1 did not receive message'); 153 | clients[0].removeAllListeners(); 154 | }, 500); 155 | }); 156 | 157 | test('close connections', cleanup(board, clients)); 158 | }; 159 | 160 | if (! module.parent) { 161 | server.start(start); 162 | } 163 | -------------------------------------------------------------------------------- /test/room-events.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var cleanup = require('./helpers/cleanup'); 4 | var uuid = require('uuid'); 5 | 6 | var start = module.exports = function(test, board) { 7 | var clients = []; 8 | var roomId = uuid.v4(); 9 | 10 | test('connect 0', connect(board, clients, 0)); 11 | test('connect 1', connect(board, clients, 1)); 12 | 13 | test('switchboard emits a room:create event when a new room is created', function(t) { 14 | t.plan(1); 15 | 16 | board.once('room:create', function(name) { 17 | t.equal(name, roomId, 'room id match'); 18 | }); 19 | 20 | clients[0].announce({ room: roomId }); 21 | }); 22 | 23 | test('client:0 close, room:destroy event fires', function(t) { 24 | t.plan(1); 25 | 26 | board.once('room:destroy', function(name) { 27 | t.equal(name, roomId, 'room id match'); 28 | }); 29 | 30 | clients[0].leave(); 31 | }); 32 | 33 | test('connect 0', connect(board, clients, 0)); 34 | 35 | test('switchboard emits another room:create event when a new room is recreated', function(t) { 36 | t.plan(1); 37 | 38 | board.once('room:create', function(name) { 39 | t.equal(name, roomId, 'room id match'); 40 | }); 41 | 42 | clients[0].announce({ room: roomId }); 43 | }); 44 | 45 | test('switchboard does not emit a room:create event when the client joins the room', function(t) { 46 | t.plan(1); 47 | 48 | function handleCreate(name) { 49 | t.fail('room:create event should not have fired'); 50 | } 51 | 52 | board.once('room:create', handleCreate); 53 | 54 | setTimeout(function() { 55 | board.removeListener('room:create', handleCreate); 56 | t.pass('room:create event did not fire'); 57 | }, 100); 58 | 59 | clients[1].announce({ room: roomId }); 60 | }); 61 | 62 | test('client:0 close, room:destroy does not fire', function(t) { 63 | t.plan(1); 64 | 65 | function handleDestroy(name) { 66 | t.fail('room:destroy should not have fired'); 67 | } 68 | 69 | board.once('room:destroy', handleDestroy); 70 | 71 | setTimeout(function() { 72 | board.removeListener('room:destroy', handleDestroy); 73 | t.pass('room:destroy event did not fire'); 74 | }, 100); 75 | 76 | clients[0].leave(); 77 | }); 78 | 79 | test('client:1 close, room:destroy does fire', function(t) { 80 | t.plan(1); 81 | 82 | board.once('room:destroy', function(name) { 83 | t.equal(name, roomId, 'room id match'); 84 | }); 85 | 86 | clients[1].leave(); 87 | }); 88 | 89 | test('connect 0', connect(board, clients, 0)); 90 | 91 | test('switchboard emits another room:create event when a new room is recreated', function(t) { 92 | t.plan(1); 93 | 94 | board.once('room:create', function(name) { 95 | t.equal(name, roomId, 'room id match'); 96 | }); 97 | 98 | clients[0].announce({ room: roomId }); 99 | }); 100 | 101 | test('switchboard emits room:create and room:destroy events when a client changes room', function(t) { 102 | var newRoomId = uuid.v4(); 103 | 104 | t.plan(2); 105 | 106 | board.once('room:destroy', function(name) { 107 | t.equal(name, roomId, 'old room destroyed'); 108 | }); 109 | 110 | board.once('room:create', function(name) { 111 | t.equal(name, newRoomId, 'new room created'); 112 | }); 113 | 114 | clients[0].announce({ room: newRoomId }); 115 | }); 116 | 117 | test('client:0 close', function(t) { 118 | t.plan(1); 119 | 120 | board.once('room:destroy', function(name) { 121 | t.notEqual(name, roomId, 'new room destroyed'); 122 | }); 123 | 124 | clients[0].leave(); 125 | }); 126 | 127 | // no close required as clients have been removed and movements tracked 128 | }; 129 | 130 | if (! module.parent) { 131 | server.start(start); 132 | } 133 | -------------------------------------------------------------------------------- /test/room-info.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var cleanup = require('./helpers/cleanup'); 4 | var uuid = require('uuid'); 5 | 6 | var start = module.exports = function(test, board) { 7 | var clients = []; 8 | var roomId = uuid.v4(); 9 | 10 | test('connect 0', connect(board, clients, 0)); 11 | test('connect 1', connect(board, clients, 1)); 12 | 13 | test('announce 0', function(t) { 14 | t.plan(4); 15 | 16 | board.once('announce', function(payload, peer, sender, data) { 17 | t.equal(data.id, clients[0].id); 18 | t.equal(data.room, roomId); 19 | }); 20 | 21 | clients[0].once('message:roominfo', function(data) { 22 | t.ok(data && typeof data == 'object'); 23 | t.equal(data.memberCount, 1, 'reported as 1st peer'); 24 | }); 25 | 26 | clients[0].announce({ room: roomId }); 27 | }); 28 | 29 | test('announce 1', function(t) { 30 | t.plan(4); 31 | 32 | board.once('announce', function(payload, peer, sender, data) { 33 | t.equal(data.id, clients[1].id); 34 | t.equal(data.room, roomId); 35 | }); 36 | 37 | clients[1].once('message:roominfo', function(data) { 38 | t.ok(data && typeof data == 'object'); 39 | t.equal(data.memberCount, 2, 'reported as 2nd peer'); 40 | }); 41 | 42 | clients[1].announce({ room: roomId }); 43 | }); 44 | 45 | test('close connections', cleanup(board, clients)); 46 | }; 47 | 48 | if (! module.parent) { 49 | server.start(start); 50 | } 51 | -------------------------------------------------------------------------------- /test/room-isolation.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var cleanup = require('./helpers/cleanup'); 4 | var uuid = require('uuid'); 5 | 6 | var start = module.exports = function(test, board) { 7 | var clients = []; 8 | var roomId = uuid.v4(); 9 | 10 | test('connect 0', connect(board, clients, 0)); 11 | test('connect 1', connect(board, clients, 1)); 12 | test('connect 2', connect(board, clients, 2)); 13 | 14 | test('announce 0', function(t) { 15 | t.plan(2); 16 | 17 | board.once('announce', function(payload, peer, sender, data) { 18 | t.equal(data.id, clients[0].id); 19 | t.equal(data.room, roomId); 20 | }); 21 | 22 | clients[0].announce({ room: roomId }); 23 | }); 24 | 25 | test('announce 1 - in same room as 0', function(t) { 26 | 27 | function checkData(data) { 28 | t.equal(data.id, clients[1].id); 29 | t.equal(data.room, roomId); 30 | } 31 | 32 | t.plan(4); 33 | clients[0].once('peer:announce', checkData); 34 | board.once('announce', function(payload, peer, sender, data) { 35 | checkData(data); 36 | }); 37 | 38 | clients[1].announce({ room: roomId }); 39 | }); 40 | 41 | test('check that peer 0 responds to peer 0', function(t) { 42 | t.plan(2); 43 | clients[1].once('peer:announce', function(data) { 44 | t.equal(data.id, clients[0].id); 45 | t.equal(data.room, roomId); 46 | }); 47 | }); 48 | 49 | test('announce 2 - in different room to 0 + 1', function(t) { 50 | var newRoomId = uuid.v4(); 51 | 52 | function failTest() { 53 | t.fail('captured announce message even though in a different room'); 54 | } 55 | 56 | t.plan(3); 57 | 58 | board.once('announce', function(payload, peer, sender, data) { 59 | t.equal(data.id, clients[2].id); 60 | t.equal(data.room, newRoomId); 61 | }); 62 | 63 | clients[0].once('peer:announce', failTest); 64 | clients[1].once('peer:announce', failTest); 65 | 66 | setTimeout(function() { 67 | clients[0].removeListener('peer:announce', failTest); 68 | clients[1].removeListener('peer:announce', failTest); 69 | 70 | t.pass('did not trigger an event for clients in original room'); 71 | }, 200); 72 | 73 | clients[2].announce({ room: newRoomId }); 74 | }); 75 | 76 | test('close connections', cleanup(board, clients)); 77 | }; 78 | 79 | if (! module.parent) { 80 | server.start(start); 81 | } 82 | -------------------------------------------------------------------------------- /test/room-leave.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var announce = require('./helpers/announce'); 4 | var cleanup = require('./helpers/cleanup'); 5 | var uuid = require('uuid'); 6 | 7 | var start = module.exports = function(test, board) { 8 | var clients = []; 9 | var roomId = uuid.v4(); 10 | var room2 = uuid.v4(); 11 | 12 | test('connect 0', connect(board, clients, 0)); 13 | test('connect 1', connect(board, clients, 1)); 14 | 15 | test('announce 0', announce(board, clients, 0, { room: roomId })); 16 | test('announce 1', announce(board, clients, 1, { room: roomId })); 17 | 18 | test('check 2 room members', function(t) { 19 | var room = board.rooms.get(roomId); 20 | 21 | t.plan(2); 22 | t.ok(room && room.members, 'have room'); 23 | t.equal(room.members.length, 2); 24 | }); 25 | 26 | test('announce 1 in new room', announce(board, clients, 1, { room: room2 })); 27 | 28 | test('check 1 member in original room', function(t) { 29 | var room = board.rooms.get(roomId); 30 | 31 | t.plan(2); 32 | t.ok(room && room.members, 'have room'); 33 | t.equal(room.members.length, 1); 34 | }); 35 | 36 | test('check 1 member in new room', function(t) { 37 | var room = board.rooms.get(room2); 38 | 39 | t.plan(2); 40 | t.ok(room && room.members, 'have room'); 41 | t.equal(room.members.length, 1); 42 | }); 43 | 44 | test('close connections', cleanup(board, clients)); 45 | 46 | test('check room has been destroyed', function(t) { 47 | var room = board.rooms.get(roomId); 48 | var failTimer; 49 | 50 | t.plan(1); 51 | if (! room) { 52 | return t.pass('room has been removed'); 53 | } 54 | 55 | failTimer = setTimeout(t.fail.bind(t, 'room not destroyed'), 500); 56 | board.once('room:destroy', function(room) { 57 | t.equal(room, roomId, 'room has been removed'); 58 | clearTimeout(failTimer); 59 | }); 60 | }); 61 | }; 62 | 63 | if (! module.parent) { 64 | server.start(start); 65 | } 66 | -------------------------------------------------------------------------------- /test/room-reuse.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var announce = require('./helpers/announce'); 4 | var cleanup = require('./helpers/cleanup'); 5 | var uuid = require('uuid'); 6 | 7 | var start = module.exports = function(test, board) { 8 | var clients = []; 9 | var roomId = uuid.v4(); 10 | var room2 = uuid.v4(); 11 | 12 | test('connect 0', connect(board, clients, 0)); 13 | test('announce 0', announce(board, clients, 0, { room: roomId })); 14 | test('close connections', cleanup(board, clients)); 15 | 16 | test('check room has been destroyed', function(t) { 17 | t.plan(1); 18 | t.notOk(board.rooms[roomId], 'room has been removed'); 19 | }); 20 | 21 | test('reuse room: connect 0', connect(board, clients, 0)); 22 | test('reuse room: announce 0', announce(board, clients, 0, { room: roomId })); 23 | test('reuse room: close connections', cleanup(board, clients)); 24 | 25 | test('reuse room: check room has been destroyed', function(t) { 26 | t.plan(1); 27 | t.notOk(board.rooms[roomId], 'room has been removed'); 28 | }); 29 | }; 30 | 31 | if (! module.parent) { 32 | server.start(start); 33 | } -------------------------------------------------------------------------------- /test/signaller-durability.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var cleanup = require('./helpers/cleanup'); 4 | var uuid = require('uuid'); 5 | 6 | var start = module.exports = function(test, board) { 7 | var clients = []; 8 | var roomId = uuid.v4(); 9 | 10 | test('connect 0', connect(board, clients, 0)); 11 | test('connect 1', connect(board, clients, 1)); 12 | 13 | test('announce 0', function(t) { 14 | t.plan(2); 15 | 16 | clients[0].once('message:roominfo', function(data) { 17 | t.ok(data && typeof data == 'object'); 18 | t.equal(data.memberCount, 1, 'reported as 1st peer'); 19 | }); 20 | 21 | clients[0].announce({ room: roomId }); 22 | }); 23 | 24 | test('announce 1', function(t) { 25 | t.plan(2); 26 | 27 | clients[1].once('message:roominfo', function(data) { 28 | t.ok(data && typeof data == 'object'); 29 | t.equal(data.memberCount, 2, 'reported as 2nd peer'); 30 | }); 31 | 32 | clients[1].announce({ room: roomId }); 33 | }); 34 | 35 | test('signallers remain connected and do not timeout', function(t) { 36 | var timer = setInterval(t.pass.bind(t, 'still connected'), 5e3); 37 | var waitIntervals = 10; 38 | 39 | function handleDisconnect() { 40 | unbindHandlers(); 41 | t.fail('signaller disconnected'); 42 | } 43 | 44 | function unbindHandlers() { 45 | clients.forEach(function(c) { 46 | c.removeListener('disconnected', handleDisconnect); 47 | }); 48 | } 49 | 50 | clients.forEach(function(c) { 51 | c.on('disconnected', handleDisconnect); 52 | }); 53 | 54 | setTimeout(function() { 55 | clearInterval(timer); 56 | unbindHandlers(); 57 | t.pass('completed checks'); 58 | }, waitIntervals * 5e3 + 1e3); 59 | 60 | t.plan(waitIntervals + 1); 61 | }); 62 | 63 | test('close connections', cleanup(board, clients)); 64 | }; 65 | 66 | if (! module.parent) { 67 | server.start(start); 68 | } 69 | -------------------------------------------------------------------------------- /test/to-messaging.js: -------------------------------------------------------------------------------- 1 | var server = require('./helpers/server'); 2 | var connect = require('./helpers/connect'); 3 | var announce = require('./helpers/announce'); 4 | var cleanup = require('./helpers/cleanup'); 5 | var uuid = require('uuid'); 6 | 7 | var start = module.exports = function(test, board) { 8 | var clients = []; 9 | var roomId = uuid.v4(); 10 | 11 | test('connect 0', connect(board, clients, 0, { autoreply: true })); 12 | test('connect 1', connect(board, clients, 1, { autoreply: true })); 13 | test('connect 2', connect(board, clients, 2, { autoreply: true })); 14 | 15 | test('announce 0', announce(board, clients, 0, { room: roomId })); 16 | test('announce 1', announce(board, clients, 1, { room: roomId })); 17 | test('announce 2', announce(board, clients, 2, { room: uuid.v4() })); 18 | 19 | test('send from 0 --> 1', function(t) { 20 | t.plan(1); 21 | 22 | clients[1].on('message:hello', function(data) { 23 | t.equal(data.a, 1, 'got message'); 24 | }); 25 | 26 | setTimeout(function() { 27 | clients[0].to(clients[1].id).send('/hello', { a: 1 }); 28 | }, 200); 29 | }); 30 | 31 | // test('send from 1 --> 2', function(t) { 32 | // t.plan(1); 33 | 34 | // clients[2].on('hello', function(data) { 35 | // t.equal(data.b, 2, 'got message'); 36 | // }); 37 | 38 | // clients[1].to(clients[2].id).send('/hello', { b: 2 }); 39 | // }); 40 | 41 | // test('send from 2 --> 0', function(t) { 42 | // t.plan(1); 43 | 44 | // clients[0].on('hello', function(data) { 45 | // t.equal(data.c, 3, 'got message'); 46 | // }); 47 | 48 | // clients[2].to(clients[0].id).send('/hello', { c: 3 }); 49 | // }); 50 | 51 | test('close connections', cleanup(board, clients)); 52 | }; 53 | 54 | if (! module.parent) { 55 | server.start(start); 56 | } 57 | --------------------------------------------------------------------------------