OverviewFilesCommitsIssuesDocsReleasesPeers

holepunchto-deps / @holepunchto / call-swarm / lib / connection.js

1 lines · javascript ref:
const{EventEmitter:e}=require("events"),s=require("./errors"),{encodeHandshake:t,decodeHandshake:i}=require("./messages"),r=new Set(["HOLEPUNCH_ABORTED","HOLEPUNCH_DOUBLE_RANDOMIZED_NATS","CANNOT_HOLEPUNCH","REMOTE_NOT_HOLEPUNCHABLE"]);module.exports=class extends e{constructor(e,s,t){super(),this.peer=s,this.swarm=e,this.stream=t,this.timestamp=0,this.remoteTimestamp=0,this.silentTicks=0,this.remotePacketsReceived=0,this.error=null,this.closed=!1,this.established=!1,this._tickTimer=null,this._establishTimer=null,this.stream.on("error",this._handleError.bind(this)),this.stream.on("close",this._handleClose.bind(this)),this._open()}internalDestroy(e){this.closed||this.stream.destroying||(this.error=e,this.stream.destroy(e))}async _doOpen(){if(this._sendHandshake(),!await this._waitForOpen())return;this._startLiveness();const e=await this._readHandshake();null!==e&&this._establish(e)}async _open(){try{await this._doOpen()}catch(e){this.internalDestroy(e)}}async _waitForOpen(){const e=await this.stream.opened;return!(this.closed||!1===e||(this.swarm.destroyed||this.swarm.suspended)&&(this.internalDestroy(s.Suspended()),1))}_sendHandshake(){this.timestamp=this.swarm.internalNextTimestamp(),this.stream.write(t(this.timestamp))}_startLiveness(){this.stream.setKeepAlive(this.swarm.timings.keepAlive),this.remotePacketsReceived=this.stream.rawStream.packetsReceived,this._tickTimer=setInterval(this._tick.bind(this),this.swarm.timings.livenessTick)}async _readHandshake(){this._establishTimer=setTimeout(()=>this.internalDestroy(s.EstablishTimeout()),this.swarm.timings.establishTimeout);const e=await this._readMessage();if(clearTimeout(this._establishTimer),this._establishTimer=null,null===e)return null;const t=i(e);return null===t&&this.internalDestroy(s.BadHandshake()),t}async _readMessage(){try{const{value:e}=await this.stream[Symbol.asyncIterator]().next();return e}catch{return null}}_establish(e){this.established=!0,this.remoteTimestamp=e.timestamp,this.emit("established")}_tick(){if(this.closed)return;const e=this.stream.rawStream.packetsReceived;if(e!==this.remotePacketsReceived)return this.silentTicks=0,void(this.remotePacketsReceived=e);const t=this.swarm.timings;++this.silentTicks*t.livenessTick<t.idleTimeout||this.internalDestroy(s.IdleTimeout())}_handleError(e){this.swarm.relaying&&r.has(e.code)&&(this.peer.attempts=0,this.peer.forceRelaying=!0)}_handleClose(){this.closed||(this.closed=!0,null!==this._tickTimer&&clearInterval(this._tickTimer),null!==this._establishTimer&&clearTimeout(this._establishTimer),this._tickTimer=null,this._establishTimer=null,this.emit("close"))}};