import os from "os"; import { parseCanonicalResourceUri, type RecordKey } from "@atcute/lexicons"; import type { SystemsGazeBarometerCheck, SystemsGazeBarometerHost, SystemsGazeBarometerService, SystemsGazeBarometerState, } from "barometer-lexicon"; import { err, expect, getRecord, ok, putRecord, type CheckUri, type CollectionUri, type Result, type ServiceUri, type StateUri, } from "./utils"; import { systemctlShow } from "./systemd"; import { config } from "./config"; import { now as generateTid } from "@atcute/tid"; export interface State { rkey: RecordKey; record: SystemsGazeBarometerState.Main; } export interface Check { rkey: RecordKey; record: SystemsGazeBarometerCheck.Main; } export interface Service { checks: Set; rkey: RecordKey; record: SystemsGazeBarometerService.Main; } class Store { services: Map; checks: Map; states: Map; host: SystemsGazeBarometerHost.Main | null; hostname: string; constructor() { this.services = new Map(); this.checks = new Map(); this.states = new Map(); this.host = null; this.hostname = os.hostname(); } getOrFetch = async < Nsid extends | "systems.gaze.barometer.state" | "systems.gaze.barometer.check" | "systems.gaze.barometer.service", Uri extends CollectionUri, >( uri: Uri, ): Promise< Result< Uri extends StateUri ? State : Uri extends CheckUri ? Check : Uri extends ServiceUri ? Service : never, string > > => { const parsedUri = expect(parseCanonicalResourceUri(uri)); const nsid = parsedUri.collection; const record = await getRecord(nsid as Nsid, parsedUri.rkey); if (!record.ok) return err(`record not found or is invalid: ${record.error}`); const data = { record: record.value, rkey: parsedUri.rkey, }; switch (nsid) { case "systems.gaze.barometer.state": this.states.set(uri as StateUri, data as State); return ok(data as any); case "systems.gaze.barometer.check": this.checks.set(uri as CheckUri, data as Check); return ok(data as any); case "systems.gaze.barometer.service": this.services.set( uri as ServiceUri, { checks: new Set(), ...data } as Service, ); return ok(data as any); default: throw new Error(`unsupported namespace: ${nsid}`); } }; getServiceFromSystemd = async ( serviceName: string, ): Promise> => { const serviceInfo = await systemctlShow(serviceName); if (serviceInfo.ok) { const record: SystemsGazeBarometerService.Main = { $type: "systems.gaze.barometer.service", name: serviceName, description: serviceInfo.value.description, hostedBy: `at://${config.repoDid}/systems.gaze.barometer.host/${store.hostname}`, }; const rkey = generateTid(); const putAt = await putRecord(record, rkey); const serviceUri = putAt.uri as ServiceUri; const service: Service = { record, checks: new Set(), rkey, }; store.services.set(serviceUri, service); return ok([serviceUri, service]); } else { return err(`could not fetch service from systemd: ${serviceInfo.error}`); } }; } const store = new Store(); export default store;