UNPKG

@iotize/tap

Version:

IoTize Device client for Javascript

323 lines (317 loc) 12.7 kB
import { Buffer } from 'buffer'; import { Subject } from 'rxjs'; import { createDebugger } from '@iotize/common/debug'; import { bufferToHexString } from '@iotize/common/byte-converter'; import { CodeError } from '@iotize/common/error'; const prefix = '@iotize/tap/relay'; const debug = createDebugger(prefix); var __awaiter$1 = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 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) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; const TAG$1 = 'Relay'; class RelayServer { constructor(_server, params) { this._server = _server; this._params = params || { port: 2000, }; this._clients = []; } get server() { return this._server; } addClient(socket) { this._clients.push(socket); return this; } removeClient(client) { let index = this._clients.indexOf(client); if (index >= 0) { client.close(); debug(TAG$1, `Removing client ${client.getClientName()}...`); delete this._clients[index]; } return this; } start() { this._subscription = new Subject(); this._server .connections() .subscribe((socket) => __awaiter$1(this, void 0, void 0, function* () { // Identify this client let clientName = socket.getClientName(); debug(TAG$1, `[NEW_CLIENT] ${clientName}`); yield socket.ready(); debug(TAG$1, `[NEW_CLIENT] ${clientName} IS READY`); // Put this new client in the list this.addClient(socket); socket.events().subscribe({ next: (event) => { switch (event.type) { case 'data': let messageString = this.messageToLog(event.payload); debug(TAG$1, `[MESSAGE] ${messageString} from ${clientName}`); this.broadcastMessage(event.payload, socket); break; case 'error': debug(TAG$1, `[ERROR] ${clientName} `, event.payload); // Do we have to remove client every time ? this.removeClient(socket); break; case 'end': debug(TAG$1, `[CLIENTEND] ${clientName}`); this.removeClient(socket); break; } }, }); })); return this._server.listen(this._params); } stop() { return __awaiter$1(this, void 0, void 0, function* () { this._clients.forEach((client) => { client.close(); }); if (this._server) { yield this._server.stop(); } if (this._subscription) { this._subscription.complete(); } }); } broadcastMessage(message, sender) { let messageString = this.messageToLog(message); debug(TAG$1, `[BROADCAST] ${messageString} from ${sender.getClientName()}`); if (this._clients.length == 0) { debug(TAG$1, 'There is no client yet'); return; } // Send a message to all clients this._clients.forEach(function (client) { // Don't want to send it to sender try { if (client === sender) { debug(TAG$1, `\t- Skip sender ${client.getClientName()}`); return; } if (client.isWritable()) { debug(TAG$1, `\t- Sent to ${client.getClientName()}`); client.write(message); } else { debug(TAG$1, `Client ${client.getClientName()} is not writable. Cannot send to it`); } } catch (err) { debug(`Cannot broadcast to ${client.getClientName()}`, err); } }); } messageToLog(message) { if (typeof message === 'string') { return `"${message}"`; } else if (message instanceof Buffer) { return bufferToHexString(message); } else { return message; } } } var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 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) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; const TAG = 'Relay'; class ComRelayError extends CodeError { static illegalArgument(message) { return new ComRelayError(ComRelayError.Code.IllegalArgmentError, message); } constructor(code, msg) { super(msg, code); } } (function (ComRelayError) { let Code; (function (Code) { Code["IllegalArgmentError"] = "IllegalArgmentError"; })(Code = ComRelayError.Code || (ComRelayError.Code = {})); })(ComRelayError || (ComRelayError = {})); /** * This is an experimental feature. * * @experimental */ class ComRelay { // private IRelayCallback mCallback; // public final RelayServiceInfoModel mRelayInfo; // private DefaultSocketServer mSocketServer; // private WebSocketServer mWebSocketServer; /** * @param sourceProtocol protocol that will received commands * @param targetProtocol protocol on wich commmand will be sent */ constructor(sourceProtocol, targetProtocol) { if (sourceProtocol) { this.setSourceProtocol(sourceProtocol); } if (targetProtocol) { this.setTargetProtocol(targetProtocol); } } get sourceProtocol() { if (!this.mSourceProtocol) { throw ComRelayError.illegalArgument('Missing source protocol'); } return this.mSourceProtocol; } get targetProtocol() { if (!this.mTargetProtocol) { throw ComRelayError.illegalArgument('Missing target protocol'); } return this.mTargetProtocol; } setSourceProtocol(protocol) { if (this.mSourceProtocol) { this.removeSourceProtocol(); } this.mSourceProtocol = protocol; return this; } removeSourceProtocol() { if (this._sourceProtocolSubscription) { this._sourceProtocolSubscription.unsubscribe(); this._sourceProtocolSubscription = undefined; } this.mSourceProtocol = undefined; return this; } setTargetProtocol(protocol) { this.mTargetProtocol = protocol; return this; } start(options) { return __awaiter(this, void 0, void 0, function* () { return promiseTimout(options ? options.timeout || -1 : -1, (resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { if (!this.sourceProtocol.isConnected()) { debug(TAG, 'Connecting to source protocol...'); yield this.sourceProtocol.connect().toPromise(); } if (!this.targetProtocol.isConnected()) { debug(TAG, 'Connecting to target protocol...'); yield this.targetProtocol.connect().toPromise(); } debug(TAG, 'Source/Target are now connected. Listening to messages...'); // We need to reconnect this.listenToDataStream(); resolve(); } catch (ex) { reject(ex); } })); }); } /** * Stop relay and disconnect target and source protocol according to given options * @param options */ stop(options) { var _a, _b, _c, _d; if (!(options === null || options === void 0 ? void 0 : options.keepTargetProtocolConnected) && ((_a = this.mTargetProtocol) === null || _a === void 0 ? void 0 : _a.isConnected())) { (_b = this.mTargetProtocol) === null || _b === void 0 ? void 0 : _b.disconnect(); } if (!(options === null || options === void 0 ? void 0 : options.keepSourceProtocolConnected) && ((_c = this.mSourceProtocol) === null || _c === void 0 ? void 0 : _c.isConnected())) { (_d = this.mSourceProtocol) === null || _d === void 0 ? void 0 : _d.disconnect(); } } listenToDataStream() { // if (!this.mSourceProtocol!.isConnected()){ // await this.mSourceProtocol!.connect(); // } return new Promise((resolve, reject) => { if (!this.mSourceProtocol) { return reject(ComRelayError.illegalArgument(`Missing source protocol`)); } this._sourceProtocolSubscription = this.mSourceProtocol .receiveStream() .subscribe({ next: (data) => { if (!data) { debug(TAG, 'Received null event...'); return; } if (!this.mTargetProtocol) { debug(TAG, 'Target protocol is null. Cannot redirect message to it'); return; } try { debug(TAG, `Received new message`, bufferToHexString(data)); this.mTargetProtocol .send(data) .toPromise() .then((response) => { response = response || new Uint8Array(); debug(TAG, `Target protocol responded with: `, bufferToHexString(response)); return this.sourceProtocol.write(response); }) .then(() => { debug(TAG, `Successfully sent response!`); }) .catch((err) => { debug(TAG, `Cannot transfer response to source protocol: ${err} JSON=${JSON.stringify(err)}`, err); }); } catch (err) { debug(TAG, `Source cannot transfer data to target due to error: ${err}`, err); } }, error: (err) => { debug(TAG, `Error occured ${err}`); }, complete: () => { resolve(); }, }); }); } onStop() { // TODO cleanup return this; } } function promiseTimout(ms, callback) { return new Promise(function (resolve, reject) { debug(TAG, `promiseTimout start with ${ms} milliseconds`); // Set up the real work callback(resolve, reject); // Set up the timeout if (ms >= 0) { setTimeout(function () { reject('Promise timed out after ' + ms + ' ms'); }, ms); } }); } /** * Generated bundle index. Do not edit. */ export { ComRelay, ComRelayError, RelayServer }; //# sourceMappingURL=iotize-tap-relay-impl.js.map