atagen

malice

public
Star0
Watch0
976126a62a3c99e6b4bf5c28590eb74706059dc3
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
web/src/lib/engine-build.tsTypescript57 lines1.8 KB
1
export const ENGINE_CHANNEL = 'malice-engine';
2
3
export type HelloAction = 'ignore' | 'yield' | 'announce';
4
5
interface BuildStamp {
6
  seconds: number;
7
  tag: string;
8
}
9
10
function parseBuild(build: string): BuildStamp | null {
11
  const match = /^(\d+)-(.+)$/.exec(build);
12
  return match ? { seconds: Number(match[1]), tag: match[2] } : null;
13
}
14
15
/** Positive when `a` is newer than `b`, null when either is not a build id. */
16
export function compareBuilds(a: string, b: string): number | null {
17
  const left = parseBuild(a);
18
  const right = parseBuild(b);
19
  if (!left || !right) return null;
20
  if (left.seconds !== right.seconds) return left.seconds - right.seconds;
21
  return left.tag < right.tag ? -1 : left.tag > right.tag ? 1 : 0;
22
}
23
24
/**
25
 * What a worker of build `own` does on hearing a hello from build `other`.
26
 * A newer peer wins the store lock, so the worker yields. An older peer is
27
 * told to yield by repeating our own hello, which it will judge the same way.
28
 */
29
export function helloAction(own: string, other: string): HelloAction {
30
  const order = compareBuilds(other, own);
31
  if (order === null || order === 0) return 'ignore';
32
  return order > 0 ? 'yield' : 'announce';
33
}
34
35
export const RELOAD_GUARD_MS = 60_000;
36
37
/** A superseded tab reloads itself once, so a shell stuck on the old build cannot loop. */
38
export function mayAutoReload(now: number, lastReload: number | null): boolean {
39
  return lastReload === null || now - lastReload >= RELOAD_GUARD_MS;
40
}
41
42
export function retryDelay(attempt: number): number {
43
  return Math.min(1000 * 2 ** attempt, 8000);
44
}
45
46
export const RELEASE_TIMEOUT_MS = 5_000;
47
48
export function within(promise: Promise<unknown>, ms: number): Promise<void> {
49
  return new Promise((resolve) => {
50
    const timer = setTimeout(resolve, ms);
51
    const done = () => {
52
      clearTimeout(timer);
53
      resolve();
54
    };
55
    promise.then(done, done);
56
  });
57
}