All files / server/routes compiler.routes.ts

100% Statements 26/26
94.44% Branches 17/18
100% Functions 2/2
100% Lines 26/26

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 71 72 73                                        10x   10x 11x 11x 11x 2x     9x 9x   9x 2x 2x 1x 1x 1x 1x   1x       8x 11x       11x                   7x 6x 6x 6x     7x   1x 1x        
import type { Express } from "express";
import type { CompilationResult, CompileRequestOptions } from "../services/arduino-compiler";
import type { Logger } from "@shared/logger";
 
type CompilerHeader = { name: string; content: string };
 
type CompilerDeps = {
  compiler: {
    compile: (code: string, headers?: CompilerHeader[], tempRoot?: string, options?: CompileRequestOptions) => Promise<CompilationResult>;
  };
  compilationCache: Map<string, { result: CompilationResult; timestamp: number }>;
  hashCode: (code: string, headers?: CompilerHeader[]) => string;
  CACHE_TTL: number;
  setLastCompiledCode: (code: string | null) => void;
  logger: Logger;
};
 
import path from "node:path";
 
export function registerCompilerRoutes(app: Express, deps: CompilerDeps) {
  const { compiler, compilationCache, hashCode, CACHE_TTL, setLastCompiledCode, logger } = deps;
 
  app.post("/api/compile", async (req, res) => {
    try {
      const { code, headers, fqbn, libraries } = req.body;
      if (!code || typeof code !== "string") {
        return res.status(400).json({ error: "Code is required" });
      }
 
      const codeHash = hashCode(code, headers);
      const cachedEntry = compilationCache.get(codeHash);
 
      if (cachedEntry) {
        const cacheAge = Date.now() - cachedEntry.timestamp;
        if (cacheAge < CACHE_TTL) {
          logger.info(`✅ Cache hit for code (age: ${cacheAge}ms)`);
          const result = cachedEntry.result;
          setLastCompiledCode(code);
          return res.json({ ...result, cached: true });
        } else {
          compilationCache.delete(codeHash);
        }
      }
 
      const testRunIdHeader = req.header("x-test-run-id") || undefined;
      const compileTempRoot = testRunIdHeader
        ? path.join(process.cwd(), "temp", testRunIdHeader)
        : undefined;
 
      const result: CompilationResult = await compiler.compile(
        code,
        headers,
        compileTempRoot,
        {
          fqbn,
          libraries: Array.isArray(libraries) ? libraries : undefined,
        },
      );
 
      if (result.success) {
        compilationCache.set(codeHash, { result, timestamp: Date.now() });
        logger.info(`✅ Cached compilation result for code`);
        setLastCompiledCode(code);
      }
 
      res.json(result);
    } catch (error) {
      logger.error(`[Compiler Route] Error during /api/compile: ${error instanceof Error ? error.message : String(error)}`);
      res.status(500).json({ error: "Compilation failed" });
    }
  });
}