@iotize/tap-scripts
Version:
IoTize Tap scripts
312 lines • 19.6 kB
JavaScript
"use strict";
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScriptRunner = exports.DisplayToLogFunction = exports.OutputToLogFunction = exports.TestRunnerContext = void 0;
const byte_converter_1 = require("@iotize/common/byte-converter");
const rxjs_1 = require("rxjs");
const errors_1 = require("./errors");
const instructions_1 = require("./instructions");
const logger_1 = require("./logger");
/**
*
*/
class TestRunnerContext {
constructor(device, instructions, io) {
this.device = device;
this.instructions = instructions;
this.io = io;
this._labels = {};
this.current = -1;
this.resultCode = null;
this._data = {};
this._running = false;
this.nextChanged = false;
this.errorHandler = (error) => {
throw error;
};
this.instructions.forEach((instruction, index) => {
if (instruction instanceof instructions_1.LabelInstruction) {
this.mapLabel(instruction.name, index);
}
});
}
store(key, value) {
if (arguments.length === 2) {
this._data[key] = value;
}
else {
return this._data[key];
}
}
get labels() {
return this._labels;
}
set lastLwm2mGetResponse(r) {
this._lastLwm2mGetResponse = r;
this.lastLwm2mResponse = r;
}
get lastLwm2mGetResponse() {
if (!this._lastLwm2mGetResponse) {
throw new Error(`No last LWM2M get response available yet`);
}
return this._lastLwm2mGetResponse;
}
// asObservable() {
// return this._observer!.asObservable(); // TODO fix
// }
/**
* Resume script execution
*/
continue() {
return __awaiter(this, void 0, void 0, function* () {
this._running = true;
while (this._running && !this.isEnded()) {
if (!this.nextChanged) {
this.current++;
}
this.nextChanged = false;
yield this.safeRunOne(this.current);
}
this._running = false;
});
}
runAll() {
return new rxjs_1.Observable((observer) => {
this._observer = observer;
this.resultCode = null;
this.current = -1;
this.continue()
.then(() => [this._observer, undefined])
.catch((err) => [this._observer, err])
.then(([observer, err]) => {
this._observer = undefined;
if (!err) {
observer === null || observer === void 0 ? void 0 : observer.complete();
}
else {
observer === null || observer === void 0 ? void 0 : observer.error(err);
}
});
return () => {
this._observer = undefined;
this.stop();
};
});
}
isRunning() {
return this._running;
}
/**
* Pause script execution
*/
stop() {
this._running = false;
}
/**
* Return true script execution is finished
*/
isEnded() {
return (this.resultCode !== null || this.current >= this.instructions.length);
}
getCurrentIndex() {
return this.current;
}
setNextIndex(index) {
(0, logger_1.debug)(`TestRunnerContext`, `Jumping to index: ${index}`);
this.current = index;
this.nextChanged = true;
}
runCurrent() {
return this.safeRunOne(this.current);
}
/**
* Run instruction at given index
* @param index
*/
runOne(index) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
this.current = index;
// debug(`next on instruction ${index}/${this.instructions.length}`);
if (index < this.instructions.length) {
const instruction = this.instructions[index];
if (!instruction) {
throw errors_1.ScriptError.internalError(`Instruction should not be null at index ${index}`);
}
(0, logger_1.debug)(`Running instruction ${index + 1}/${this.instructions.length}: ${instruction.constructor.name} (${instruction.toString()})`);
const progressInfo = {
loaded: index,
total: this.instructions.length
};
(_a = this._observer) === null || _a === void 0 ? void 0 : _a.next({
type: 'before',
instruction: instruction,
progress: progressInfo
});
const result = instruction.run(this);
let promise;
if (result instanceof Promise) {
promise = result;
}
else {
promise = Promise.resolve(result);
}
return promise.then(res => {
var _a;
(_a = this._observer) === null || _a === void 0 ? void 0 : _a.next({
type: 'after',
instruction: instruction,
progress: progressInfo,
result: result
});
return res;
});
}
else {
this.end();
return Promise.resolve();
}
});
}
next() {
return __awaiter(this, void 0, void 0, function* () {
const result = yield this.safeRunOne(this.current + 1);
this.next();
});
}
/**
* TODO use result code
*/
end(resultCode = 0) {
var _a;
if (typeof resultCode !== 'number') {
throw errors_1.ScriptError.internalError(`result code should be a number. Given: "${resultCode}" (type=${typeof resultCode})`);
}
this.resultCode = resultCode;
(0, logger_1.debug)(`Ending script with result code ${resultCode}`);
(_a = this._observer) === null || _a === void 0 ? void 0 : _a.next({
type: 'end',
resultCode: resultCode,
progress: {
total: this.instructions.length,
loaded: this.instructions.length
}
});
}
onError(err) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
// debug('ScriptRunner', `An error occured`, err);
try {
if (!this.errorHandler) {
this._running = false;
(_a = this._observer) === null || _a === void 0 ? void 0 : _a.error(err);
}
else {
yield this.errorHandler(err);
}
}
catch (error) {
this._running = false;
(_b = this._observer) === null || _b === void 0 ? void 0 : _b.error(err);
}
});
}
mapLabel(name, value) {
// debug(`Adding label "${name}" to index ${value}`)
this._labels[name] = value;
}
getLabel(name) {
if (name in this._labels) {
return this._labels[name];
}
else {
return undefined;
}
}
safeRunOne(index) {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield this.runOne(index);
}
catch (err) {
yield this.onError(err);
}
});
}
}
exports.TestRunnerContext = TestRunnerContext;
function OutputToLogFunction(response) {
let message;
if (response) {
message = (0, byte_converter_1.bufferToHexString)(response.toBytes());
}
else {
message = 'NO OUTPUT YET';
}
(0, logger_1.debug)(message + '\r\n');
}
exports.OutputToLogFunction = OutputToLogFunction;
function DisplayToLogFunction(logLevel, message) {
const map = {
error: 'error',
verbose: 'debug',
message: 'info'
};
console[map[logLevel]](message);
}
exports.DisplayToLogFunction = DisplayToLogFunction;
/**
* Script runner
*
*/
class ScriptRunner {
constructor(io = {
output: OutputToLogFunction,
display: DisplayToLogFunction
}) {
this.io = io;
}
/**
* Configure error handler
*/
set errorHandler(handler) {
this._errorHandler = handler;
}
get errorHandler() {
return this._errorHandler;
}
isRunning() {
var _a;
return !!((_a = this.context) === null || _a === void 0 ? void 0 : _a.isRunning());
}
/**
* Run script instructions
* @param instructions
* @param device
*/
run(instructions, device) {
if (this.context) {
// should we throw an error when script is already running ?
}
this.context = new TestRunnerContext(device, instructions, this.io);
if (this.context.errorHandler) {
this.context.errorHandler = this._errorHandler;
}
return this.context.runAll();
}
stop() {
var _a;
(_a = this.context) === null || _a === void 0 ? void 0 : _a.stop();
}
}
exports.ScriptRunner = ScriptRunner;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NyaXB0LXJ1bm5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvc2NyaXB0LXJ1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFBQSxrRUFBa0U7QUFHbEUsK0JBQTRDO0FBRzVDLHFDQUF1QztBQUN2QyxpREFBa0Q7QUFFbEQscUNBQWlDO0FBVWpDOztHQUVHO0FBQ0gsTUFBYSxpQkFBaUI7SUEyQzFCLFlBQ1csTUFBVyxFQUNYLFlBQWlDLEVBQ2pDLEVBQXdEO1FBRnhELFdBQU0sR0FBTixNQUFNLENBQUs7UUFDWCxpQkFBWSxHQUFaLFlBQVksQ0FBcUI7UUFDakMsT0FBRSxHQUFGLEVBQUUsQ0FBc0Q7UUF6Q3pELFlBQU8sR0FBZ0MsRUFBRSxDQUFDO1FBQzFDLFlBQU8sR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNiLGVBQVUsR0FBa0IsSUFBSSxDQUFDO1FBQ2pDLFVBQUssR0FBMkIsRUFBRSxDQUFDO1FBQ25DLGFBQVEsR0FBWSxLQUFLLENBQUM7UUFFcEMsZ0JBQVcsR0FBWSxLQUFLLENBQUM7UUEyQnRCLGlCQUFZLEdBQTZCLENBQUMsS0FBWSxFQUFFLEVBQUU7WUFDN0QsTUFBTSxLQUFLLENBQUM7UUFDaEIsQ0FBQyxDQUFDO1FBUUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDN0MsSUFBSSxXQUFXLFlBQVksK0JBQWdCLEVBQUU7Z0JBQ3pDLElBQUksQ0FBQyxRQUFRLENBQUUsV0FBZ0MsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7YUFDaEU7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUF2Q0QsS0FBSyxDQUFDLEdBQVEsRUFBRSxLQUFXO1FBQ3ZCLElBQUksU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7WUFDeEIsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FB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