|
/* |
|
Copyright (C) 2019 Simon Schmidt |
|
|
|
Usage of the works is permitted provided that this instrument is retained with |
|
the works, so that any entity that uses the works is notified of this instrument. |
|
|
|
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. |
|
*/ |
|
|
|
const hyperswarm = require('hyperswarm'); |
|
|
|
const NONE = []; |
|
|
|
const ESD_CONN = conncb=>(e,s,d)=>conncb(s,d,false) |
|
|
|
function peerid(peer) { |
|
return peer.topic.toString('base64'); |
|
} |
|
|
|
function HyperSwitch(hs) { |
|
if(!hs) hs = hyperswarm(); |
|
this.hs = hs; |
|
this.subscribed = {}; |
|
this.peer1 = {}; |
|
this.starin = {}; |
|
this.conn1 = {}; |
|
this._server = null; |
|
hs.on('connection',(socket,details)=>this._on_connection(socket,details)); |
|
hs.on('peer',(peer)=>this._on_peer(peer)); |
|
} |
|
HyperSwitch.prototype._consume_peer1 = function(pid,peer,socket,details) { |
|
if(!this.peer1[pid]) |
|
this.peer1[pid] = peer; |
|
const conn1 = this.conn1[pid]||NONE; |
|
if(conn1.length<1) return false; |
|
conn1.shift()(socket,details,true); |
|
for(const conncb of conn1) |
|
this.hs.connect(peer,ESD_CONN(conncb)); |
|
conn1.length=0; |
|
return true; |
|
}; |
|
HyperSwitch.prototype._on_connection = function(socket,details) { |
|
if(details.client) { |
|
const peer = details.peer |
|
const pid = peerid(peer); |
|
if(this._consume_peer1(pid,peer,socket,details)) |
|
return; |
|
if(this.starin[pid]) |
|
this.starin[pid](socket,details); |
|
} else { |
|
const srv = this._server; |
|
if(srv) srv(socket,details,true); |
|
} |
|
}; |
|
HyperSwitch.prototype._on_peer = function(peer) { |
|
const pid = peerid(peer); |
|
if(!this.peer1[pid]) this.peer1[pid] = peer; |
|
}; |
|
HyperSwitch.prototype.peer = function(topic,callback) { |
|
if(topic.length!=32) throw new Error("Malformed Topic: '"+topic.toString('base64')+"'"); |
|
const pid = topic.toString('base64'); |
|
if(this._server) throw new Error("Port already hooked up."); |
|
if(this.starin[pid]) throw new Error("Port already hooked up."); |
|
this.starin[pid] = callback; |
|
this._server = callback; |
|
this.hs.join(topic,{announce:true,lookup:true}); |
|
this.subscribed[pid] = true; |
|
}; |
|
HyperSwitch.prototype.listen = function(topic,callback) { |
|
if(topic.length!=32) throw new Error("Malformed Topic: '"+topic.toString('base64')+"'"); |
|
const pid = topic.toString('base64'); |
|
if(this._server) throw new Error("Port already hooked up."); |
|
this._server = callback; |
|
this.hs.join(topic,{announce:true,lookup:false}); |
|
this.subscribed[pid] = true; |
|
}; |
|
HyperSwitch.prototype._join = function(topic,pid) { |
|
if(!this.subscribed[pid]){ |
|
this.hs.join(topic,{announce:false,lookup:true}); |
|
this.subscribed[pid] = true; |
|
} |
|
}; |
|
HyperSwitch.prototype.joinAll = function(topic,conncb) { |
|
if(topic.length!=32) throw new Error("Malformed Topic: '"+topic.toString('base64')+"'"); |
|
const pid = topic.toString('base64'); |
|
if(this.subscribed[pid]) throw new Error("Port already hooked up."); |
|
if(this.starin[pid]) throw new Error("Port already hooked up."); |
|
this.starin[pid] = conncb; |
|
this._join(topic,pid); |
|
}; |
|
HyperSwitch.prototype.connect = function(topic,conncb) { |
|
if(topic.length!=32) throw new Error("Malformed Topic: '"+topic.toString('base64')+"'"); |
|
const pid = topic.toString('base64'); |
|
if(this.peer1[pid]) { |
|
this.hs.connect(this.peer1[pid],ESD_CONN(conncb)); |
|
return; |
|
} |
|
if(!this.conn1[pid]) this.conn1[pid] = []; |
|
this.conn1[pid].push(conncb); |
|
this._join(topic,pid); |
|
}; |
|
HyperSwitch.prototype.disconnect = function(topic) { |
|
if(topic.length!=32) throw new Error("Malformed Topic: '"+topic.toString('base64')+"'"); |
|
const pid = topic.toString('base64'); |
|
if(this.subscribed[pid]){ |
|
this.hs.leave(topic); |
|
delete this.subscribed[pid]; |
|
delete this.peer1[pid]; |
|
} |
|
}; |
|
// |
|
|
|
module.exports = {HyperSwitch}; |