atagen

malice

public
Star0
Watch0
e99ada4450ecaa8f2bbfb50cf78be269cefa8752
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git

Blame: web/src/lib/engine-build.ts

d9be72fdb393atagen2026-10-26 09:23 UTC1
export const ENGINE_CHANNEL = 'malice-engine';
d9be72fdb393atagen2026-10-26 09:23 UTC2
d9be72fdb393atagen2026-10-26 09:23 UTC3
export type HelloAction = 'ignore' | 'yield' | 'announce';
d9be72fdb393atagen2026-10-26 09:23 UTC4
d9be72fdb393atagen2026-10-26 09:23 UTC5
interface BuildStamp {
d9be72fdb393atagen2026-10-26 09:23 UTC6
  seconds: number;
d9be72fdb393atagen2026-10-26 09:23 UTC7
  tag: string;
d9be72fdb393atagen2026-10-26 09:23 UTC8
}
d9be72fdb393atagen2026-10-26 09:23 UTC9
d9be72fdb393atagen2026-10-26 09:23 UTC10
function parseBuild(build: string): BuildStamp | null {
d9be72fdb393atagen2026-10-26 09:23 UTC11
  const match = /^(\d+)-(.+)$/.exec(build);
d9be72fdb393atagen2026-10-26 09:23 UTC12
  return match ? { seconds: Number(match[1]), tag: match[2] } : null;
d9be72fdb393atagen2026-10-26 09:23 UTC13
}
d9be72fdb393atagen2026-10-26 09:23 UTC14
d9be72fdb393atagen2026-10-26 09:23 UTC15
/** Positive when `a` is newer than `b`, null when either is not a build id. */
d9be72fdb393atagen2026-10-26 09:23 UTC16
export function compareBuilds(a: string, b: string): number | null {
d9be72fdb393atagen2026-10-26 09:23 UTC17
  const left = parseBuild(a);
d9be72fdb393atagen2026-10-26 09:23 UTC18
  const right = parseBuild(b);
d9be72fdb393atagen2026-10-26 09:23 UTC19
  if (!left || !right) return null;
d9be72fdb393atagen2026-10-26 09:23 UTC20
  if (left.seconds !== right.seconds) return left.seconds - right.seconds;
d9be72fdb393atagen2026-10-26 09:23 UTC21
  return left.tag < right.tag ? -1 : left.tag > right.tag ? 1 : 0;
d9be72fdb393atagen2026-10-26 09:23 UTC22
}
d9be72fdb393atagen2026-10-26 09:23 UTC23
d9be72fdb393atagen2026-10-26 09:23 UTC24
/**
d9be72fdb393atagen2026-10-26 09:23 UTC25
 * What a worker of build `own` does on hearing a hello from build `other`.
d9be72fdb393atagen2026-10-26 09:23 UTC26
 * A newer peer wins the store lock, so the worker yields. An older peer is
d9be72fdb393atagen2026-10-26 09:23 UTC27
 * told to yield by repeating our own hello, which it will judge the same way.
d9be72fdb393atagen2026-10-26 09:23 UTC28
 */
d9be72fdb393atagen2026-10-26 09:23 UTC29
export function helloAction(own: string, other: string): HelloAction {
d9be72fdb393atagen2026-10-26 09:23 UTC30
  const order = compareBuilds(other, own);
d9be72fdb393atagen2026-10-26 09:23 UTC31
  if (order === null || order === 0) return 'ignore';
d9be72fdb393atagen2026-10-26 09:23 UTC32
  return order > 0 ? 'yield' : 'announce';
d9be72fdb393atagen2026-10-26 09:23 UTC33
}
d9be72fdb393atagen2026-10-26 09:23 UTC34
d9be72fdb393atagen2026-10-26 09:23 UTC35
export const RELOAD_GUARD_MS = 60_000;
d9be72fdb393atagen2026-10-26 09:23 UTC36
d9be72fdb393atagen2026-10-26 09:23 UTC37
/** A superseded tab reloads itself once, so a shell stuck on the old build cannot loop. */
d9be72fdb393atagen2026-10-26 09:23 UTC38
export function mayAutoReload(now: number, lastReload: number | null): boolean {
d9be72fdb393atagen2026-10-26 09:23 UTC39
  return lastReload === null || now - lastReload >= RELOAD_GUARD_MS;
d9be72fdb393atagen2026-10-26 09:23 UTC40
}
d9be72fdb393atagen2026-10-26 09:23 UTC41
d9be72fdb393atagen2026-10-26 09:23 UTC42
export function retryDelay(attempt: number): number {
d9be72fdb393atagen2026-10-26 09:23 UTC43
  return Math.min(1000 * 2 ** attempt, 8000);
d9be72fdb393atagen2026-10-26 09:23 UTC44
}