wire.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. var Gun = require('../gun');
  2. /*
  3. An Ad-Hoc Mesh-Network Daisy-Chain
  4. should work even if humans are
  5. communicating with each other blind.
  6. To prevent infinite broadcast loops,
  7. we use a deduplication process
  8. based on the message's identifier.
  9. This is currently implemented in core.
  10. However, because this still creates a
  11. N*2 (where N is the number of connections)
  12. flood, it is not scalable for traditional
  13. services that have a hub network topology.
  14. Does this mean we have to abandon mesh
  15. algorithms? No, we can simply layer more
  16. efficient optimizations in based on constraints.
  17. If these constraints exist, it automatically
  18. upgrades, but if not, it falls back to the
  19. brute-force mesh based robust algorithm.
  20. A simple example is to limit peer connections
  21. and rely upon daisy chaining to relay messages.
  22. Another example, is if peers are willing to
  23. identify themselves, then we can improve the
  24. efficiency of the network by having each peer
  25. include the names of peers it is connected in
  26. each message. Then each subsequent peer will
  27. not relay it to them, since it is unnecessary.
  28. This should create N (where N is the number of
  29. peers) messages (or possibly N+ if there is a
  30. common peer of uncommon peers that receives it
  31. and relays at exact latency timings), which is
  32. optimal.
  33. Since computer networks aren't actually blind,
  34. we will implement the above method to improve
  35. the performance of the ad-hoc mesh network.
  36. But why not have every message contain the
  37. whole history of peers that it relayed through?
  38. Because in sufficiently large enough networks,
  39. with extensive daisy chaining, this will cause
  40. the message to become prohibitively slow and
  41. increase indefinitely in size.
  42. */
  43. Gun.on('opt', function(root){
  44. var opt = root.opt;
  45. if(false === opt.ws || opt.once){
  46. this.to.next(root);
  47. return;
  48. }
  49. var url = require('url');
  50. opt.mesh = opt.mesh || Gun.Mesh(root);
  51. opt.WebSocket = opt.WebSocket || require('ws');
  52. var ws = opt.ws = opt.ws || {};
  53. ws.path = ws.path || '/gun';
  54. // if we DO need an HTTP server, then choose ws specific one or GUN default one.
  55. if(!ws.noServer){
  56. ws.server = ws.server || opt.web;
  57. if(!ws.server){ this.to.next(root); return } // ugh, bug fix for @jamierez & unstoppable ryan.
  58. }
  59. ws.web = ws.web || new opt.WebSocket.Server(ws); // we still need a WS server.
  60. ws.web.on('connection', function(wire){ var peer;
  61. wire.upgradeReq = wire.upgradeReq || {};
  62. wire.url = url.parse(wire.upgradeReq.url||'', true);
  63. opt.mesh.hi(peer = {wire: wire});
  64. wire.on('message', function(msg){
  65. opt.mesh.hear(msg.data || msg, peer);
  66. });
  67. wire.on('close', function(){
  68. opt.mesh.bye(peer);
  69. });
  70. wire.on('error', function(e){});
  71. setTimeout(function heart(){ if(!opt.peers[peer.id]){ return } try{ wire.send("[]") }catch(e){} ;setTimeout(heart, 1000 * 20) }, 1000 * 20); // Some systems, like Heroku, require heartbeats to not time out. // TODO: Make this configurable? // TODO: PERF: Find better approach than try/timeouts?
  72. });
  73. this.to.next(root);
  74. });