UNPKG

@iotize/tap

Version:

IoTize Device client for Javascript

218 lines 17 kB
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()); }); }; import { chunkArray } from '@iotize/common/array'; import { bufferToHexString } from '@iotize/common/byte-converter'; import { TapRequestFrame, } from '@iotize/tap/client/api'; import { TapRequestFrameBuilder } from '@iotize/tap/client/impl'; import { Observable, defer } from 'rxjs'; import { first } from 'rxjs/operators'; import { PathParameter } from './path-parameter'; import { TapResponse } from './response-impl'; import { TapError } from './tap-errors'; export function serviceCallToString(call, options) { function printObject(obj) { if (obj instanceof Uint8Array) { return '0x' + bufferToHexString(obj); } else if (typeof obj === 'object') { return ('{' + Object.keys(obj) .map((key) => `"${key}":${printObject(obj[key])}`) .join(',') + '}'); } else { return JSON.stringify(obj); } } const lwm2mPath = ServiceCallRunner.resolvePathParameters(call); const pathAlias = call.pathAlias ? PathParameter.fillAllParams(call.pathAlias, call.pathParameters || {}) : undefined; let result = `${TapRequestFrame.MethodType[call.method]} ${pathAlias || lwm2mPath}`; if (call.pathAlias) { result += ` (${lwm2mPath})`; } if (!(options === null || options === void 0 ? void 0 : options.skipBody) && call.body !== undefined) { result += ' ' + printObject(call.body); } return result; } export class ServiceCallRunner { constructor(client, options = { chunkSize: 220, }) { this.client = client; this.options = options; } get(path, body) { return this.execute({ method: TapRequestFrame.MethodType.GET, path, body, }); } put(path, body) { return this.execute({ method: TapRequestFrame.MethodType.PUT, path, body, }); } post(path, body) { return this.execute({ method: TapRequestFrame.MethodType.POST, path, body, }); } prepare(call) { return defer(() => __awaiter(this, void 0, void 0, function* () { const tapRequestFrame = ServiceCallRunner.toTapRequest(call); // const debugArgs: string[] = [`CALL: ${call.method} ${call.path} body=`]; // debugArgs.push( // call.body instanceof Uint8Array // ? bufferToHexString(call.body) // : call.body // ); // debugArgs.push(`(${args[0].toString()})`); try { const tapResponseFrame = yield this.client .request(tapRequestFrame) .toPromise(); if (!tapResponseFrame) { throw new Error(`No Tap response`); } const response = new TapResponse(tapResponseFrame, tapRequestFrame); const responseBodyDecoder = ServiceCallRunner.resolveResponseBodyDecoder(call); if (responseBodyDecoder) { response.setBodyDecoder({ decode: responseBodyDecoder, }); } if (!response.isSuccessful()) { response.setError(TapError.reponseStatusError(response, call)); } return response; } catch (err) { if (!(err instanceof TapError)) { throw TapError.executeRequestError(call, err); } throw err; } })); // return response$.pipe( // tap( // response => { // debug(this.constructor.name, ...debugArgs, '=>', response.toString()); // }, // err => { // debug(this.constructor.name, ...debugArgs, ` => ${err.message}`); // } // ) // ); } execute(call) { return this.prepare(call).pipe(first()).toPromise(); } createAppendCalls(call, chunkSize = this.options.chunkSize) { const chunks = chunkArray(Array.from(call.body || new Uint8Array()), chunkSize).map((chunk, index) => { return Object.assign(Object.assign({}, call), { body: Uint8Array.from(chunk) }); }); return chunks; } prepareAppendCall(call, chunkSize = this.options.chunkSize) { return new Observable((emitter) => { let isCancelled = false; (() => __awaiter(this, void 0, void 0, function* () { try { const calls = this.createAppendCalls(call, chunkSize); let index = 0; let byteOffset = 0; for (const call of calls) { if (isCancelled) { return; } const chunk = call.body; const progress = { total: chunk.length, loaded: index + 1, byteOffset, }; emitter.next(progress); const response = yield this.execute({ method: call.method || TapRequestFrame.MethodType.PUT, path: call.path, body: chunk, }); try { response.successful(); } catch (err) { throw TapError.appendChunkError(err, chunk, progress); } byteOffset += chunk.length; index++; } emitter.complete(); } catch (err) { emitter.error(err); return; } }))(); return () => { // TODO throw error on cancel isCancelled = true; }; }); } static toTapRequest(call) { const path = ServiceCallRunner.resolvePathParameters(call); const body = ServiceCallRunner.encodeBody(call); return TapRequestFrameBuilder.create(call.method, path, body); } static resolveResponseBodyDecoder(call) { if (call.responseBodyDecoder) { return toDecoderFunction(call.responseBodyDecoder); } return undefined; } static resolvePathParameters(info) { return PathParameter.fillAllParams(info.path, info.pathParameters || {}); } /** * Encode body according to options and configuration */ static encodeBody(options) { if (options.body === undefined) { return undefined; } const encoded = options.bodyEncoder ? toEncoderFunction(options.bodyEncoder)(options.body) : options.body; if (encoded !== undefined && !(encoded instanceof Uint8Array)) { throw TapError.invalidServiceCallConfiguration(`Request body encoder is required for call to ${serviceCallToString(options)}`); } return encoded; } } function toEncoderFunction(classOrFunction) { return typeof classOrFunction === 'function' ? classOrFunction : classOrFunction.encode.bind(classOrFunction); } function toDecoderFunction(classOrFunction) { return typeof classOrFunction === 'function' ? classOrFunction : classOrFunction.decode.bind(classOrFunction); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS1jYWxsLXJ1bm5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc2VydmljZS1jYWxsLXJ1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFHbEUsT0FBTyxFQUlMLGVBQWUsR0FDaEIsTUFBTSx3QkFBd0IsQ0FBQztBQUNoQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN6QyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHdkMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBV3hDLE1BQU0sVUFBVSxtQkFBbUIsQ0FDakMsSUFBK0IsRUFDL0IsT0FFQztJQUVELFNBQVMsV0FBVyxDQUFDLEdBQVE7UUFDM0IsSUFBSSxHQUFHLFlBQVksVUFBVSxFQUFFO1lBQzdCLE9BQU8sSUFBSSxHQUFHLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3RDO2FBQU0sSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLEVBQUU7WUFDbEMsT0FBTyxDQUNMLEdBQUc7Z0JBQ0gsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7cUJBQ2IsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLEdBQUcsS0FBSyxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztx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