Self-hosted multi-platform broadcast newsroom for activist collectives: publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style column wall with hostile-content-safe rendering, live control room with Auto Director, bridged chat governance with polls and quorum, distributed sandboxed transcode workers, encrypted content-addressed archive, monthly analytics. MIT licensed. See README.md and docs/.
85 lines
3.6 KiB
TypeScript
85 lines
3.6 KiB
TypeScript
/**
|
|
* Native helper binaries (src/gate/rust, std only): `frame-gate` (the channel's
|
|
* clock master) and `source-bus` (per-source raw frame fan-out).
|
|
*
|
|
* Resolution order, first hit wins:
|
|
* 1. `MEDIA_FRAME_GATE_BIN` / `MEDIA_SOURCE_BUS_BIN`: an explicit path per binary;
|
|
* 2. `MEDIA_HELPER_DIR/<name>`: the packaged directory (the image builds the crate
|
|
* with `scripts/build-helpers.sh` and sets this; see runs/wp4/s2b-report.md item 5);
|
|
* 3. the crate's `target/release/<name>` (development checkouts and tests).
|
|
*
|
|
* Nothing builds at runtime in production. `ensureHelperBinaries()` is for tests
|
|
* and the spike/smoke scripts: it builds the crate offline when a binary is
|
|
* missing or older than its sources.
|
|
*/
|
|
import { spawnSync } from "node:child_process";
|
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
import { join, resolve } from "node:path";
|
|
|
|
export type HelperBinary = "frame-gate" | "source-bus";
|
|
|
|
const ENV: Record<HelperBinary, string> = { "frame-gate": "MEDIA_FRAME_GATE_BIN", "source-bus": "MEDIA_SOURCE_BUS_BIN" };
|
|
|
|
/** The crate directory, from `src/gate` (tsx) or `dist/gate` (compiled). */
|
|
export function helperCrateDir(): string {
|
|
const local = resolve(__dirname, "rust");
|
|
return existsSync(join(local, "Cargo.toml")) ? local : resolve(__dirname, "../../src/gate/rust");
|
|
}
|
|
|
|
function candidates(name: HelperBinary): string[] {
|
|
return [
|
|
process.env[ENV[name]],
|
|
process.env.MEDIA_HELPER_DIR ? join(process.env.MEDIA_HELPER_DIR, name) : undefined,
|
|
join(helperCrateDir(), "target/release", name),
|
|
].filter((path): path is string => typeof path === "string" && path.length > 0);
|
|
}
|
|
|
|
export function resolveHelperBinary(name: HelperBinary): string {
|
|
const found = candidates(name).find((path) => existsSync(path));
|
|
if (!found) throw new Error(`${name} binary not found: set ${ENV[name]} or MEDIA_HELPER_DIR, or run scripts/build-helpers.sh`);
|
|
return found;
|
|
}
|
|
|
|
function newestSource(crate: string): number {
|
|
const files = ["Cargo.toml", "Cargo.lock"].map((f) => join(crate, f));
|
|
const walk = (dir: string): void => {
|
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
const path = join(dir, entry.name);
|
|
if (entry.isDirectory()) walk(path);
|
|
else if (entry.name.endsWith(".rs")) files.push(path);
|
|
}
|
|
};
|
|
walk(join(crate, "src"));
|
|
return Math.max(...files.filter((f) => existsSync(f)).map((f) => statSync(f).mtimeMs));
|
|
}
|
|
|
|
/** Development binaries that are missing or older than the crate sources. Env/packaged binaries are taken as given. */
|
|
export function staleHelpers(): HelperBinary[] {
|
|
const crate = helperCrateDir();
|
|
if (!existsSync(join(crate, "Cargo.toml"))) return [];
|
|
const newest = newestSource(crate);
|
|
return (Object.keys(ENV) as HelperBinary[]).filter((name) => {
|
|
if (process.env[ENV[name]] || process.env.MEDIA_HELPER_DIR) return false;
|
|
const path = join(crate, "target/release", name);
|
|
return !existsSync(path) || statSync(path).mtimeMs < newest;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Tests/scripts: build the crate if a development binary is missing or stale.
|
|
* `--offline --locked`: no network, and the (dependency-free) lockfile must not change.
|
|
* Concurrent callers are serialized by cargo's own build-directory lock.
|
|
*/
|
|
export function ensureHelperBinaries(): boolean {
|
|
if (staleHelpers().length > 0) {
|
|
const built = spawnSync("cargo", ["build", "--release", "--offline", "--locked", "--manifest-path", join(helperCrateDir(), "Cargo.toml")], { stdio: "ignore" });
|
|
if (built.status !== 0) return false;
|
|
}
|
|
try {
|
|
resolveHelperBinary("frame-gate");
|
|
resolveHelperBinary("source-bus");
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|