import { ASSIGN_SCRIPT, COMMIT_DESIRED_SCRIPT, DELIVER_RECEIPT_SCRIPT } from "../../media-control/media-control.service.js"; import type { ControlRedis, RedisReply } from "../../media-control/redis.js"; import type { SignedCommand } from "../../media-control/wire.js"; export class MemoryRedis implements ControlRedis { readonly data = new Map(); readonly sets = new Map>(); readonly published: Array<{ channel: string; message: string }> = []; failDelivery = false; echo: ((command: SignedCommand) => void) | null = null; async get(k: string): Promise { return this.data.get(k) ?? null; } async mget(ks: string[]): Promise> { return ks.map(k => this.data.get(k) ?? null); } async set(k: string, v: string, options?: { nx?: boolean }): Promise { if (options?.nx && this.data.has(k)) return false; this.data.set(k, v); return true; } async incr(k: string): Promise { const n = Number(this.data.get(k) ?? 0) + 1; this.data.set(k, String(n)); return n; } async sadd(k: string, v: string): Promise { const s = this.sets.get(k) ?? new Set(); s.add(v); this.sets.set(k, s); } async smembers(k: string): Promise { return [...(this.sets.get(k) ?? [])]; } async publish(channel: string, message: string): Promise { this.published.push({ channel, message }); if (channel.startsWith("cmd:")) this.echo?.(JSON.parse(message) as SignedCommand); return 1; } async eval(script: string, keys: string[], args: string[]): Promise { const k = (i: number): string => keys[i] ?? "", a = (i: number): string => args[i] ?? ""; if (script === ASSIGN_SCRIPT) { this.data.set(k(0), a(0)); await this.sadd(k(1), a(3)); return 1; } if (script === COMMIT_DESIRED_SCRIPT) { this.data.set(k(0), a(0)); return 1; } if (script !== DELIVER_RECEIPT_SCRIPT) throw new Error("unknown script"); if (this.failDelivery) { this.failDelivery = false; throw new Error("crash before delivery"); } const prior = this.data.get(k(0)); if (prior) return prior; if (this.data.get(k(3)) !== a(3)) return -1; const current = JSON.parse(this.data.get(k(1)) ?? "null") as { desiredVersion: number } | null; if (!current || current.desiredVersion < Number(a(2))) { this.data.set(k(1), a(1)); this.data.set(k(2), a(2)); this.data.set(k(7), JSON.stringify((JSON.parse(a(6)) as { state: unknown }).state)); } this.data.set(k(5), a(4)); const result = JSON.parse(a(0)) as Record; result.receivers = 1; const receipt = JSON.stringify(result); this.data.set(k(0), receipt); await this.publish(k(4), a(4)); await this.publish(k(6), a(6)); return receipt; } close(): void {} }