UNPKG

@iotize/tap

Version:

IoTize Device client for Javascript

218 lines (212 loc) 8.15 kB
import { ConnectionState, ComProtocol } from '@iotize/tap/protocol/api'; import { Subject, defer, of, throwError } from 'rxjs'; import { createDebugger } from '@iotize/common/debug'; import { promiseTimeout } from '@iotize/common/promise'; import { TaskQueue } from '@iotize/common/task-manager'; import { share, timeoutWith, tap, finalize, switchMap } from 'rxjs/operators'; const prefix = '@iotize/tap/protocol/common'; const debug = createDebugger(prefix); const TAG$1 = 'ComProtocol'; class AbstractComProtocol { constructor() { this.connectionState = ConnectionState.DISCONNECTED; this._options = { connect: { timeout: 1000, }, disconnect: { timeout: 1000, }, send: { timeout: 500, }, }; } get options() { return this._options; } set options(options) { this._options = options; } getConnectionState() { return this.connectionState; } isConnected() { return this.connectionState == ConnectionState.CONNECTED; } setConnectionState(connectionState) { debug(TAG$1, 'setConnectionState', ConnectionState[connectionState], 'Old: ', ConnectionState[this.connectionState]); let event = { newState: connectionState, oldState: this.connectionState, }; this.connectionState = connectionState; if (this._connectionStateChange) { this._connectionStateChange.next(event); } return this; } /** * Must be implemented in childs */ receiveStream() { throw new Error('Method not implemented.'); } onConnectionStateChange() { if (!this._connectionStateChange) { this._connectionStateChange = new Subject(); } return this._connectionStateChange; } } 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 = 'ComProtocol'; /** * */ class QueueComProtocol extends AbstractComProtocol { constructor() { super(); this._jobQueue = new TaskQueue(); } _send(data, options) { return defer(() => __awaiter(this, void 0, void 0, function* () { if (!this.isConnected()) { throw ComProtocol.Errors.notConnected({ protocol: this, }); } let startTime = new Date(); yield promiseTimeout(options.timeout, this.write(data), (info) => { return ComProtocol.Errors.timeoutError({ msg: `Communication timeout. Send request to device device timeout (${info.timeout}ms).`, protocol: this, timeout: info.timeout, startTime: info.startTime, }); }); let elapsedTime = new Date().getTime() - startTime.getTime(); let newTimeout = options.timeout - elapsedTime; const result = yield promiseTimeout(newTimeout, this.read(), (info) => { return ComProtocol.Errors.timeoutError({ msg: `Communication timeout. Read response from device timeout (${newTimeout}ms).`, protocol: this, timeout: newTimeout, startTime: info.startTime, }); }); return result; })).pipe(share()); } /** * Cancel pending requests */ cancel() { debug(TAG, `Canceling operations`); this._jobQueue.cancelAll(ComProtocol.Errors.operationCanceled()); } /** * * @param data * @param options */ send(data, options) { // debug(TAG, `QueueComProtocol`, `::send() ENQUEUE request (${data.length} bytes) ${toHexString(data)}. Queue position: ${this._queue.size}`); if (true) { // Copy data ? TODO can be removed ? data = data.slice(0); } return this._jobQueue.addExecutor(() => { let timeout = options ? options.timeout : this._options.send.timeout; return this._send(data, { timeout: timeout, }); }); } /** * Connect with timeout * * If connect has already been called or is in progress / no further action * * @param options */ connect(options) { if (this.connectionState === ConnectionState.CONNECTED) { debug(TAG, `QueueComProtocol is already connected`); return of(null); } if (this._connect$) { debug(TAG, `QueueComProtocol is already connecting...`); return this._connect$; } if (this._disconnect$) { return throwError(ComProtocol.Errors.operationInProgress(`Failed to connect as disconnection is in progress`)); } let connectTimeout = options ? options.timeout : this._options.connect.timeout; this._connect$ = defer(() => { this.setConnectionState(ConnectionState.CONNECTING); let startTime = new Date(); return this._connect(options).pipe(timeoutWith(connectTimeout, throwError(ComProtocol.Errors.timeoutError({ msg: 'Protocol connection timeout', protocol: this, timeout: connectTimeout, startTime: startTime, })))); }).pipe(tap({ complete: () => { this.setConnectionState(ConnectionState.CONNECTED); }, error: () => { this.setConnectionState(ConnectionState.DISCONNECTED); }, }), finalize(() => { this._connect$ = undefined; }), share()); return this._connect$; } disconnect(options) { if (this.connectionState === ConnectionState.DISCONNECTED) { debug(TAG, `QueueComProtocol is already disconnected`); return of(); } if (this._disconnect$) { return this._disconnect$; } if (this._connect$) { return throwError(ComProtocol.Errors.operationInProgress(`Failed to disconnect as connection is in progress`)); } let disconnectTimeout = options ? options.timeout : this._options.disconnect.timeout; this._disconnect$ = defer(() => __awaiter(this, void 0, void 0, function* () { this.setConnectionState(ConnectionState.DISCONNECTING); })).pipe(switchMap(() => { let startTime = new Date(); return this._disconnect(options).pipe(timeoutWith(disconnectTimeout, throwError(ComProtocol.Errors.timeoutError({ msg: 'Protocol disconnection timeout', protocol: this, timeout: disconnectTimeout, startTime: startTime, }))), finalize(() => { this.setConnectionState(ConnectionState.DISCONNECTED); this._disconnect$ = undefined; })); }), share()); return this._disconnect$; } } /** * Generated bundle index. Do not edit. */ export { AbstractComProtocol, QueueComProtocol }; //# sourceMappingURL=iotize-tap-protocol-core.js.map