import { TextLineStream } from "https://deno.land/std@0.208.0/streams/mod.ts"; export type Channel = ReturnType>; export function channel() { const inner = { queue: [] as T[], resolver: null as (() => void) | null, }; const send = (item: T) => { inner.queue.push(item); if (inner.resolver === null) return; inner.resolver(); inner.resolver = null; }; const receive = async () => { if (inner.queue.length < 1) await new Promise((res) => inner.resolver = res); const [head] = inner.queue.splice(0, 1); return head; }; return { send, receive }; } export function* range(from: number, to: number) { while (from < to) yield from++; } export async function exists(path: string) { try { await Deno.stat(path); return true; } catch (_) { return false; } } export async function next(readable: ReadableStream) { for await (const item of readable) return item; } export function lines(readable: ReadableStream) { return readable .pipeThrough(new TextDecoderStream()) .pipeThrough(new TextLineStream()); } const async_noop = async () => {}; export type LoopProcess = ReturnType; export function loop_process( command: Deno.Command, opts?: { delay?: number; on_start?: () => unknown; on_stop?: () => unknown }, ) { const events = { on_start: opts?.on_start ?? async_noop, on_stop: opts?.on_stop ?? async_noop, }; const kill_sig = channel<"kill">(); async function launch() { while (true) { await events.on_start(); const child_process = command.spawn(); const result = await Promise.any([kill_sig.receive(), child_process.output()]); if (result === "kill") { await events.on_stop(); child_process.kill(); break; } await events.on_stop(); await sleep(opts?.delay ?? 500); } } const looping = launch(); return { kill: async () => { kill_sig.send("kill"), await looping; }, events, looping, }; } export function sleep(ms: number) { return new Promise((resolver) => setTimeout(resolver, ms)); } export async function run(command: string, ...args: string[]) { const { code } = await new Deno.Command(command, { args }).output(); if (code != 0) throw new Error(`command ${command} failed`); } export function log_from(...prefixes: string[]) { const prefix = prefixes.map((p) => `[${p}]`).join("").padStart(10); return function (...args: unknown[]) { console.log(prefix, ...args); }; }