Advertisement
Guest User

peer.js

a guest
Dec 6th, 2016
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. 'use strict';
  2.  
  3. const
  4.     events = require("events"),
  5.     dgram = require("dgram"),
  6.     ip = require("ip")
  7.  
  8. const DEFAULT_PORT = 4305;
  9.  
  10. function buffer2bytes(...buf) {
  11.     let s = "";
  12.     for(let b of buf) {
  13.         if(typeof b == 'number') {
  14.             s += String.fromCharCodes(b);
  15.         }
  16.         else if(typeof b == 'string') {
  17.             s += b;
  18.         }
  19.         else {
  20.             for(let c of b) {
  21.                 s += String.fromCharCode(c);
  22.             }
  23.         }
  24.     }
  25.    
  26.     return s;
  27. }
  28.  
  29. function* range(begin, end, incr=1) {
  30.     for(let i = begin; i < end; i += incr) {
  31.         yield i;
  32.     }
  33. }
  34.  
  35. function* broadcast_index_iter(n, m) {
  36.     if(m > n) {
  37.         let taken = new Array(m);
  38.        
  39.         for(let i = 0, j = m; i < n; ++i) {
  40.             let x = (Math.random()*m)|0;
  41.             yield taken.indexOf(x) < 0? taken[x] : x;
  42.             taken[x] = --j;
  43.         }
  44.     }
  45.     else {
  46.         yield* range(0, m);
  47.     }
  48. }
  49.  
  50. class CapMap {
  51.     constructor(limit) {
  52.         this.limit = limit;
  53.         this.keys = [];
  54.         this.vals = [];
  55.     }
  56.    
  57.     get(k, touch) {
  58.         let x = this.keys.indexOf(k), v = this.vals[x];
  59.         if(touch) {
  60.             this.keys.push(this.keys.splice(x, 1)[0]);
  61.             this.vals.push(this.vals.splice(x, 1)[0]);
  62.         }
  63.        
  64.         return v;
  65.     }
  66.    
  67.     set(k, v, touch) {
  68.         let x = this.keys.indexOf(k);
  69.         if(x == -1) {
  70.             if(this.keys.length < this.limit) {
  71.                 this.keys.push(k);
  72.                 this.vals.push(v);
  73.             }
  74.            
  75.             return;
  76.         }
  77.        
  78.         if(touch) {
  79.             this.keys.splice(x, 1);
  80.             this.vals.splice(x, 1);
  81.            
  82.             this.keys.push(k);
  83.             this.vals.push(v);
  84.         }
  85.         else {
  86.             this.keys[x] = k;
  87.             this.vals[x] = v;
  88.         }
  89.     }
  90. }
  91.  
  92. class Unaswarm extends events.EventEmitter {
  93.     constructor(config) {
  94.         let addrs = [], ports = [];
  95.         for(let p of (config.peers || [])) {
  96.             if(typeof p == "string") {
  97.                 addrs.push(p);
  98.                 ports.push(DEFAULT_PORT);
  99.             }
  100.             else {
  101.                 if(p.address) {
  102.                     addrs.push(p.address);
  103.                     ports.push(p.port);
  104.                 }
  105.             }
  106.         }
  107.        
  108.         this.addrs = addrs;
  109.         this.ports = ports;
  110.         this.limit = (config.peerlimit|0) || 256;
  111.         this.echo = (config.echo|0) || 12;
  112.         this.port = (config.port|0) || DEFAULT_PORT;
  113.        
  114.         this.sock = dgram.createSocket('udp6');
  115.        
  116.         this.sock.on('error', err => this.emit('error', err));
  117.         this.sock.on('message', (msg, rinfo) => {
  118.             if(msg.length == 0) return;
  119.            
  120.             if(msg[0] == 0) {
  121.                 /*
  122.                  * Unaswarm protocol v0 has packets with the following
  123.                  *  format:
  124.                  *
  125.                  * version intent payload
  126.                  */
  127.                 if(msg.length == 1) return;
  128.                
  129.                 switch(msg[1]) {
  130.                     case 0x3F: //?
  131.                         //"Hey buddy what do you know about..."
  132.                         what = 'query';
  133.                         break;
  134.                     case 0x21: //!
  135.                         //"What follows is an assertion"
  136.                         what = 'assert';
  137.                         break;
  138.                     case 0x1B: //~
  139.                         //"I don't want to be messaged"
  140.                         // Common use case: version unsupported
  141.                         this.removePeer(rinfo);
  142.                         return;
  143.                 }
  144.                
  145.                 let px = this.peerIndex(rinfo);
  146.                 if(px != -1) {
  147.                     this.addPeer(this.peers.splice(px, 1)[0]);
  148.                 }
  149.                
  150.                 this.emit(what, rinfo, msg.slice(2));
  151.             }
  152.             else {
  153.                 this.removePeer(rinfo);
  154.             }
  155.         });
  156.     }
  157.    
  158.     peerIndex(peer) {
  159.         let x = 0;
  160.         do {
  161.             x = this.addrs.indexOf(peer.address, x);
  162.         } while(this.ports[x] == peer.port);
  163.        
  164.         return x;
  165.     }
  166.    
  167.     addPeer(peer) {
  168.         if(this.peerIndex(peer) == -1) {
  169.             if(this.addrs.length > this.limit) {
  170.                 this.addrs.shift();
  171.                 this.ports.shift();
  172.             }
  173.             this.addrs.push(peer.address);
  174.             this.ports.push(peer.port);
  175.         }
  176.     }
  177.    
  178.     removePeer(addr, port) {
  179.         let px = this.peerIndex(peer);
  180.         if(px != -1) {
  181.             this.addrs.splice(px, 1);
  182.             this.ports.splice(px, 1);
  183.         }
  184.     }
  185.    
  186.     connect() {
  187.         this.sock.bind(this.port);
  188.     }
  189.    
  190.     query(payload) {
  191.         let msg = buffer2bytes('\0?', payload);
  192.        
  193.         for(let x of broadcast_iter(this.echo, this.addrs.length)) {
  194.             this.sock.send(msg, this.addrs[x], this.ports[x]);
  195.         }
  196.     }
  197.    
  198.     assert(to, payload) {
  199.         this.sock.send(buffer2bytes('\0!', payload), to.address, to.port);
  200.     }
  201. }
  202.  
  203. class Unamos extends events.EventEmitter {
  204.     constructor(config) {
  205.         this.procs = new CapMap((config.datalimit|0) || 1024);
  206.        
  207.         this.swarm = new Unaswarm(config);
  208.         this.swarm.on('error', err => this.emit('error', err));
  209.         this.swarm.on('query', (peer, data) => {
  210.             /*
  211.              * Unamos queries have the following payload format:
  212.              *  class [public] [address]
  213.              *   class - The resource's core type
  214.              *    - X = block (address)
  215.              *    - L = lambda count (public)
  216.              *    - m = soft memory (public address)
  217.              *    - M = hard memory (address)
  218.              *   public - Hash of the public key of a worker (byte[32])
  219.              *   address - Hash of the content of hard memory or an arbitrary
  220.              *    number referring to soft memory for a process (byte[32])
  221.              */
  222.             if(data.length == 0) return;
  223.            
  224.             let klass = data[0];
  225.            
  226.             data = data.slice(1);
  227.            
  228.             switch(data[0]) {
  229.                 case 0x23: //X
  230.                     break;
  231.                
  232.                 case 0x4C: //L
  233.                     if(data.length < 32) return;
  234.                    
  235.                     let lam = this.procs.get(
  236.                         buffer2bytes(data.slice(0, 32)), true
  237.                     );
  238.                    
  239.                     if(lam) {
  240.                         this.swarm.assert(peer,
  241.                             buffer2bytes("L", p
  242.                         lam.
  243.                    
  244.                     break;
  245.                
  246.                 case 0x6D: //m
  247.                     break;
  248.                
  249.                 case 0x4D: //M
  250.                     break;
  251.                
  252.                 default:
  253.                     return;
  254.             }
  255.         });
  256.         this.swarm.on('assert', (peer, data) => {
  257.            
  258.         });
  259.     }
  260.    
  261.    
  262. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement