feat: add image support across web and twilio

This commit is contained in:
Peter Steinberger
2025-11-25 04:58:31 +01:00
parent ac2bdcbea6
commit 948ff7f035
13 changed files with 510 additions and 82 deletions

68
src/media/host.ts Normal file
View File

@@ -0,0 +1,68 @@
import { once } from "node:events";
import fs from "node:fs/promises";
import path from "node:path";
import { danger, warn } from "../globals.js";
import { logInfo, logWarn } from "../logger.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import { ensurePortAvailable, PortInUseError } from "../infra/ports.js";
import { getTailnetHostname } from "../infra/tailscale.js";
import { saveMediaSource } from "./store.js";
import { startMediaServer } from "./server.js";
const DEFAULT_PORT = 42873;
const TTL_MS = 2 * 60 * 1000;
let mediaServer: import("http").Server | null = null;
export type HostedMedia = {
url: string;
id: string;
size: number;
};
export async function ensureMediaHosted(
source: string,
opts: {
port?: number;
startServer?: boolean;
runtime?: RuntimeEnv;
} = {},
): Promise<HostedMedia> {
const port = opts.port ?? DEFAULT_PORT;
const runtime = opts.runtime ?? defaultRuntime;
const saved = await saveMediaSource(source);
const hostname = await getTailnetHostname();
// Decide whether we must start a media server.
const needsServerStart = await isPortFree(port);
if (needsServerStart && !opts.startServer) {
await fs.rm(saved.path).catch(() => {});
throw new Error(
"Media hosting requires the webhook/Funnel server. Start `warelay webhook`/`warelay up` or re-run with --serve-media.",
);
}
if (needsServerStart && opts.startServer) {
if (!mediaServer) {
mediaServer = await startMediaServer(port, TTL_MS, runtime);
logInfo(
`📡 Started temporary media host on http://localhost:${port}/media/:id (TTL ${TTL_MS / 1000}s)`,
runtime,
);
mediaServer.unref?.();
}
}
const url = `https://${hostname}/media/${saved.id}`;
return { url, id: saved.id, size: saved.size };
}
async function isPortFree(port: number) {
try {
await ensurePortAvailable(port);
return true;
} catch (err) {
if (err instanceof PortInUseError) return false;
throw err;
}
}