UNPKG

@voximplant/voxengine-ci

Version:

Manage Voximplant Platform `applications`, `rules` and `scenarios` from your own environment

228 lines (227 loc) 12.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.VoxScenarioService = void 0; const node_util_1 = require("node:util"); const node_crypto_1 = require("node:crypto"); const node_child_process_1 = require("node:child_process"); const vox_scenario_entity_1 = require("../entities/vox-scenario.entity"); const log_message_generator_1 = require("../../utils/log-message-generator"); const asyncExec = (0, node_util_1.promisify)(node_child_process_1.exec); class VoxScenarioService { constructor(platformRepository, persistentRepository) { this.platformRepository = platformRepository; this.persistentRepository = persistentRepository; this.lmg = log_message_generator_1.LogMessageGeneratorFactory.getInstance(); this.init = () => { console.info(this.lmg.generate('INFO__INIT_SUCCESS', this.constructor.name)); }; this.generateHash = (data) => (0, node_crypto_1.createHash)('sha256').update(data).digest('hex'); this.cleanup = async () => { await this.persistentRepository.unlink(); await this.persistentRepository.link(); await this.persistentRepository.unlinkMetadata(); await this.persistentRepository.linkMetadata(); }; this.cleanupSrc = async () => { await this.persistentRepository.unlinkSrc(); await this.persistentRepository.linkSrc(); }; this.cleanupDist = async () => { await this.persistentRepository.unlinkDist(); await this.persistentRepository.linkDist(); }; this.checkScenariosAlreadyExists = async () => { try { const scenarios = await this.persistentRepository.readStorage(); const scenariosMetadata = await this.persistentRepository.readMetadataStorage(); return !!scenarios.length && !!scenariosMetadata.length; } catch (error) { console.error(this.lmg.generate('ERR__CHECK_SCENARIO_ALREADY_EXISTS_FAILED', this.constructor.name)); console.error(error); } }; this.checkScenariosNames = (rawScenarios) => { if (!rawScenarios || !rawScenarios.length) return; const scenariosNamesGrouped = rawScenarios.reduce((acc, scenario) => { const { scenarioName } = scenario; const scenarioNameLowCase = scenarioName.toLowerCase(); acc?.[scenarioNameLowCase] ? acc[scenarioNameLowCase]?.push(scenarioName) : (acc[scenarioNameLowCase] = [scenarioName]); return acc; }, {}); const duplicatedNames = Object.values(scenariosNamesGrouped).filter((names) => names.length > 1); if (duplicatedNames.length) { throw new Error(this.lmg.generate('INFO__SAME_SCENARIOS', duplicatedNames.toString())); } }; this.downloadScenarios = async () => { return await this.platformRepository.downloadScenarios(); }; this.downloadScenario = async (scenarioId) => { try { const scenario = await this.platformRepository.downloadScenarioById(scenarioId); if (!scenario) { throw new Error(this.lmg.generate('ERR__SCENARIO_BY_ID_IS_NOT_FOUND', scenarioId.toString())); } return scenario; } catch (error) { console.error(this.lmg.generate('ERR__DOWNLOAD_SCENARIO_FAILED', this.constructor.name)); console.error(error); } }; this.saveScenario = async (rawScenario) => { try { const voxScenario = new vox_scenario_entity_1.VoxScenario(rawScenario); await this.persistentRepository.create(voxScenario); } catch (error) { console.error(this.lmg.generate('ERR__SAVE_SCENARIO_FAILED', this.constructor.name)); console.error(error); } }; this.addScenariosToRule = async (bindScenarioRequest) => { try { return await this.platformRepository.bindScenarios(bindScenarioRequest); } catch (error) { console.error(this.lmg.generate('ERR__ADD_SCENARIOS_TO_RULE_FAILED', this.constructor.name)); console.error(error); } }; this.saveScenarioMetadata = async (rawScenario) => { try { const hash = this.generateHash(rawScenario.scenarioScript); const voxScenarioMetadata = new vox_scenario_entity_1.VoxScenarioMetadata(rawScenario, hash); await this.persistentRepository.createMetadata(voxScenarioMetadata); } catch (error) { console.error(this.lmg.generate('ERR__SAVE_SCENARIO_METADATA_FAILED', this.constructor.name)); console.error(error); } }; this.getScenarioInfoFromPlatform = async (scenarioNames) => { const allScenarios = await this.platformRepository.downloadScenarios(); return scenarioNames .map((scenarioName) => allScenarios.find((scenario) => scenario.scenarioName === scenarioName)) .filter((scenario) => scenario); }; this.getScenariosMetadata = async (scenariosNames) => { const scenariosMetadata = []; try { for (const scenarioName of scenariosNames) { const stringDistScenarioMetadata = await this.persistentRepository.readDistMetadata(scenarioName); const scenario = (JSON.parse(stringDistScenarioMetadata)); scenariosMetadata.push({ scenarioId: scenario.scenarioId, hash: scenario.hash, scenarioName: scenario.scenarioName, }); } } catch (error) { console.error(this.lmg.generate('ERR__GET_SCENARIOS_METADATA_FAILED', this.constructor.name)); } return scenariosMetadata; }; /** * TODO: The `build` method must to return something */ this.build = async (scenarios = []) => { try { await this.persistentRepository.createOrUpdateTsConfig(scenarios); const tsConfigPath = this.persistentRepository.getTsConfigPath(); try { await asyncExec(`npx tsc -p ${tsConfigPath}`); } catch (compileError) { console.error(this.lmg.generate('ERR__SCENARIOS_COMPILATION_FAILED', scenarios.toString())); throw compileError; } console.info(this.lmg.generate('INFO__SCENARIOS_BUILT', scenarios.toString())); } catch (error) { console.error(this.lmg.generate('ERR__BUILD_FAILED', this.constructor.name)); throw error; } finally { await this.persistentRepository.removeTsConfig(); } }; this.upload = async (scenarios = [], isForce = false) => { try { for (const scenarioName of scenarios) { const distScenario = await this.persistentRepository.readDist(scenarioName); if (!distScenario && distScenario !== '') { throw new Error(this.lmg.generate('ERR__SCENARIO_DIST_IS_NOT_FOUND', scenarioName)); } const distScenarioHash = this.generateHash(distScenario); let stringDistScenarioMetadata = await this.persistentRepository.readDistMetadata(scenarioName); const platformScenarioInfo = await this.platformRepository.downloadScenarioByName(scenarioName); // Brand-new scenario if (!stringDistScenarioMetadata && !platformScenarioInfo) { const addScenarioResult = await this.platformRepository.addScenario(scenarioName, distScenario); if (!addScenarioResult) { throw new Error(this.lmg.generate('ERR__SCENARIO_IS_NOT_ADDED', scenarioName)); } const platformScenarioInfoWithoutScript = await this.platformRepository.downloadScenarioByName(scenarioName); if (!platformScenarioInfoWithoutScript) { throw new Error(this.lmg.generate('ERR__SCENARIO_BY_NAME_IS_NOT_FOUND_AFTER_ADDING', scenarioName)); } const voxScenarioMetadata = new vox_scenario_entity_1.VoxScenarioMetadata(platformScenarioInfoWithoutScript, distScenarioHash); await this.persistentRepository.createOrUpdateMetadata(voxScenarioMetadata); continue; } // No metadata for the existing scenario if (!stringDistScenarioMetadata && platformScenarioInfo) { const platformScenarioHash = this.generateHash(platformScenarioInfo.scenarioScript); const voxScenarioMetadata = new vox_scenario_entity_1.VoxScenarioMetadata(platformScenarioInfo, platformScenarioHash); await this.persistentRepository.createOrUpdateMetadata(voxScenarioMetadata); stringDistScenarioMetadata = await this.persistentRepository.readDistMetadata(scenarioName); } // Updating the existing scenario if (stringDistScenarioMetadata && platformScenarioInfo) { const rawDistScenarioMetadata = (JSON.parse(stringDistScenarioMetadata)); const metadataScenarioHash = rawDistScenarioMetadata.hash; if (distScenarioHash === metadataScenarioHash) { console.info(this.lmg.generate('INFO__SCENARIO_NOT_CHANGED', scenarioName)); continue; } console.info(this.lmg.generate('INFO__SCENARIO_CHANGED', scenarioName)); const scenarioId = rawDistScenarioMetadata.scenarioId; const platformScenarioInfoWithScript = await this.platformRepository.downloadScenarioById(scenarioId); if (!platformScenarioInfoWithScript) { throw new Error(this.lmg.generate('ERR__SCENARIO_BY_ID_AND_NAME_IS_NOT_FOUND_AFTER_ADDING', scenarioId.toString(), scenarioName)); } const platformScenarioScript = platformScenarioInfoWithScript.scenarioScript; const platformScenarioHash = this.generateHash(platformScenarioScript); const platformChanges = metadataScenarioHash !== platformScenarioHash; // If there are platform changes that emit aborting the operation (no '--force' flag has been provided) if (platformChanges && !isForce) { throw new Error(this.lmg.generate('ERR__SCENARIO_IS_CHANGED_FROM_THE_PLATFORM', scenarioId.toString(), scenarioName)); } // Alert about '--force' flag using to prevent the 'platform changes' aborting if (platformChanges && isForce) { console.info(this.lmg.generate('INFO__SCENARIO_FORCE_CHANGE', scenarioId.toString(), scenarioName)); } const updateScenarioResult = await this.platformRepository.updateScenario(scenarioId, scenarioName, distScenario); if (!updateScenarioResult) { throw new Error(this.lmg.generate('ERR__SCENARIO_IS_NOT_UPDATED', scenarioName, scenarioId.toString())); } const voxScenarioMetadata = new vox_scenario_entity_1.VoxScenarioMetadata(platformScenarioInfoWithScript, distScenarioHash); await this.persistentRepository.createOrUpdateMetadata(voxScenarioMetadata); } } } catch (error) { console.error(this.lmg.generate('ERR__UPLOAD_FAILED', this.constructor.name)); throw error; } }; } } exports.VoxScenarioService = VoxScenarioService;