| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 |
- import { Log } from "@/util/log"
- export namespace State {
- interface Entry {
- state: any
- dispose?: (state: any) => Promise<void>
- }
- const log = Log.create({ service: "state" })
- const recordsByKey = new Map<string, Map<any, Entry>>()
- export function create<S>(root: () => string, init: () => S, dispose?: (state: Awaited<S>) => Promise<void>) {
- return () => {
- const key = root()
- let entries = recordsByKey.get(key)
- if (!entries) {
- entries = new Map<string, Entry>()
- recordsByKey.set(key, entries)
- }
- const exists = entries.get(init)
- if (exists) return exists.state as S
- const state = init()
- entries.set(init, {
- state,
- dispose,
- })
- return state
- }
- }
- export async function dispose(key: string) {
- const entries = recordsByKey.get(key)
- if (!entries) return
- log.info("waiting for state disposal to complete", { key })
- let disposalFinished = false
- setTimeout(() => {
- if (!disposalFinished) {
- log.warn(
- "state disposal is taking an unusually long time - if it does not complete in a reasonable time, please report this as a bug",
- { key },
- )
- }
- }, 10000).unref()
- const tasks: Promise<void>[] = []
- for (const entry of entries.values()) {
- if (!entry.dispose) continue
- const task = Promise.resolve(entry.state)
- .then((state) => entry.dispose!(state))
- .catch((error) => {
- log.error("Error while disposing state:", { error, key })
- })
- tasks.push(task)
- }
- entries.clear()
- recordsByKey.delete(key)
- await Promise.all(tasks)
- disposalFinished = true
- log.info("state disposal completed", { key })
- }
- }
|