From 974f74d12ad4d9468815d8f1007456aa5632623a Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Tue, 8 Jul 2025 16:42:26 +0200 Subject: [PATCH] feat: dispatch emulator --- src/services/emulator/dispatch.services.ts | 47 +++++++++++++ .../build/build.javascript.services.ts | 17 +++-- .../functions/build/build.rust.services.ts | 18 +++-- .../functions/build/build.services.ts | 66 ++++++++++++------- 4 files changed, 111 insertions(+), 37 deletions(-) create mode 100644 src/services/emulator/dispatch.services.ts diff --git a/src/services/emulator/dispatch.services.ts b/src/services/emulator/dispatch.services.ts new file mode 100644 index 00000000..61604bbe --- /dev/null +++ b/src/services/emulator/dispatch.services.ts @@ -0,0 +1,47 @@ +import {red, yellow} from 'kleur'; +import {readEmulatorConfig} from '../../configs/emulator.config'; +import {EMULATOR_SKYLAB} from '../../constants/emulator.constants'; +import {DEV} from '../../env'; + +export const dispatchEmulatorUpgrade = async () => { + await dispatchSatelliteCommand({subCommand: 'upgrade'}); +}; + +export const dispatchEmulatorConfig = async () => { + await dispatchSatelliteCommand({subCommand: 'config'}); +}; + +const dispatchSatelliteCommand = async ({subCommand}: {subCommand: 'upgrade' | 'config'}) => { + if (!DEV) { + return; + } + + const parsedResult = await readEmulatorConfig(); + + if (!parsedResult.success) { + return; + } + + const { + config: { + config, + derivedConfig: {emulatorType} + } + } = parsedResult; + + const adminPort = config[emulatorType]?.ports?.admin ?? EMULATOR_SKYLAB.ports.admin; + + try { + const response = await fetch(`http://localhost:${adminPort}/satellite/${subCommand}`); + + if (!response.ok) { + console.log( + red(`Invalid response from the emulator. The '${subCommand}' command did not succeed.`) + ); + } + } catch (error: unknown) { + console.log( + yellow(`The '${subCommand}' command failed. Maybe the emulator is not running? 🤔`) + ); + } +}; diff --git a/src/services/functions/build/build.javascript.services.ts b/src/services/functions/build/build.javascript.services.ts index 5cf0cebf..08c70b6f 100644 --- a/src/services/functions/build/build.javascript.services.ts +++ b/src/services/functions/build/build.javascript.services.ts @@ -19,20 +19,23 @@ import {prepareJavaScriptBuildMetadata} from './build.metadata.services'; export const buildTypeScript = async ({ paths, exitOnError -}: Pick = {}) => { - await build({lang: 'ts', paths, exitOnError}); +}: Pick = {}): Promise<{result: 'success' | 'error'}> => { + return await build({lang: 'ts', paths, exitOnError}); }; export const buildJavaScript = async ({ paths, exitOnError -}: Pick = {}) => { - await build({lang: 'mjs', paths, exitOnError}); +}: Pick = {}): Promise<{result: 'success' | 'error'}> => { + return await build({lang: 'mjs', paths, exitOnError}); }; type BuildArgsTsJs = {lang: Omit} & Pick; -const build = async ({exitOnError, ...params}: BuildArgsTsJs) => { +const build = async ({ + exitOnError, + ...params +}: BuildArgsTsJs): Promise<{result: 'success' | 'error'}> => { await installEsbuild(); await readEmulatorConfigAndCreateDeployTargetDir(); @@ -43,10 +46,14 @@ const build = async ({exitOnError, ...params}: BuildArgsTsJs) => { const buildResult = await buildWithEsbuild({params, metadata}); printResults({metadata, buildResult}); + + return {result: 'success'}; } catch (_error: unknown) { if (exitOnError !== false) { process.exit(1); } + + return {result: 'error'}; } }; diff --git a/src/services/functions/build/build.rust.services.ts b/src/services/functions/build/build.rust.services.ts index 6874b3a9..8176d698 100644 --- a/src/services/functions/build/build.rust.services.ts +++ b/src/services/functions/build/build.rust.services.ts @@ -35,35 +35,37 @@ import {prepareJunoPkgForSatellite, prepareJunoPkgForSputnik} from './build.meta export const buildRust = async ({ paths, target -}: Pick & {target?: 'wasm32-unknown-unknown' | 'wasm32-wasip1'} = {}) => { +}: Pick & {target?: 'wasm32-unknown-unknown' | 'wasm32-wasip1'} = {}): Promise<{ + result: 'success' | 'error'; +}> => { const {valid: validRust} = await checkRustVersion(); if (validRust === 'error' || !validRust) { - return; + return {result: 'error'}; } const {valid} = await checkIcWasm(); if (!valid) { - return; + return {result: 'error'}; } const {valid: validExtractor} = await checkCandidExtractor(); if (!validExtractor) { - return; + return {result: 'error'}; } const {valid: validDidc} = await checkJunoDidc(); if (!validDidc) { - return; + return {result: 'error'}; } const {valid: validWasi2ic} = target === 'wasm32-wasip1' ? await checkWasi2ic() : {valid: true}; if (!validWasi2ic) { - return; + return {result: 'error'}; } const defaultProjectArgs = ['-p', SATELLITE_PROJECT_NAME]; @@ -105,7 +107,7 @@ export const buildRust = async ({ if ('error' in buildType) { console.log(red(buildType.error)); - return; + return {result: 'error'}; } switch (target) { @@ -156,6 +158,8 @@ export const buildRust = async ({ await rename(`${SATELLITE_OUTPUT}.tmp.gz`, `${SATELLITE_OUTPUT}.gz`); await successMsg(spinner); + + return {result: 'success'}; } finally { spinner.stop(); } diff --git a/src/services/functions/build/build.services.ts b/src/services/functions/build/build.services.ts index fdad173a..b7742516 100644 --- a/src/services/functions/build/build.services.ts +++ b/src/services/functions/build/build.services.ts @@ -16,6 +16,7 @@ import {type BuildArgs} from '../../../types/build'; import {buildArgs} from '../../../utils/build.utils'; import {buildJavaScript, buildTypeScript} from './build.javascript.services'; import {buildRust} from './build.rust.services'; +import {dispatchEmulatorUpgrade} from '../../emulator/dispatch.services'; export const build = async (args?: string[]) => { const {watch, ...params} = buildArgs(args); @@ -25,21 +26,32 @@ export const build = async (args?: string[]) => { return; } - await executeBuild(params); + await executeBuildAndUpgrade(params); }; -const executeBuild = async ({lang, paths, exitOnError}: Omit) => { +const executeBuildAndUpgrade = async (params: Omit) => { + const {result} = await executeBuild(params); + + if (result !== 'success') { + return; + } + + await dispatchEmulatorUpgrade(); +}; + +const executeBuild = async ({ + lang, + paths, + exitOnError +}: Omit): Promise<{result: 'success' | 'error' | 'unknown'}> => { // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (lang) { case 'rs': - await buildRust({paths}); - return; + return await buildRust({paths}); case 'ts': - await executeSputnikBuild({paths, exitOnError, buildFn: buildTypeScript}); - return; + return await executeSputnikBuild({paths, exitOnError, buildFn: buildTypeScript}); case 'mjs': - await executeSputnikBuild({paths, exitOnError, buildFn: buildJavaScript}); - return; + return await executeSputnikBuild({paths, exitOnError, buildFn: buildJavaScript}); } const isPathToml = @@ -47,8 +59,7 @@ const executeBuild = async ({lang, paths, exitOnError}: Omit basename(paths.cargo) === basename(DEVELOPER_PROJECT_SATELLITE_CARGO_TOML); if (isPathToml) { - await buildRust({paths}); - return; + return await buildRust({paths}); } const isPathTypeScript = @@ -56,8 +67,7 @@ const executeBuild = async ({lang, paths, exitOnError}: Omit extname(paths.source) === extname(DEVELOPER_PROJECT_SATELLITE_INDEX_TS); if (isPathTypeScript) { - await executeSputnikBuild({paths, exitOnError, buildFn: buildTypeScript}); - return; + return await executeSputnikBuild({paths, exitOnError, buildFn: buildTypeScript}); } const isPathJavaScript = @@ -65,17 +75,15 @@ const executeBuild = async ({lang, paths, exitOnError}: Omit extname(paths.source) === extname(DEVELOPER_PROJECT_SATELLITE_INDEX_MJS); if (isPathJavaScript) { - await executeSputnikBuild({paths, exitOnError, buildFn: buildJavaScript}); - return; + return await executeSputnikBuild({paths, exitOnError, buildFn: buildJavaScript}); } if (existsSync(DEVELOPER_PROJECT_SATELLITE_CARGO_TOML)) { - await buildRust(); - return; + return await buildRust(); } if (existsSync(DEVELOPER_PROJECT_SATELLITE_INDEX_TS)) { - await executeSputnikBuild({ + return await executeSputnikBuild({ paths: { ...paths, source: DEVELOPER_PROJECT_SATELLITE_INDEX_TS @@ -83,11 +91,10 @@ const executeBuild = async ({lang, paths, exitOnError}: Omit exitOnError, buildFn: buildTypeScript }); - return; } if (existsSync(DEVELOPER_PROJECT_SATELLITE_INDEX_MJS)) { - await executeSputnikBuild({ + return await executeSputnikBuild({ paths: { ...paths, source: DEVELOPER_PROJECT_SATELLITE_INDEX_MJS @@ -95,7 +102,6 @@ const executeBuild = async ({lang, paths, exitOnError}: Omit exitOnError, buildFn: buildJavaScript }); - return; } console.log( @@ -103,6 +109,8 @@ const executeBuild = async ({lang, paths, exitOnError}: Omit 'No source found for Satellite serverless functions. Expected a Rust, TypeScript, or JavaScript project.' ) ); + + return {result: 'unknown'}; }; const executeSputnikBuild = async ({ @@ -110,9 +118,15 @@ const executeSputnikBuild = async ({ exitOnError, buildFn }: Omit & { - buildFn: (args: Pick) => Promise; -}) => { - await buildFn({paths, exitOnError}); + buildFn: ( + args: Pick + ) => Promise<{result: 'success' | 'error'}>; +}): Promise<{result: 'success' | 'error'}> => { + const {result: resultBuild} = await buildFn({paths, exitOnError}); + + if (resultBuild === 'error') { + return {result: 'error'}; + } const withToolchain = nonNullish(paths?.cargo) || ENV.ci; @@ -122,14 +136,16 @@ const executeSputnikBuild = async ({ cargo: paths?.cargo ?? SPUTNIK_CARGO_TOML }; - await buildRust({paths: rustPaths, target: 'wasm32-wasip1'}); + return await buildRust({paths: rustPaths, target: 'wasm32-wasip1'}); } + + return {result: 'success'}; }; export const watchBuild = ({watch, paths, ...params}: BuildArgs) => { const doBuild = async () => { console.log(`\n⏱ Rebuilding serverless functions...`); - await executeBuild({paths, exitOnError: false, ...params}); + await executeBuildAndUpgrade({paths, exitOnError: false, ...params}); }; const DEFAULT_TIMEOUT = 10_000;