From 8818dac640307ec622f23ceea957bd9eb9067378 Mon Sep 17 00:00:00 2001 From: Bryce Zuccaro Date: Fri, 14 Aug 2026 10:46:42 -0600 Subject: [PATCH] feat: add shared runtime and PI datasource handlers --- src/lib/datasources.ts | 45 +++++++++++++++++++++++++++++++++++++++ src/lib/runtime.ts | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/lib/datasources.ts create mode 100644 src/lib/runtime.ts diff --git a/src/lib/datasources.ts b/src/lib/datasources.ts new file mode 100644 index 0000000..703a008 --- /dev/null +++ b/src/lib/datasources.ts @@ -0,0 +1,45 @@ +import streamDeck from "@elgato/streamdeck"; +import { fetchMetrics, fetchModels } from "./llamaswap"; +import { gpuInfos, parseGpuMetrics } from "./metrics-parser"; +import { cfgFromSettings, type CfgSettings } from "./util"; + +interface DataSourceItem { + label: string; + value: string; +} + +export function registerDataSources(): void { + streamDeck.ui.onSendToPlugin(async (ev) => { + const request = ev.payload as { event?: string } | undefined; + const event = request?.event; + if (!event) return; + const settings = await ev.action.getSettings(); + + if (event === "models") { + let items: DataSourceItem[] = []; + try { + const models = await fetchModels(cfgFromSettings(settings)); + items = models.map((m) => ({ label: `${m.id} (${m.status})`, value: m.id })); + } catch { + items = []; + } + await streamDeck.ui.sendToPropertyInspector({ event, items }); + return; + } + + if (event === "gpus") { + let items: DataSourceItem[] = []; + try { + const text = await fetchMetrics(cfgFromSettings(settings)); + const gpus = gpuInfos(parseGpuMetrics(text)); + items = [ + { label: "All GPUs", value: "all" }, + ...gpus.map((g) => ({ label: `GPU ${g.id} ยท ${g.name}`, value: g.id })), + ]; + } catch { + items = [{ label: "All GPUs", value: "all" }]; + } + await streamDeck.ui.sendToPropertyInspector({ event, items }); + } + }); +} diff --git a/src/lib/runtime.ts b/src/lib/runtime.ts new file mode 100644 index 0000000..f5e89e0 --- /dev/null +++ b/src/lib/runtime.ts @@ -0,0 +1,48 @@ +import { EventFeed } from "./event-feed"; +import { InflightTracker } from "./inflight-tracker"; +import { MetricsPoller } from "./metrics-poller"; +import { type LlamaSwapConfig } from "./util"; + +class Runtime { + readonly tracker = new InflightTracker(); + offline = true; + private feed?: EventFeed; + private poller?: MetricsPoller; + private listeners = new Set<() => void>(); + + ensureConnections(cfg: LlamaSwapConfig): void { + if (!this.feed) { + this.feed = new EventFeed(cfg, (ev) => { + this.tracker.apply(ev); + this.emit(); + }); + this.feed.setStatusHandler((connected) => { + this.offline = !connected; + this.emit(); + }); + this.feed.start(); + } + if (!this.poller) { + this.poller = new MetricsPoller(cfg); + this.poller.on(() => this.emit()); + this.poller.start(); + } + } + + get pollerInstance(): MetricsPoller | undefined { + return this.poller; + } + + subscribe(listener: () => void): () => void { + this.listeners.add(listener); + return () => { + this.listeners.delete(listener); + }; + } + + private emit(): void { + for (const listener of this.listeners) listener(); + } +} + +export const runtime = new Runtime();