All files / server/services/sandbox/execution-phases prepare-phase.ts

100% Statements 17/17
87.5% Branches 7/8
100% Functions 3/3
100% Lines 15/15

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70                                                                      19x 19x     19x 19x           19x       1x 1x 1x     18x 18x 16x 9x 9x     18x 18x            
// prepare-phase.ts
// Preparation and compilation phase for simulation execution
// Extracted from ExecutionManager.performCompilation()
 
import { config } from "../../../config";
import { Logger } from "@shared/logger";
import type { RunSketchOptions } from "../../run-sketch-types";
import type { ExecutionState } from "../execution-manager";
import { SimulationState } from "../execution-manager";
import type { LocalCompiler } from "../../local-compiler";
import { getUnifiedGatekeeper } from "../../unified-gatekeeper";
 
export interface PrepareContext {
  localCompiler: LocalCompiler;
  logger: Logger;
  transitionTo: (state: ExecutionState, newState: SimulationState) => boolean;
}
 
/**
 * Perform compilation with gatekeeper control
 * 
 * @param sketchFile - Path to the sketch file
 * @param exeFile - Path to the executable file
 * @param opts - Run options with compile callbacks
 * @param state - Current execution state
 * @param context - Dependency injection context
 * @returns Promise that resolves when compilation completes
 */
export async function performCompilation(
  sketchFile: string,
  exeFile: string,
  opts: RunSketchOptions,
  state: ExecutionState,
  context: PrepareContext,
): Promise<void> {
  const WAIT_TIMEOUT_MS = config.timeouts.compileGatekeeperAcquireMs;
  const gatekeeper = getUnifiedGatekeeper();
  let release: () => void;
 
  try {
    release = await Promise.race([
      gatekeeper.acquireCompileSlotHighPriority(
        "simulation-start",
        opts.onCompileQueued,
      ),
      new Promise<never>((_, reject) =>
        setTimeout(() => reject(new Error("compile-gatekeeper timeout")), WAIT_TIMEOUT_MS),
      ),
    ]);
  } catch (err) {
    context.logger.error(`Gatekeeper wait failed: ${err instanceof Error ? err.message : String(err)}`);
    context.transitionTo(state, SimulationState.ERROR);
    throw err;
  }
 
  try {
    if (state.processController && context.localCompiler) {
      await context.localCompiler.compile(sketchFile, exeFile);
      if (opts.onCompileSuccess) opts.onCompileSuccess();
      await context.localCompiler.makeExecutable(exeFile);
    }
  } finally {
    try {
      release();
    } catch {
      // should never happen
    }
  }
}