ziron-server
Version:
1 lines • 8.34 kB
JavaScript
"use strict";var __awaiter=this&&this.__awaiter||function(e,t,s,i){return new(s||(s=Promise))((function(r,n){function o(e){try{a(i.next(e))}catch(e){n(e)}}function h(e){try{a(i.throw(e))}catch(e){n(e)}}function a(e){var t;e.done?r(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(o,h)}a((i=i.apply(e,t||[])).next())}))};Object.defineProperty(exports,"__esModule",{value:!0});const base64=require("base64id"),emitix_1=require("emitix"),ziron_errors_1=require("ziron-errors"),isIp=require("is-ip"),Utils_1=require("./Utils"),ziron_engine_1=require("ziron-engine"),MiddlewareUtils_1=require("./MiddlewareUtils"),Constants_1=require("./Constants");class Socket{setAuth(e,t){const s=this.authToken;this.authToken=e,this.signedAuthToken=t,this.authenticated=null!=e,s!==e&&this._emit("authTokenChange",e,s)}get handshakeAttachment(){return this.upgradeRequest.attachment}constructor(e,t){this.id=base64.generateId(),this.open=!0,this.signedAuthToken=null,this.authToken=null,this.authenticated=!1,this._emitter=new emitix_1.default,this.once=this._emitter.once.bind(this._emitter),this.on=this._emitter.on.bind(this._emitter),this.off=this._emitter.off.bind(this._emitter),this._emit=this._emitter.emit.bind(this._emitter),this.procedures={"#2":this._handleAuthenticateInvoke.bind(this),"#1":this._handleSubscribeInvoke.bind(this),"#0":this._handleClientPublishInvoke.bind(this)},this.onUnknownInvoke=Constants_1.EMPTY_FUNCTION,this.receivers={"#2":this._deauthenticate.bind(this),"#0":this._handleClientPublishTransmit.bind(this),"#1":this._handleUnsubscribeTransmit.bind(this)},this.onUnknownTransmit=Constants_1.EMPTY_FUNCTION,this.subscriptions=[],this._server=e,this._socket=t,this.upgradeRequest=t.req,this.remoteAddress=(0,Utils_1.tryGetClientIpFromHeaders)(this.upgradeRequest.headers)||Buffer.from(t.getRemoteAddressAsText()).toString(),this.remoteFamily=isIp.version(this.remoteAddress)||4,this._transport=new ziron_engine_1.Transport({send:this._sendRaw.bind(this),cork:this._cork.bind(this),onListenerError:e=>this._emitter.emit("error",e),onInvalidMessage:()=>this.disconnect(4400,"Bad message"),onInvoke:this._onInvoke.bind(this),onTransmit:this._onTransmit.bind(this),hasLowSendBackpressure:this.hasLowSendBackpressure.bind(this)},this._server.transportOptions,!0),this.transmit=this._transport.transmit.bind(this._transport),this.invoke=this._transport.invoke.bind(this._transport),this.sendPackage=this._transport.sendPackage.bind(this._transport),this.flushBuffer=this._transport.buffer.flushBuffer.bind(this._transport.buffer),this.getBufferSize=this._transport.buffer.getBufferSize.bind(this._transport.buffer),e.socketConstructorExtension(this)}bufferedSendAmount(){return this._socket.getBufferedAmount()}_emitClose(e,t){this._destroy(e||1001,t)}_emitMessage(e){this._transport.emitMessage(e)}_emitDrain(){this._transport.emitSendBackpressureDrain()}_cork(e){this._socket.cork(e)}_sendRaw(e,t,s){this._socket.send(e,t,this._server._shouldCompress(e,t,s))}_clearListener(){this._emitter.off()}_blockSocketInteractions(){this.transmit=Constants_1.NOT_OPEN_FAILURE_FUNCTION,this.invoke=Constants_1.NOT_OPEN_FAILURE_FUNCTION,this.sendPackage=Constants_1.NOT_OPEN_FAILURE_FUNCTION,this.bufferedSendAmount=Constants_1.NOT_OPEN_FAILURE_FUNCTION,this.hasLowSendBackpressure=Constants_1.NOT_OPEN_FAILURE_FUNCTION,this.join=Constants_1.NOT_OPEN_FAILURE_FUNCTION}_destroy(e,t){this.open=!1,this._transport.emitBadConnection(ziron_engine_1.BadConnectionType.Disconnect),this._transport.buffer.clearBuffer(),this._blockSocketInteractions(),this._emit("disconnect",e,t),this._server._emit("disconnection",this,e,t),ziron_errors_1.socketProtocolIgnoreStatuses[e]||this._emit("error",new ziron_errors_1.SocketProtocolError(ziron_errors_1.socketProtocolErrorStatuses[e]||"Socket connection closed with code: "+e+(t?` and message: ${t}.`:"."),e)),this._unsubscribeAll(),this._clearListener(),this._server._removeSocket(this)}isAuthTokenExpired(){return!(!this.authToken||null==this.authToken.exp)&&Date.now()>1e3*this.authToken.exp}_checkAuthTokenExpire(){this.isAuthTokenExpired()&&this.deauthenticate()}_deauthenticate(){this.authenticated&&this.setAuth(null,null)}deauthenticate(){this._deauthenticate(),this.transmit("#2")}authenticate(e,t){return __awaiter(this,void 0,void 0,(function*(){const s=yield this._server.auth.signToken(e,t);this.setAuth(e,s),this.transmit("#1",s)}))}disconnect(e,t){this.open&&this._socket.end(e||1e3,t)}hasLowSendBackpressure(){return this._socket.getBufferedAmount()<=this._server.lowSendBackpressureMark}_handleAuthenticateInvoke(e,t,s){return __awaiter(this,void 0,void 0,(function*(){try{yield this._processAuthToken(e,()=>t())}catch(e){s(e)}}))}_processAuthToken(e,t){return __awaiter(this,void 0,void 0,(function*(){try{const s=yield this._server.auth.verifyToken(e);this._server.authenticateMiddleware&&(yield this._server.authenticateMiddleware(this,s,e)),this.setAuth(s,e),t&&t()}catch(t){throw t instanceof Error&&t.badAuthToken&&this._server._emit("badSocketAuthToken",this,t,e),t}}))}_onInvoke(e,t,s,i,r){if(!this._server.ignoreFurtherInvokes){if(this._server.invokeMessageCount++,this.procedures[e])return this.procedures[e](t,s,i,r);this.onUnknownInvoke(e,t,s,i,r)}}_onTransmit(e,t,s){if(!this._server.ignoreFurtherTransmits){if(this._server.transmitMessageCount++,this.receivers[e])return this.receivers[e](t,s);this.onUnknownTransmit(e,t,s)}}kickOut(e,t){const s=this.subscriptions.indexOf(e);-1!==s&&(this._server._internalBroker.socketUnsubscribe(this,e),this.subscriptions.splice(s,1),this.transmit("#3",[e,t]))}_handleSubscribeInvoke(e,t,s){return __awaiter(this,void 0,void 0,(function*(){if("string"!=typeof e)return s(new ziron_errors_1.InvalidArgumentsError("Channel must be a string."));if(this._server._checkSocketChLimitReached(this.subscriptions.length))return s(new ziron_engine_1.InvalidActionError(`Socket ${this.id} tried to exceed the channel subscription limit of ${this._server.options.socketChannelLimit}`));if(this._server.subscribeMiddleware)try{yield this._server.subscribeMiddleware(this,e)}catch(e){return e instanceof MiddlewareUtils_1.Block?s(e):(this._server._emit("error",(0,Utils_1.ensureError)(e)),s(new MiddlewareUtils_1.Block(4403,"Subscribe was blocked by the subscribe middleware")))}this.subscriptions.includes(e)||(this._server._internalBroker.socketSubscribe(this,e),this.subscriptions.push(e)),t()}))}_handleUnsubscribeTransmit(e){return __awaiter(this,void 0,void 0,(function*(){if("string"==typeof e){const t=this.subscriptions.indexOf(e);-1!==t&&(this._server._internalBroker.socketUnsubscribe(this,e),this.subscriptions.splice(t,1))}}))}_unsubscribeAll(){const e=this.subscriptions.length;for(let t=0;t<e;t++)this._server._internalBroker.socketUnsubscribe(this,this.subscriptions[t]);this.subscriptions=[]}_handleClientPublishInvoke(e,t,s,i){return __awaiter(this,void 0,void 0,(function*(){if(!this._server.options.allowClientPublish)return t(4403);const r=(e=e||[])[0];if("string"!=typeof r)return s(new ziron_errors_1.InvalidArgumentsError("Channel must be a string."));if(this._server.publishInMiddleware)try{yield this._server.publishInMiddleware(this,r,e[1])}catch(e){return e instanceof MiddlewareUtils_1.Block?s(e):(this._server._emit("error",(0,Utils_1.ensureError)(e)),s(new MiddlewareUtils_1.Block(4403,"Publish was blocked by the publish in middleware")))}this._server._internalBroker.publish(r,e[1],0!==i,this),t()}))}_handleClientPublishTransmit(e,t){return __awaiter(this,void 0,void 0,(function*(){if(!this._server.options.allowClientPublish)return;const s=(e=e||[])[0];if("string"==typeof s){if(this._server.publishInMiddleware)try{yield this._server.publishInMiddleware(this,s,e[1])}catch(e){return void(e instanceof MiddlewareUtils_1.Block||this._server._emit("error",(0,Utils_1.ensureError)(e)))}this._server._internalBroker.publish(s,e[1],0!==t,this)}}))}publish(e,t,{processComplexTypes:s}={}){this._server._internalBroker.publish(e,t,s,this)}join(e){return this._socket.subscribe("G"+e)}hasJoined(e){return!!this.open&&this._socket.isSubscribed("G"+e)}leave(e){return!!this.open&&this._socket.unsubscribe("G"+e)}_terminate(){this.open&&this._socket.close(),this.open=!1,this._transport.buffer.clearBuffer(),this._blockSocketInteractions(),this._unsubscribeAll(),this._clearListener()}}exports.default=Socket;