@iotize/tap
Version:
IoTize Device client for Javascript
218 lines • 17 kB
JavaScript
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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