UNPKG

@iotize/tap

Version:

IoTize Device client for Javascript

269 lines 16.4 kB
import { bufferToHexString } from '@iotize/common/byte-converter'; import { Subject, throwError } from 'rxjs'; import { map } from 'rxjs/operators'; import { TAP_REQUEST_FRAME_CONVERTER, TAP_RESPONSE_FRAME_CONVERTER, } from './converters'; import { debug } from './debug'; import { InterceptorChain } from './interceptors/interceptor-chain'; import { TapClientError } from './tap-client-error'; import { TapRequestHelper } from './request/tap-request-helper'; const TAG = 'Client'; export class TapClient { constructor(requestEncoder, responseDecoder) { this._onProtocolChange = new Subject(); this._commandEncoder = requestEncoder; this._responseDecoder = responseDecoder; this.protocols = {}; this._interceptorChain = new InterceptorChain((context) => { try { const command = context.request; // const bodyDecoder = context.bodyDecoder; return this._command(command); } catch (err) { return throwError(err); } }); } static create(protocol) { const client = new TapClient(TAP_REQUEST_FRAME_CONVERTER, TAP_RESPONSE_FRAME_CONVERTER); if (protocol) { client.addComProtocol(protocol); } return client; } // public isEncryptionEnabled(): boolean { // return this._options.encryption; // } // public get cryptedFrameConverter() { // return this._cryptedFrameConverter; // } get interceptorChain() { return this._interceptorChain; } addInterceptor(interceptor) { this.interceptorChain.addInterceptor(interceptor); return this; } // /** // * Enable/Disable encrytion when communicating with a device // * @param value true if requests must be encrypted // * @param algo optional if you have already provided the algo with @{link setEncryptionAlgo(algo)} method // */ // public enableEncryption(value: boolean, algo?: EncryptionAlgo): Promise<any> { // if (value) { // algo = algo || this._encryptionAlgo; // if (!algo) { // return Promise.reject( // TapClientError.illegalArgument( // 'Illegal argument, encryption algo must be set' // ) // ); // } // return this._startEncryption(algo); // } // else { // return this._stopEncryption(); // } // } isConnected() { return (this.hasProtocol(this.currentProtocolId) && this.getCurrentProtocol().isConnected()); } /** * see {@link getCurrentProtocol} */ get protocol() { return this.getCurrentProtocol(); } get commandEncoder() { return this._commandEncoder; } get responseDecoder() { return this._responseDecoder; } /** * Get current protocol or throw an error if no protocol */ getCurrentProtocol() { if (!this.currentProtocolId) { throw TapClientError.illegalStateError('Tap client protocol is required'); } if (!this.hasProtocol(this.currentProtocolId)) { throw TapClientError.illegalArgument('Protocol ' + this.currentProtocolId + ' does not exist'); } return this.protocols[this.currentProtocolId]; } /** * Register/replace a communication protocol with given id * If no communication protocol is selected yet, it will select it. * @param newProtocol * @param id */ addComProtocol(newProtocol, id = 'default') { this.protocols[id] = newProtocol; if (!this.currentProtocolId) { this.currentProtocolId = id; } return this; } /** * Switch to given communication protocol identifier * @throws if protocol identifier does not exist * @param name */ switchProtocol(name) { if (!this.hasProtocol(name)) { throw TapClientError.illegalArgument('Unkonwn protocol: ' + name); } const oldProtocol = this.getCurrentProtocol(); this.currentProtocolId = name; debug(TAG, `Changing protocol to: ${name}`); this._onProtocolChange.next({ newProtocol: this.getCurrentProtocol(), oldProtocol, }); return this; } /** * Change communication protocol * @throws if protocol identifier does not exist * @param protocol can either be the communication protocol instance or a string identifier */ useComProtocol(protocol) { let protocolId; if (typeof protocol == 'string') { protocolId = protocol; } else { protocolId = protocol.constructor.name; this.addComProtocol(protocol, protocolId); } this.switchProtocol(protocolId); return this; } /** * Return true if protocol identifier is registered * @param id */ hasProtocol(id) { return id in this.protocols; } connect() { try { return this.getCurrentProtocol().connect(); } catch (err) { return throwError(err); } } disconnect() { try { return this.getCurrentProtocol().disconnect(); } catch (err) { return throwError(err); } } /** * Send request * @param request * @param bodyDecoder */ request(request) { return this._interceptorChain.execute({ // bodyDecoder, request, client: this, }); } /** * Send raw request * No interceptors/No encryption will be triggered * @param dataIn request bytes * @param bodyDecoder optional body decoder to use */ send(dataIn) { try { return this.getCurrentProtocol() .send(dataIn) .pipe(map((result) => { // debug( // TAG, // 'Received result: ', // bufferToHexString(result), // 'DECODER: ', // bodyDecoder ? bodyDecoder.constructor.name : 'NO' // ); try { return this._responseDecoder.decode(result); } catch (err) { throw TapClientError.decodeResponseError(err, dataIn); } })); } catch (err) { return throwError(err); } } /** * Listen to connection state change event * We have to resubscribe when protocol change.. */ onConnectionStateChange() { try { return this.getCurrentProtocol().onConnectionStateChange(); } catch (err) { return throwError(err); } } onProtocolChange() { try { return this._onProtocolChange.asObservable(); } catch (err) { return throwError(err); } } _command(command) { try { if (!this.isConnected()) { return throwError(TapClientError.notConnectedError()); } let dataIn; try { dataIn = this._commandEncoder.encode(command); } catch (e) { return throwError(TapClientError.encodeRequestError(command, e)); } debug(TAG, `Sending ${TapRequestHelper.toString(command)} (${dataIn.length} bytes 0x${bufferToHexString(dataIn)})`); return this.getCurrentProtocol() .send(dataIn) .pipe(map((result) => { // debug( // TAG, // 'Received result: ', // bufferToHexString(result), // 'DECODER: ', // bodyDecoder ? bodyDecoder.constructor.name : 'NO' // ); try { const response = this._responseDecoder.decode(result); // if (bodyDecoder) { // response.setBodyDecoder(bodyDecoder); // } return response; } catch (err) { throw TapClientError.decodeResponseError(err, command); } })); } catch (err) { return throwError(err); } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL2NsaWVudC9pbXBsL3NyYy9saWIvdGFwLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQWNsRSxPQUFPLEVBQWMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN2RCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFckMsT0FBTyxFQUNMLDJCQUEyQixFQUMzQiw0QkFBNEIsR0FDN0IsTUFBTSxjQUFjLENBQUM7QUFDdEIsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNoQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUNwRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDcEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFFaEUsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDO0FBRXJCLE1BQU0sT0FBTyxTQUFTO0lBbUJwQixZQUNFLGNBQW9ELEVBQ3BELGVBQXNEO1FBbEJoRCxzQkFBaUIsR0FBRyxJQUFJLE9BQU8sRUFBdUIsQ0FBQztRQW9CN0QsSUFBSSxDQUFDLGVBQWUsR0FBRyxjQUFjLENBQUM7UUFDdEMsSUFBSSxDQUFDLGdCQUFnQixHQUFHLGVBQWUsQ0FBQztRQUN4QyxJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQztRQUNwQixJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxnQkFBZ0IsQ0FDM0MsQ0FBQyxPQUF5QixFQUFFLEVBQUU7WUFDNUIsSUFBSTtnQkFDRixNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDO2dCQUNoQywyQ0FBMkM7Z0JBQzNDLE9BQU8sSUFBSSxDQUFD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