mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
Merge pull request #1058 from kiyeonjeon21/fix/aws-lambda-build-zip-linux-ffmpeg
fix(aws-lambda): fail build-zip when ffmpeg-static binary isn't Linux x86-64
This commit is contained in:
@@ -32,11 +32,14 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import {
|
||||
chmodSync,
|
||||
closeSync,
|
||||
cpSync,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
openSync,
|
||||
readdirSync,
|
||||
readFileSync,
|
||||
readSync,
|
||||
rmSync,
|
||||
statSync,
|
||||
writeFileSync,
|
||||
@@ -349,6 +352,55 @@ function stageHyperframeRuntime(stagingDir: string): void {
|
||||
console.log(`[build-zip] staged hyperframe.manifest.json + hyperframe.runtime.iife.js`);
|
||||
}
|
||||
|
||||
// ELF header constants used by `assertLinuxX86_64Elf`. Header layout:
|
||||
// bytes 0..3 magic `0x7F 'E' 'L' 'F'`, byte 4 EI_CLASS (`2` = ELFCLASS64),
|
||||
// bytes 18..19 e_machine little-endian (`0x3E` = EM_X86_64).
|
||||
const ELF_MAGIC = Buffer.from([0x7f, 0x45, 0x4c, 0x46]);
|
||||
const ELF_CLASS_64 = 2;
|
||||
const ELF_MACHINE_X86_64 = 0x3e;
|
||||
const ELF_HEADER_BYTES = 20;
|
||||
|
||||
/**
|
||||
* Verify the binary at `path` is a Linux x86-64 ELF executable, the only
|
||||
* shape the Lambda runtime can exec. Throws with the canonical workaround
|
||||
* (Docker `--platform=linux/amd64` or `npm_config_platform` /
|
||||
* `npm_config_arch` overrides) so the build doesn't ship a silently
|
||||
* broken zip when a non-Linux host's postinstall fetched the wrong arch.
|
||||
*/
|
||||
function assertLinuxX86_64Elf(path: string, label: string): void {
|
||||
const head = readFileHead(path, ELF_HEADER_BYTES, label);
|
||||
const isElf = head.subarray(0, 4).equals(ELF_MAGIC);
|
||||
const isElf64 = head[4] === ELF_CLASS_64;
|
||||
const machine = head.readUInt16LE(18);
|
||||
if (isElf && isElf64 && machine === ELF_MACHINE_X86_64) return;
|
||||
|
||||
const magicHex = head.subarray(0, 4).toString("hex");
|
||||
throw new Error(
|
||||
`[build-zip] ${label} at ${path} is not a Linux x86-64 ELF executable ` +
|
||||
`(magic=0x${magicHex}, ei_class=${head[4]}, e_machine=0x${machine.toString(16)}). ` +
|
||||
`This usually means the deploy host's postinstall fetched a host-platform binary ` +
|
||||
`(e.g. macOS arm64 ffmpeg) instead of the linux/x64 binary Lambda needs. ` +
|
||||
`Re-run the build inside a linux/amd64 container, or pre-install with ` +
|
||||
`\`npm_config_platform=linux npm_config_arch=x64\` so the package fetches the right binary.`,
|
||||
);
|
||||
}
|
||||
|
||||
function readFileHead(path: string, byteCount: number, label: string): Buffer {
|
||||
const fd = openSync(path, "r");
|
||||
try {
|
||||
const buf = Buffer.alloc(byteCount);
|
||||
const bytesRead = readSync(fd, buf, 0, byteCount, 0);
|
||||
if (bytesRead < byteCount) {
|
||||
throw new Error(
|
||||
`[build-zip] ${label} at ${path} is too short — read ${bytesRead} of ${byteCount} bytes.`,
|
||||
);
|
||||
}
|
||||
return buf;
|
||||
} finally {
|
||||
closeSync(fd);
|
||||
}
|
||||
}
|
||||
|
||||
function stageFfmpeg(stagingDir: string): void {
|
||||
const binDir = join(stagingDir, "bin");
|
||||
mkdirSync(binDir, { recursive: true });
|
||||
@@ -356,12 +408,19 @@ function stageFfmpeg(stagingDir: string): void {
|
||||
// ffmpeg from `ffmpeg-static`. The package only ships the encoder
|
||||
// binary; the audio pad/trim path also needs ffprobe, which comes
|
||||
// from `ffprobe-static`.
|
||||
//
|
||||
// `ffmpeg-static`'s postinstall fetches a binary for the host platform
|
||||
// (e.g. arm64 Mach-O on Apple Silicon macOS). Lambda runs Linux x86-64,
|
||||
// so a build from a non-Linux host silently produces a zip that boots
|
||||
// but fails at first ffmpeg invocation with `cannot execute binary file`.
|
||||
// Verify the ELF header up front and bail with a clear message instead.
|
||||
const ffmpegBinary = join(resolveModuleDir("ffmpeg-static"), "ffmpeg");
|
||||
if (!existsSync(ffmpegBinary)) {
|
||||
throw new Error(
|
||||
`[build-zip] ffmpeg-static binary missing at ${ffmpegBinary}. Did postinstall run?`,
|
||||
);
|
||||
}
|
||||
assertLinuxX86_64Elf(ffmpegBinary, "ffmpeg-static binary");
|
||||
const ffmpegDest = join(binDir, "ffmpeg");
|
||||
cpSync(ffmpegBinary, ffmpegDest);
|
||||
chmodSync(ffmpegDest, 0o755);
|
||||
|
||||
Reference in New Issue
Block a user