ws-server.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. function hash(text) {
  30. // A string hashing function based on Daniel J. Bernstein's popular 'times 33' hash algorithm.
  31. var h = 5381,
  32. index = text.length;
  33. while (index) {
  34. h = (h * 33) ^ text.charCodeAt(--index);
  35. }
  36. return h >>> 0;
  37. }
  38. function getIP(socket) {
  39. return socket.upgradeReq.headers['x-forwarded-for'] || socket.upgradeReq.connection.remoteAddress;
  40. }
  41. // Wait for new user connections
  42. bs.on('connection', function(client) {
  43. //console.log('connection received!', client._socket.upgradeReq.connection.remoteAddress);
  44. client.uuidRaw = guid();
  45. //ip is hashed to prevent injections by spoofing the 'x-forwarded-for' header
  46. client.hashedIp = hash(getIP(client._socket));
  47. client.deviceName = getDeviceName(client._socket.upgradeReq);
  48. // Incoming stream from browsers
  49. client.on('stream', function(stream, meta) {
  50. if (meta && meta.serverMsg === 'rtc-support') {
  51. client.uuid = (meta.rtc ? 'rtc_' : '') + client.uuidRaw;
  52. client.send({
  53. isSystemEvent: true,
  54. type: 'handshake',
  55. uuid: client.uuid
  56. });
  57. return;
  58. }
  59. meta.from = client.uuid;
  60. // broadcast to the other client
  61. for (var id in bs.clients) {
  62. if (bs.clients.hasOwnProperty(id)) {
  63. var otherClient = bs.clients[id];
  64. if (otherClient !== client && meta.toPeer === otherClient.uuid) {
  65. var send = otherClient.createStream(meta);
  66. stream.pipe(send, meta);
  67. }
  68. }
  69. }
  70. });
  71. });
  72. function forEachClient(fn) {
  73. for (var id in bs.clients) {
  74. if (bs.clients.hasOwnProperty(id)) {
  75. var client = bs.clients[id];
  76. fn(client);
  77. }
  78. }
  79. }
  80. function notifyBuddiesX() {
  81. var locations = {};
  82. //group all clients by location (by public ip address)
  83. forEachClient(function(client) {
  84. var ip = client.hashedIp;
  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. };