UNPKG

networking

Version:

Library for typed, event-based networking between a server and clients.

158 lines (157 loc) 5.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const errors_1 = require("./errors"); class AuthQueue { constructor(socket) { this.socket = socket; this.resolutions = []; this.packets = []; this.terminated = false; this.resolutionPromises = []; this.packetPromises = []; this.terminatedPromises = []; socket.on('@net/auth', (packet) => this.handleAuthPacket(packet)); socket.on('@net/auth/res', (success) => this.handleResolutionPacket(success)); socket.on('@net/auth/term', () => this.handleTerminatePacket()); } handleAuthPacket(packet) { if (this.resolutionPromises.length) { if (this.packetPromises.length) { this.packetPromises.shift().reject(new errors_1.AuthError(`Authentication out of sequence (expected resolution, got a step)`)); } return; } if (this.packetPromises.length) { let promise = this.packetPromises.shift(); if (promise.type !== packet.type) { return promise.reject(new errors_1.AuthError(`Authentication out of sequence (expected ${promise.type}, got ${packet.type})`)); } promise.resolve(packet.payload); } else { this.packets.push(packet); } } handleResolutionPacket(success) { if (this.resolutionPromises.length) { let resolution = this.resolutionPromises.shift(); resolution.resolve(success); } else { this.resolutions.push(success); } } handleTerminatePacket() { // Set the terminated flag to true this.terminated = true; // Reject all resolution promises if (this.resolutionPromises.length) { this.resolutionPromises.forEach(promise => { promise.reject(new errors_1.AuthError('Authentication out of sequence (terminated early)')); }); } // Reject all packet promises if (this.packetPromises.length) { this.packetPromises.forEach(promise => { promise.reject(new errors_1.AuthError('Authentication out of sequence (terminated early)')); }); } // Resolve all termination promises if (this.terminatedPromises.length) { this.terminatedPromises.forEach(resolve => { resolve(); }); } // Clear this.resolutions = []; this.packets = []; this.packetPromises = []; this.resolutionPromises = []; this.terminatedPromises = []; // Remove listeners this.socket.removeAllListeners('@net/auth'); this.socket.removeAllListeners('@net/auth/res'); this.socket.removeAllListeners('@net/auth/term'); } /** * Resolves with the next authentication packet of the specified type. Throws an `AuthError` if we receive one of * a different type, or if the received authentication sequence doesn't match. * * @param type */ getPacket(type) { return new Promise((resolve, reject) => { if (this.resolutions.length) { return reject(new errors_1.AuthError(`Authentication out of sequence (expected ${type}, got a resolution)`)); } if (this.terminated) { return reject(new errors_1.AuthError(`Authentication out of sequence (authentication was terminated by the remote)`)); } if (this.packets.length) { let packet = this.packets.shift(); if (packet.type !== type) { return reject(new errors_1.AuthError(`Authentication out of sequence (expected ${type}, got ${packet.type})`)); } resolve(packet.payload); } else { this.packetPromises.push({ type, resolve, reject }); } }); } /** * Resolves with the next available resolution signal as a boolean. */ getResolution() { return new Promise((resolve, reject) => { if (this.terminated) { return reject(new errors_1.AuthError(`Authentication out of sequence (authentication was terminated by the remote)`)); } if (this.resolutions.length) { let resolution = this.resolutions.shift(); resolve(resolution); } else { this.resolutionPromises.push({ resolve, reject }); } }); } getTermination() { return new Promise(resolve => { if (this.terminated) { return resolve(); } this.terminatedPromises.push(resolve); }); } /** * Sends an authentication packet to the other side. * * @param type * @param payload */ sendPacket(type, payload) { if (this.terminated) { throw new errors_1.AuthError(`Cannot send packet (authentication was terminated by the remote)`); } this.socket.emit('@net/auth', { type, payload }); } /** * Sends an authentication packet to the other side. * * @param success */ sendResolution(success) { if (this.terminated) { throw new errors_1.AuthError(`Cannot send resolution (authentication was terminated by the remote)`); } this.socket.emit('@net/auth/res', success); } } exports.AuthQueue = AuthQueue;