UNPKG

@ledgerhq/live-common

Version:
158 lines • 5.88 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.releaseSpeculosDeviceCI = exports.createSpeculosDeviceCI = exports.waitForSpeculosReady = void 0; const axios_1 = __importDefault(require("axios")); const speculos_transport_1 = require("@ledgerhq/speculos-transport"); const https_1 = __importDefault(require("https")); const { SEED, GITHUB_TOKEN, AWS_ROLE, CLUSTER, SPECULOS_IMAGE_TAG } = process.env; const GIT_API_URL = "https://api.github.com/repos/LedgerHQ/actions/actions/"; const START_WORKFLOW_ID = "workflows/161487603/dispatches"; const STOP_WORKFLOW_ID = "workflows/161487604/dispatches"; const GITHUB_REF = "main"; const getSpeculosAddress = (runId) => `https://${runId}.speculos.aws.stg.ldg-tech.com`; const speculosPort = 443; function uniqueId() { const timestamp = Date.now().toString(36); const randomString = Math.random().toString(36).slice(2, 7); return timestamp + randomString; } function slugify(name) { return name .toLowerCase() .trim() .replace(/[^a-z0-9]+/g, "-") .replace(/^-+|-+$/g, ""); } /** * Helper function to make API requests with error handling */ async function githubApiRequest({ method = "POST", urlSuffix, data, params, }) { const url = `${GIT_API_URL}${urlSuffix}`; try { const response = await (0, axios_1.default)({ method, url, headers: { Authorization: `Bearer ${GITHUB_TOKEN}`, Accept: "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28", }, data, params, }); return response.data; } catch (error) { console.warn(`API Request failed: ${method} ${url}`, axios_1.default.isAxiosError(error) ? error.response?.data : error.message); throw error; } } function waitForSpeculosReady(deviceId, { interval = 2_000, timeout = 150_000 } = {}) { return new Promise((resolve, reject) => { const startTime = Date.now(); let currentRequest = null; const url = getSpeculosAddress(deviceId); function cleanup() { if (currentRequest) { currentRequest.destroy(); currentRequest = null; } } function check() { cleanup(); currentRequest = https_1.default.get(url, { timeout: 10000 }, res => { if (res.statusCode && res.statusCode >= 200 && res.statusCode < 400) { process.env.SPECULOS_ADDRESS = url; cleanup(); console.warn(`Speculos is ready at ${url}`); resolve(true); } else { console.warn(`Speculos not ready yet, status: ${res.statusCode}`); retry(); } }); currentRequest.on("error", error => { console.error(`Request error: ${error.message}`); retry(); }); currentRequest.on("timeout", () => { console.error("Request timeout"); retry(); }); } function retry() { if (Date.now() - startTime >= timeout) { cleanup(); reject(new Error(`Timeout: ${url} did not become available within ${timeout}ms`)); } else { setTimeout(check, interval); } } check(); }); } exports.waitForSpeculosReady = waitForSpeculosReady; function createStartPayload(deviceParams, runId) { const { model, firmware, appName, appVersion, dependency, dependencies } = deviceParams; let additional_args = "-p"; if (dependency) { additional_args = `${additional_args} -l ${dependency}:/apps/${(0, speculos_transport_1.conventionalAppSubpath)(model, firmware, dependency, appVersion)}`; } else if (dependencies) { additional_args = [ ...new Set(dependencies.map(dep => `${additional_args} -l ${dep.name}:/apps/${(0, speculos_transport_1.conventionalAppSubpath)(model, firmware, dep.name, dep.appVersion ?? "1.0.0")}`)), ].join(" "); } return { ref: GITHUB_REF, inputs: { speculos_version: SPECULOS_IMAGE_TAG?.split(":")[1] || "master", coin_app: appName, coin_app_version: appVersion, device: speculos_transport_1.reverseModelMap[model], device_os_version: firmware, aws_role: AWS_ROLE, cluster: CLUSTER, seed: SEED, run_id: runId, additional_args, }, }; } async function createSpeculosDeviceCI(deviceParams) { const runId = `${slugify(deviceParams.appName)}-${uniqueId()}`; try { const data = createStartPayload(deviceParams, runId); await githubApiRequest({ urlSuffix: START_WORKFLOW_ID, data }); return { id: runId, port: speculosPort, }; } catch (e) { console.warn(`Creating remote speculos ${deviceParams.appName}:${deviceParams.appVersion} failed with ${String(e)}`); return { id: runId, port: 0, }; } } exports.createSpeculosDeviceCI = createSpeculosDeviceCI; async function releaseSpeculosDeviceCI(runId) { const data = { ref: GITHUB_REF, inputs: { run_id: runId.toString(), aws_role: AWS_ROLE, cluster: CLUSTER, }, }; await githubApiRequest({ urlSuffix: STOP_WORKFLOW_ID, data }); } exports.releaseSpeculosDeviceCI = releaseSpeculosDeviceCI; //# sourceMappingURL=speculosCI.js.map