fix: support multiple keys per action and harden runtime/parsing
This commit is contained in:
+40
-22
@@ -5,6 +5,7 @@ import streamDeck, {
|
||||
type KeyDownEvent,
|
||||
SingletonAction,
|
||||
type WillAppearEvent,
|
||||
type WillDisappearEvent,
|
||||
} from "@elgato/streamdeck";
|
||||
import { type GpuMetricKind } from "../lib/metrics-parser";
|
||||
import { renderGpuGraph, svgDataUrl } from "../lib/render";
|
||||
@@ -16,52 +17,69 @@ type GpuSettings = CfgSettings & {
|
||||
metric?: GpuMetricKind;
|
||||
};
|
||||
|
||||
type GpuState = {
|
||||
settings: GpuSettings;
|
||||
action?: KeyAction<GpuSettings>;
|
||||
unsubscribe?: () => void;
|
||||
lastSvg?: string;
|
||||
};
|
||||
|
||||
@action({ UUID: "com.bryce.llamawatch.gpu" })
|
||||
export class GpuGraph extends SingletonAction<GpuSettings> {
|
||||
private settings: GpuSettings = {};
|
||||
private action?: KeyAction<GpuSettings>;
|
||||
private unsubscribe?: () => void;
|
||||
private lastSvg?: string;
|
||||
private states = new Map<string, GpuState>();
|
||||
|
||||
private stateFor(action: KeyAction<GpuSettings>): GpuState {
|
||||
let state = this.states.get(action.id);
|
||||
if (!state) {
|
||||
state = { settings: {} };
|
||||
this.states.set(action.id, state);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
override onWillAppear(ev: WillAppearEvent<GpuSettings>): void {
|
||||
if (!ev.action.isKey()) return;
|
||||
this.settings = ev.payload.settings;
|
||||
this.action = ev.action;
|
||||
runtime.ensureConnections(cfgFromSettings(this.settings));
|
||||
this.unsubscribe = runtime.subscribe(() => this.render());
|
||||
this.render();
|
||||
const state = this.stateFor(ev.action);
|
||||
state.settings = ev.payload.settings;
|
||||
state.action = ev.action;
|
||||
runtime.ensureConnections(cfgFromSettings(state.settings));
|
||||
state.unsubscribe = runtime.subscribe(() => this.render(state));
|
||||
this.render(state);
|
||||
}
|
||||
|
||||
override onWillDisappear(): void {
|
||||
this.unsubscribe?.();
|
||||
this.unsubscribe = undefined;
|
||||
this.action = undefined;
|
||||
override onWillDisappear(ev: WillDisappearEvent<GpuSettings>): void {
|
||||
const state = this.states.get(ev.action.id);
|
||||
if (!state) return;
|
||||
state.unsubscribe?.();
|
||||
this.states.delete(ev.action.id);
|
||||
}
|
||||
|
||||
override onDidReceiveSettings(ev: DidReceiveSettingsEvent<GpuSettings>): void {
|
||||
if (!ev.action.isKey()) return;
|
||||
this.settings = ev.payload.settings;
|
||||
this.action = ev.action;
|
||||
this.render();
|
||||
const state = this.stateFor(ev.action);
|
||||
state.settings = ev.payload.settings;
|
||||
state.action = ev.action;
|
||||
runtime.ensureConnections(cfgFromSettings(state.settings));
|
||||
this.render(state);
|
||||
}
|
||||
|
||||
override onKeyDown(ev: KeyDownEvent<GpuSettings>): void {
|
||||
void streamDeck.system.openUrl(`${cfgFromSettings(ev.payload.settings).baseUrl}/ui`);
|
||||
}
|
||||
|
||||
private render(): void {
|
||||
const action = this.action;
|
||||
private render(state: GpuState): void {
|
||||
const action = state.action;
|
||||
if (!action) return;
|
||||
const poller = runtime.pollerInstance;
|
||||
const gpuId = this.settings.gpuId ?? "all";
|
||||
const metric = this.settings.metric ?? "util_percent";
|
||||
const gpuId = state.settings.gpuId ?? "all";
|
||||
const metric = state.settings.metric ?? "util_percent";
|
||||
const value = poller?.getValue(gpuId, metric);
|
||||
const history = poller?.getHistory(gpuId, metric) ?? [];
|
||||
const offline = !poller || poller.isOffline();
|
||||
const gpuName = gpuId === "all" ? "ALL GPUS" : this.gpuLabel(gpuId);
|
||||
const svg = renderGpuGraph({ gpuName, metric, value, history, offline });
|
||||
if (svg === this.lastSvg) return;
|
||||
this.lastSvg = svg;
|
||||
if (svg === state.lastSvg) return;
|
||||
state.lastSvg = svg;
|
||||
void action.setImage(svgDataUrl(svg));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user