@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
90 lines • 3.85 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = installApp;
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const errors_1 = require("@ledgerhq/errors");
const api_1 = __importDefault(require("../manager/api"));
const polyfill_1 = require("../apps/polyfill");
const logs_1 = require("@ledgerhq/logs");
const _1 = require(".");
const quitApp_1 = require("../deviceSDK/commands/quitApp");
const APP_INSTALL_RETRY_DELAY = 500;
const APP_INSTALL_RETRY_LIMIT = 5;
/**
* Command to install a given app to a device.
*
* On error (except on locked device errors), a retry mechanism is set.
*
* @param transport
* @param targetId Device firmware target id
* @param app Info of the app to install
* @param others Extended params:
* - retryLimit: number of time this command is retried when any error occurs. Default to 5.
* - retryDelayMs: delay in ms before retrying on an error. Default to 500ms.
* @returns An Observable emitting installation progress
* - progress: float number from 0 to 1 representing the installation progress
*/
function installApp(transport, targetId, app, { retryLimit = APP_INSTALL_RETRY_LIMIT, retryDelayMs = APP_INSTALL_RETRY_DELAY, } = {}) {
const tracer = new logs_1.LocalTracer(_1.LOG_TYPE, {
...transport.getTraceContext(),
function: "installApp",
});
tracer.trace("Install app", {
targetId,
appName: app?.name,
appVersion: app?.version,
retryLimit,
retryDelayMs,
});
// Run quitApp just before ManagerAPI.install
return (0, quitApp_1.quitApp)(transport).pipe((0, operators_1.switchMap)(() => api_1.default.install(transport, "install-app", {
targetId,
perso: app.perso,
deleteKey: app.delete_key,
firmware: app.firmware,
firmwareKey: app.firmware_key,
hash: app.hash,
}).pipe((0, operators_1.retry)({
count: retryLimit,
delay: (error, retryCount) => {
// Not retrying on locked device errors
if (error instanceof errors_1.LockedDeviceError ||
error instanceof errors_1.ManagerDeviceLockedError ||
error instanceof errors_1.UnresponsiveDeviceError) {
tracer.trace(`Not retrying on error: ${error}`, {
error,
});
return (0, rxjs_1.throwError)(() => error);
}
tracer.trace(`Retrying (${retryCount}/${retryLimit}) on error: ${error}`, {
error,
retryLimit,
retryDelayMs,
});
return (0, rxjs_1.timer)(retryDelayMs);
},
}), (0, operators_1.filter)((e) => e.type === "bulk-progress"), // only bulk progress interests the UI
(0, operators_1.throttleTime)(100), // throttle to only emit 10 event/s max, to not spam the UI
(0, operators_1.map)((e) => ({
progress: e.progress,
})), // extract a stream of progress percentage
(0, operators_1.catchError)((e) => {
tracer.trace(`Error: ${e}`, { error: e });
if (!e || !e.message)
return (0, rxjs_1.throwError)(() => e);
const status = e.message.slice(e.message.length - 4);
if (status === "6a83" || status === "6811") {
const dependencies = (0, polyfill_1.getDependencies)(app.name);
return (0, rxjs_1.throwError)(() => new errors_1.ManagerAppDepInstallRequired("", {
appName: app.name,
dependency: dependencies.join(", "),
}));
}
return (0, rxjs_1.throwError)(() => e);
}))));
}
//# sourceMappingURL=installApp.js.map