UNPKG

openvino-node

Version:

OpenVINO™ utils for using from Node.js environment

203 lines (172 loc) 6.31 kB
const os = require("node:os"); const tar = require("tar-fs"); const path = require("node:path"); const gunzip = require("gunzip-maybe"); const fs = require("node:fs/promises"); const { createReadStream, existsSync } = require("node:fs"); const { downloadFile, checkIfPathExists, removeDirectory } = require("./utils"); class BinaryManager { constructor(packageRoot, version, binaryConfig) { this.packageRoot = packageRoot; this.version = version; this.binaryConfig = binaryConfig; } getPlatformLabel() { return os.platform(); } getArchLabel() { return os.arch(); } getExtension() { return "tar.gz"; } getArchiveUrl() { const { host, package_name: packageNameTemplate, remote_path: remotePathTemplate, } = this.binaryConfig; const fullPathTemplate = `${remotePathTemplate}${packageNameTemplate}`; const fullPath = fullPathTemplate .replace(new RegExp("{version}", "g"), this.version) .replace(new RegExp("{platform}", "g"), this.getPlatformLabel()) .replace(new RegExp("{arch}", "g"), this.getArchLabel()) .replace(new RegExp("{extension}", "g"), this.getExtension()); return new URL(fullPath, host).toString(); } getDestinationPath() { const modulePath = this.binaryConfig["module_path"]; return path.resolve(this.packageRoot, modulePath); } /** * Prepares the binary by downloading and extracting the OpenVINO runtime * archive. * * @param {string} packageRoot - The root directory of the package. * @param {string} version - The version of the binary. * @param {Object} binaryConfig - The configuration object for the binary. * @param {Object} options - The options for preparing the binary. * @param {boolean} options.force - Whether to force the download if the * directory already exists. * @param {boolean} options.ignoreIfExists - Whether to ignore the download * if the directory already exists. * @param {string} [options.proxy] - The proxy to use for downloading the * file. * @throws {Error} If the directory already exists and the force option * is not set. * @throws {Error} If the download or extraction fails. * @returns {Promise<void>} A promise that resolves when the binary is * prepared. */ static async prepareBinary(packageRoot, version, binaryConfig, options) { const binaryManager = new this(packageRoot, version, binaryConfig); const destinationPath = binaryManager.getDestinationPath(); const isRuntimeDirectoryExists = await checkIfPathExists(destinationPath); if (isRuntimeDirectoryExists && !options.force) { if (options.ignoreIfExists) { console.warn( `Directory '${destinationPath}' already exists. Skipping ` + 'runtime downloading because "ignoreIfExists" flag is passed.', ); return; } throw new Error( `Directory '${destinationPath}' already exists. ` + 'To force runtime downloading use "force" flag.', ); } // Install binaries from directories if possible if (process.env.npm_package_resolved?.startsWith("file:")) { const binDir = path .join(path.dirname(process.env.npm_package_resolved), "bin") .replace("file:", ""); if ( existsSync(path.join(binDir, "libopenvino.so")) || existsSync(path.join(binDir, "openvino.dll")) ) { try { await fs.cp(binDir, destinationPath, { recursive: true }); return; } catch (error) { console.error(`Failed to copy bin directory: ${error}.`); } } console.log("Do not find bin directory with openvino library."); } const archiveUrl = binaryManager.getArchiveUrl(); let tempDirectoryPath = null; try { tempDirectoryPath = await fs.mkdtemp(path.join(os.tmpdir(), "temp-ov-runtime-archive-")); const filename = path.basename(archiveUrl); console.log("Downloading OpenVINO runtime archive..."); const archiveFilePath = await downloadFile( archiveUrl, tempDirectoryPath, filename, options.proxy, ); console.log("OpenVINO runtime archive downloaded."); await removeDirectory(destinationPath); await this.unarchive(archiveFilePath, destinationPath); console.log("The archive was successfully extracted."); } catch (error) { console.error(`Failed to download OpenVINO runtime: ${error}.`); throw error; } finally { if (tempDirectoryPath) await removeDirectory(tempDirectoryPath); } } /** * Checks if the current platform and architecture are compatible. * * Supported platforms: 'win32', 'linux', 'darwin'. * Supported architectures: 'arm64', 'armhf', 'x64'. * * If the platform or architecture is not supported, an error message * is logged to the console. * * @returns {boolean} Returns true if the platform and architecture are * compatible, otherwise false. */ static isCompatible() { const missleadings = []; const platform = os.platform(); if (!["win32", "linux", "darwin"].includes(platform)) missleadings.push(`Platform '${platform}' is not supported.`); const arch = os.arch(); if (!["arm64", "armhf", "x64"].includes(arch)) missleadings.push(`Architecture '${arch}' is not supported.`); if (platform === "win32" && arch !== "x64") missleadings.push(`Version for windows and '${arch}' is not supported.`); if (missleadings.length) { console.error(missleadings.join(" ")); return false; } return true; } /** * Unarchive tar and tar.gz archives. * * @function unarchive * @param {string} archivePath - Path to archive. * @param {string} dest - Path where to unpack. * @returns {Promise<void>} */ static unarchive(archivePath, dest) { return new Promise((resolve, reject) => { createReadStream(archivePath) .pipe(gunzip()) .pipe( tar .extract(dest, { validateSymlinks: false }) .on("finish", () => { resolve(); }) .on("error", (err) => { reject(err); }), ); }); } } module.exports = BinaryManager;