"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); var packet_1 = require("./packet"); var utils_1 = require("./utils"); var error_1 = require("./error"); var clientError = 400; var Client = (function () { function Client(url, readyStateCallback) { this.listeners = new Map(); this.requestHeader = ''; this.requestHeader = ''; this._maxPayload = 1024 * 1024; this.url = url; this.reconnectTimes = 0; this.readyStateCallback = readyStateCallback; this._enableLogger = false; this.socket = this.connect(); } Object.defineProperty(Client.prototype, "maxPayload", { get: function () { return this._maxPayload; }, set: function (maxPayload) { this._maxPayload = maxPayload; }, enumerable: true, configurable: true }); Object.defineProperty(Client.prototype, "enableLogger", { get: function () { return this._enableLogger; }, set: function (enableLogger) { this._enableLogger = enableLogger; }, enumerable: true, configurable: true }); Client.prototype.ping = function (param) { return __awaiter(this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { return [2, new Promise(function (resolve, reject) { if (_this.socket.readyState !== _this.socket.OPEN) { if (_this._enableLogger) { console.log('[ping]: connection refuse'); } reject(new error_1.WebsocketError(clientError, 'connection refuse')); } var heartbeatOperator = 0; _this.listeners.set(heartbeatOperator, function (data) { var code = _this.getResponseProperty('code'); if (code !== '') { var message = _this.getResponseProperty('message'); reject(new error_1.WebsocketError(Number(code), message)); } else { resolve(data); } }); var p = new packet_1.Packet(); _this.send(p.pack(heartbeatOperator, 0, _this.requestHeader, JSON.stringify(param))); if (_this._enableLogger) { console.info('[send data packet]', heartbeatOperator, 0, _this.requestHeader, param); } })]; }); }); }; Client.prototype.request = function (operator, param) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4, this.asyncSend(operator, param)]; case 1: return [2, _a.sent()]; } }); }); }; Client.prototype.addMessageListener = function (operator, listener) { this.listeners.set(utils_1.Utils.crc32(operator), listener); }; Client.prototype.removeMessageListener = function (operator) { delete this.listeners[utils_1.Utils.crc32(operator)]; }; Object.defineProperty(Client.prototype, "readyState", { get: function () { return this.socket.readyState; }, enumerable: true, configurable: true }); Client.prototype.setRequestProperty = function (key, value) { var v = this.getRequestProperty(key); this.requestHeader = this.requestHeader.replace(key + '=' + v + ';', ''); this.requestHeader = this.requestHeader + key + '=' + value + ';'; }; Client.prototype.getRequestProperty = function (key) { if (this.requestHeader !== undefined) { var values = this.requestHeader.split(';'); for (var index in values) { var kv = values[index].split('='); if (kv[0] === key) { return kv[1]; } } } return ''; }; Client.prototype.setResponseProperty = function (key, value) { var v = this.getResponseProperty(key); this.responseHeader = this.responseHeader.replace(key + '=' + v + ';', ''); this.responseHeader = this.responseHeader + key + '=' + value + ';'; }; Client.prototype.getResponseProperty = function (key) { if (this.responseHeader !== undefined) { var values = this.responseHeader.split(';'); for (var index in values) { var kv = values[index].split('='); if (kv[0] === key) { return kv[1]; } } } return ''; }; Client.prototype.connect = function () { var _this = this; var readyStateCallback = this.readyStateCallback; var ws = new WebSocket(this.url); ws.binaryType = 'blob'; ws.onopen = function (ev) { if (_this._enableLogger) { console.info('[websocket] open connection'); } _this.reconnectTimes = 0; readyStateCallback.onOpen(ev); }; ws.onclose = function (ev) { if (_this._enableLogger) { console.info('[websocket] close connection'); } _this.reconnect(); readyStateCallback.onClose(ev); }; ws.onerror = function (ev) { if (_this._enableLogger) { console.info('[websocket] error'); } _this.reconnect(); readyStateCallback.onError(ev); }; ws.onmessage = function (ev) { if (ev.data instanceof Blob) { var reader_1 = new FileReader(); reader_1.readAsArrayBuffer(ev.data); reader_1.onload = function () { try { var packet = new packet_1.Packet().unPack(reader_1.result); var packetLength = packet.headerLength + packet.bodyLength + 20; if (packetLength > _this._maxPayload) { throw new Error('the packet is big than ' + _this._maxPayload); } var operator = Number(packet.operator) + Number(packet.sequence); if (_this.listeners.has(operator)) { if (packet.body === '') { packet.body = '{}'; } _this.responseHeader = packet.header; _this.listeners.get(operator)(JSON.parse(packet.body)); } if (_this._enableLogger) { if (operator !== 0 && packet.body !== 'null') { console.info('receive data packet', packet.body); } } } catch (e) { throw new Error(e); } }; } else { throw new Error('unsupported data format'); } }; return ws; }; Client.prototype.reconnect = function () { var _this = this; if (!this.reconnectLock) { this.reconnectLock = true; if (this._enableLogger) { console.info('websocket reconnect in ' + this.reconnectTimes + 's'); } setTimeout(function () { _this.reconnectTimes++; _this.socket = _this.connect(); _this.reconnectLock = false; }, this.reconnectTimes * 1000); } }; Client.prototype.send = function (data) { if (this.socket.readyState !== this.socket.OPEN) { if (this._enableLogger) { console.error('[send] WebSocket is already in CLOSING or CLOSED state.'); } return; } try { this.socket.send(data); } catch (e) { throw new Error('send data error' + e); } }; Client.prototype.asyncSend = function (operator, param) { var _this = this; return new Promise(function (resolve, reject) { if (_this.socket.readyState !== _this.socket.OPEN) { if (_this._enableLogger) { console.log('[ping]: connection refuse'); } reject(new error_1.WebsocketError(clientError, 'asyncSend: connection refuse')); } var sequence = new Date().getTime(); var listener = utils_1.Utils.crc32(operator) + sequence; _this.listeners.set(listener, function (data) { var code = _this.getResponseProperty('code'); if (code !== '') { var message = _this.getResponseProperty('message'); reject(new error_1.WebsocketError(Number(code), message)); } else { resolve(data); } delete _this.listeners[listener]; }); var p = new packet_1.Packet(); _this.send(p.pack(utils_1.Utils.crc32(operator), sequence, _this.requestHeader, JSON.stringify(param))); if (_this._enableLogger) { console.info('[send data packet]', operator, sequence, _this.requestHeader, param); } }); }; return Client; }()); exports.Client = Client; var client; function getClient(url, callback) { if (!client) { client = new Client(url, callback); } return client; } exports.getClient = getClient;