1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
import fs from "fs/promises";
import { AppPath } from "./path";
import { Log } from "../util/log";
import { Context } from "../util/context";
export namespace App {
const log = Log.create({ service: "app" });
export type Info = Awaited<ReturnType<typeof create>>;
const ctx = Context.create<Info>("app");
async function create(input: { directory: string }) {
const dataDir = AppPath.data(input.directory);
await fs.mkdir(dataDir, { recursive: true });
await Log.file(input.directory);
log.info("created", { path: dataDir });
const services = new Map<
any,
{
state: any;
shutdown?: (input: any) => Promise<void>;
}
>();
const result = {
get services() {
return services;
},
get root() {
return input.directory;
},
};
return result;
}
export function state<State>(
key: any,
init: (app: Info) => State,
shutdown?: (state: Awaited<State>) => Promise<void>,
) {
return () => {
const app = ctx.use();
const services = app.services;
if (!services.has(key)) {
log.info("registering service", { name: key });
services.set(key, {
state: init(app),
shutdown: shutdown,
});
}
return services.get(key)?.state as State;
};
}
export async function use() {
return ctx.use();
}
export async function provide<T extends (app: Info) => any>(
input: { directory: string },
cb: T,
) {
const app = await create(input);
return ctx.provide(app, async () => {
const result = await cb(app);
for (const [key, entry] of app.services.entries()) {
log.info("shutdown", { name: key });
await entry.shutdown?.(await entry.state);
}
return result;
});
}
}
|