Files
esports/streamer/windows/log.ts
Stan Runge 54444a77f0 feat: add native Windows broadcaster and live score modules
- streamer/windows: vash-broadcast.exe (setup/login/start/stop/status/doctor)
  with per-instance OBS, tosu and FFmpeg, a supervised worker, OCR room
  selection and OBS scene reconciliation; built and tested on Linux only
- streamer/relay.ts shared with Vash TV; Cloudflare Access proxy for dev/staging
- worker status validation and live score helpers for the site
- STREAMING_HANDOFF.md and streamer/ALPHA_TEST.md record what is unverified

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:02:25 +00:00

41 lines
1.3 KiB
TypeScript

/** Appends timestamped lines to the instance's log, keeping the last few files. */
import { appendFileSync, existsSync, mkdirSync, renameSync, rmSync, statSync } from 'node:fs';
import { dirname } from 'node:path';
const MAX_BYTES = 10 * 1024 * 1024;
const KEEP = 5;
/** Rotation keeps a multi-hour broadcast's log bounded: worker.log, worker.1.log, … */
function rotate(path: string) {
if (!existsSync(path) || statSync(path).size < MAX_BYTES) return;
const numbered = (n: number) => path.replace(/\.log$/, `.${n}.log`);
rmSync(numbered(KEEP), { force: true });
for (let n = KEEP - 1; n >= 1; n--)
if (existsSync(numbered(n))) renameSync(numbered(n), numbered(n + 1));
renameSync(path, numbered(1));
}
export function fileLogger(path: string, alsoConsole = false) {
mkdirSync(dirname(path), { recursive: true });
let lines = 0;
return (...parts: unknown[]) => {
const text = parts
.map((part) =>
part instanceof Error
? part.message
: typeof part === 'string'
? part
: JSON.stringify(part)
)
.join(' ');
const line = `${new Date().toISOString()} ${text}\n`;
if (alsoConsole) process.stdout.write(line);
try {
if (++lines % 200 === 0) rotate(path);
appendFileSync(path, line);
} catch {
/* a full or locked disk must not stop the broadcast */
}
};
}