server.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. var util = require('./util');
  2. var express = require('express');
  3. var http = require('http');
  4. var EventEmitter = require('events').EventEmitter;
  5. var WebSocketServer = require('ws').Server;
  6. var url = require('url');
  7. var allowCrossDomain = function(req, res, next) {
  8. res.header('Access-Control-Allow-Origin', '*');
  9. res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  10. res.header('Access-Control-Allow-Headers', 'Content-Type');
  11. next();
  12. };
  13. function PeerServer(options) {
  14. if (!(this instanceof PeerServer)) return new PeerServer(options);
  15. EventEmitter.call(this);
  16. this._app = express();
  17. this._httpServer = http.createServer(this._app);
  18. var self = this;
  19. this._app.configure(function() {
  20. self._app.use(express.bodyParser());
  21. self._app.use(allowCrossDomain);
  22. });
  23. options = util.extend({
  24. port: 80
  25. }, options);
  26. util.debug = options.debug;
  27. // Listen on user-specified port and create WebSocket server as well.
  28. this._httpServer.listen(options.port);
  29. this._wss = new WebSocketServer({ path: '/ws', server: this._httpServer });
  30. // WebSockets that are opened.
  31. this._clients = {};
  32. this._timeouts = {};
  33. // Initailize WebSocket server handlers.
  34. this._initializeWSS();
  35. // Initialize HTTP routes. This is only used for the first few milliseconds
  36. // before a socket is opened for a Peer.
  37. this._initializeHTTP();
  38. };
  39. util.inherits(PeerServer, EventEmitter);
  40. /* Initialize WebSocket server. */
  41. PeerServer.prototype._initializeWSS = function() {
  42. var self = this;
  43. this._wss.on('connection', function(socket) {
  44. var id = url.parse(socket.upgradeReq.url, true).query.id;
  45. // Save the socket for this id.
  46. if (!!id && (!self._clients[id] || !!self._timeouts[id])) {
  47. if (!!self._timeouts[id]) {
  48. clearTimeout(self._timeouts[id]);
  49. delete self._timeouts[id];
  50. self._clients[id].end('socket');
  51. }
  52. } else if (!id) {
  53. id = self._generateClientId();
  54. socket.send(JSON.stringify({ type: 'ID', id: id }));
  55. }
  56. self._clients[id] = socket;
  57. socket.on('message', function(data) {
  58. try {
  59. var message = JSON.parse(data);
  60. util.log(message);
  61. switch (message.type) {
  62. // ICE candidates
  63. case 'CANDIDATE':
  64. // Offer or answer between peers.
  65. case 'OFFER':
  66. case 'ANSWER':
  67. // Firefoxism (connectDataConnection ports)
  68. case 'PORT':
  69. self._handleTransmission(message.type, message.src, message.dst, data);
  70. // Clean up.
  71. if (message.type === 'LEAVE') {
  72. delete self._clients[message.src];
  73. delete self._timeouts[message.src];
  74. }
  75. break;
  76. default:
  77. util.prettyError('message unrecognized');
  78. }
  79. } catch(e) {
  80. util.log('invalid message');
  81. }
  82. });
  83. });
  84. };
  85. /** Initialize HTTP server routes. */
  86. PeerServer.prototype._initializeHTTP = function() {
  87. var self = this;
  88. // Server sets up HTTP streaming whether you get or post an ID.
  89. // Retrieve guaranteed random ID.
  90. this._app.get('/id', function(req, res) {
  91. var clientId = util.randomId();
  92. while (!!self._clients[clientId]) {
  93. clientId = util.randomId();
  94. }
  95. self._startStreaming(res, clientId, function() {
  96. // Chrome hacks.
  97. res.write('{"id":"' + clientId + '"}\n');
  98. });
  99. });
  100. this._app.post('/id', function(req, res) {
  101. var id = req.body.id;
  102. self._startStreaming(res, id);
  103. });
  104. this._app.post('/offer', function(req, res) {
  105. // TODO: if offer person does not exist, set a timeout for 10s. may need to
  106. // change switch.
  107. var data = req.body.data;
  108. var src = data.src;
  109. var dst = data.dst;
  110. self._handleTransmission('OFFER', src, dst, JSON.stringify(data));
  111. });
  112. this._app.post('/answer', function(req, res) {
  113. var data = req.body.data;
  114. var src = data.src;
  115. var dst = data.dst;
  116. self._handleTransmission('ANSWER', src, dst, JSON.stringify(data));
  117. });
  118. };
  119. /** Saves a streaming response and takes care of timeouts and headers. */
  120. PeerServer.prototype._startStreaming = function(res, id, write) {
  121. res.writeHead(200, {'Content-Type': 'application/octet-stream'});
  122. if (!!write) {
  123. write();
  124. }
  125. var pad = '00';
  126. var iterations = 10;
  127. for (var i = 0; i < iterations; i++) {
  128. pad += pad;
  129. }
  130. res.write(pad + '\n');
  131. // Save res so we can write to it.
  132. this._clients[id] = res;
  133. // Set timeout to expire.
  134. this._timeouts[id] = setTimeout(function() { res.end('end') }, 10000);
  135. };
  136. // TODO: fix for streaming
  137. /** Handles passing on a message. */
  138. PeerServer.prototype._handleTransmission = function(type, src, dst, data) {
  139. var destination = this._clients[dst];
  140. if (!!destination) {
  141. try {
  142. if (this._timeouts[dst])
  143. data += '\n';
  144. destination.send(data);
  145. } catch (e) {
  146. util.prettyError(e);
  147. }
  148. } else {
  149. // TODO: IF OFFER: Place in queue for 10 seconds.
  150. util.log('TODO/handle: destination does not exist');
  151. }
  152. };
  153. PeerServer.prototype._generateClientId = function() {
  154. var clientId = util.randomId();
  155. while (!!self._clients[clientId]) {
  156. clientId = util.randomId();
  157. }
  158. };
  159. exports.PeerServer = PeerServer;