app.ts 1.8 KB

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