UNPKG

decentralized-internet

Version:

An NPM library of programs to create decentralized web and distributed computing projects

1 lines 4.23 kB
"use strict";const path=require("path"),url=require("url"),util=require("util"),bodyParser=require("body-parser"),eventEmitter2=require("eventemitter2"),express=require("express"),flaschenpost=require("flaschenpost"),request=require("request"),requireAll=require("require-all"),sha1=require("sha1"),Endpoint=require("./Endpoint"),errors=require("./errors"),interval=require("./interval"),WellKnownPeers=require("./WellKnownPeers"),EventEmitter2=eventEmitter2.EventEmitter2,routes=requireAll(path.join(__dirname,"routes")),logger=flaschenpost.getLogger(),Peer=function(s){if(!s)throw new Error("Options are missing.");EventEmitter2.call(this,{wildcard:!0,delimiter:"::"}),this.protocol=s.protocol||"https",this.self=new Endpoint(s),this.metadata=s.metadata||{},this.successor=new Endpoint(s),this.predecessor=new Endpoint(s),this.successors=[],this.fingers=[],this.wellKnownPeers=new WellKnownPeers,this.wellKnownPeers.add(this.self),this.wellKnownPeers.add(s.wellKnownPeers||[]),this.handle={},this.app=express(),this.app.use(bodyParser.json()),this.app.post("/self",routes.self(this)),this.app.post("/status",routes.status(this)),this.app.post("/metadata",routes.metadata(this)),this.app.post("/successor",routes.successor(this)),this.app.post("/successors",routes.successors(this)),this.app.post("/predecessor",routes.predecessor(this)),this.app.post("/closest-preceding-finger",routes.closestPrecedingFinger(this)),this.app.post("/find-predecessor",routes.findPredecessor(this)),this.app.post("/find-successor",routes.findSuccessor(this)),this.app.post("/join",routes.join(this)),this.app.post("/notify",routes.notify(this)),this.app.post("/stabilize",routes.stabilize(this)),this.app.post("/fix-fingers",routes.fixFingers(this)),this.app.post("/fix-successors",routes.fixSuccessors(this)),this.app.post("/fix-predecessor",routes.fixPredecessor(this)),this.app.post("/handle/:action",routes.handle(this))};util.inherits(Peer,EventEmitter2),Peer.prototype.remote=function(s){if(!s)throw new Error("Target is missing.");if(!s.host)throw new Error("Host is missing.");if(!s.port)throw new Error("Port is missing.");return{run:(e,t,r)=>{if(!e)throw new Error("Function is missing.");if(!t)throw new Error("Callback is missing.");r||(r=t,t={});const i=url.format({protocol:this.protocol,hostname:s.host,port:s.port,pathname:e});request.post(i,{body:t,json:!0,keepAlive:!0},(s,o,n)=>{if(s)return r(s);if(o.resume(),200!==o.statusCode){const s={url:i,args:t,statusCode:o.statusCode,body:(n||"").trim("\n")};return logger.warn("Failed to call a remote function.",s),r(new errors.UnexpectedStatusCode(`Unexpected status code ${o.statusCode} when running ${e}.`,s))}r(null,n)})}}},Peer.prototype.setSuccessor=function(s){if(!s)throw new Error("Successor is missing.");const e=this.status();this.successor=new Endpoint({host:s.host,port:s.port}),this.emit("environment::successor",this.successor);const t=this.status();t!==e&&this.emit(`status::${t}`,{from:e,to:t})},Peer.prototype.setPredecessor=function(s){const e=this.status();this.predecessor=s?new Endpoint({host:s.host,port:s.port}):void 0,this.emit("environment::predecessor",this.predecessor);const t=this.status();t!==e&&this.emit(`status::${t}`,{from:e,to:t})},Peer.prototype.status=function(){return this.predecessor?this.self.id===this.successor.id&&this.self.id===this.predecessor.id?"lonely":this.self.id!==this.successor.id&&this.self.id!==this.predecessor.id?"joined":"unbalanced":"unbalanced"},Peer.prototype.fixSuccessor=function(){if(this.successors.shift(),0===this.successors.length)return this.setSuccessor({host:this.self.host,port:this.self.port});this.setSuccessor({host:this.successors[0].host,port:this.successors[0].port})},Peer.prototype.getEndpointFor=function(s,e){if(!s)throw new Error("Value is missing.");if(!e)throw new Error("Callback is missing.");this.remote(this.self).run("find-successor",{id:sha1(s)},(s,t)=>{if(s)return e(s);this.remote(t).run("metadata",(s,r)=>{if(s)return e(s);e(null,t,r)})})},Peer.prototype.isResponsibleFor=function(s){if(!s)throw new Error("Value is missing.");if(!this.predecessor)return!1;const e=sha1(s);return interval({left:this.predecessor.id,right:this.self.id,type:"leftopen"}).contains(e)},module.exports=Peer;