ws-server.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. 'use strict';
  2. var parser = require('ua-parser-js');
  3. // Start Binary.js server
  4. var BinaryServer = require('binaryjs').BinaryServer;
  5. exports.create = function(server) {
  6. // link it to express
  7. var bs = BinaryServer({
  8. server: server,
  9. path: '/binary'
  10. });
  11. function guid() {
  12. function s4() {
  13. return Math.floor((1 + Math.random()) * 0x10000)
  14. .toString(16)
  15. .substring(1);
  16. }
  17. return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
  18. s4() + '-' + s4() + s4() + s4();
  19. }
  20. function getDeviceName(req) {
  21. var ua = parser(req.headers['user-agent']);
  22. return {
  23. model: ua.device.model,
  24. os: ua.os.name,
  25. browser: ua.browser.name,
  26. type: ua.device.type
  27. };
  28. }
  29. // Wait for new user connections
  30. bs.on('connection', function(client) {
  31. console.log('connection received!', client._socket.upgradeReq.connection.remoteAddress);
  32. client.uuidRaw = guid();
  33. client.deviceName = getDeviceName(client._socket.upgradeReq);
  34. // Incoming stream from browsers
  35. client.on('stream', function(stream, meta) {
  36. console.log('stream received!', meta);
  37. if (meta && meta.serverMsg === 'rtc-support') {
  38. client.uuid = (meta.rtc ? 'rtc_' : '') + client.uuidRaw;
  39. client.send({
  40. isSystemEvent: true,
  41. type: 'handshake',
  42. uuid: client.uuid
  43. });
  44. return;
  45. }
  46. meta.from = client.uuid;
  47. // broadcast to the other client
  48. for (var id in bs.clients) {
  49. if (bs.clients.hasOwnProperty(id)) {
  50. var otherClient = bs.clients[id];
  51. if (otherClient !== client && meta.toPeer === otherClient.uuid) {
  52. var send = otherClient.createStream(meta);
  53. stream.pipe(send, meta);
  54. }
  55. }
  56. }
  57. });
  58. });
  59. function forEachClient(fn) {
  60. for (var id in bs.clients) {
  61. if (bs.clients.hasOwnProperty(id)) {
  62. var client = bs.clients[id];
  63. fn(client);
  64. }
  65. }
  66. }
  67. function getIP(socket) {
  68. return socket.upgradeReq.headers['x-forwarded-for'] || socket.upgradeReq.connection.remoteAddress;
  69. }
  70. function hash(text) {
  71. // A string hashing function based on Daniel J. Bernstein's popular 'times 33' hash algorithm.
  72. var h = 5381,
  73. index = text.length;
  74. while (index) {
  75. h = (h * 33) ^ text.charCodeAt(--index);
  76. }
  77. return h >>> 0;
  78. }
  79. function notifyBuddiesX() {
  80. var locations = {};
  81. //group all clients by location (by public ip address)
  82. forEachClient(function(client) {
  83. //ip is hashed to prevent injections by spoofing the 'x-forwarded-for' header
  84. var ip = hash(getIP(client._socket));
  85. locations[ip] = locations[ip] || [];
  86. locations[ip].push({
  87. socket: client,
  88. contact: {
  89. peerId: client.uuid,
  90. name: client.deviceName,
  91. }
  92. });
  93. });
  94. //notify every location
  95. Object.keys(locations).forEach(function(locationKey) {
  96. //notify every client of all other clients in this location
  97. var location = locations[locationKey];
  98. location.forEach(function(client) {
  99. //all other clients
  100. var buddies = location.reduce(function(result, otherClient) {
  101. if (otherClient !== client) {
  102. result.push(otherClient.contact);
  103. }
  104. return result;
  105. }, []);
  106. //protocol
  107. var msg = {
  108. buddies: buddies,
  109. isSystemEvent: true,
  110. type: 'buddies'
  111. };
  112. client.socket.send(msg);
  113. });
  114. });
  115. }
  116. setInterval(notifyBuddiesX, 5000);
  117. };