9cb59d723e
Real bugs found by actually compiling the Tauri crate for the first time: - Cargo.toml declared a [lib] with no src/lib.rs (cargo refused to parse the manifest) — added the standard Tauri 2 main.rs/lib.rs split. - generate_context!() needs real icon files; icons/ only had a .gitkeep. Added placeholder PNG/ICO/ICNS icons. Also simplified: dropped the tray icon + menu (one more moving part not needed yet), and the telemetry store's exponential backoff is now a fixed 3s retry, matching the same simplification made to continuum-proxy's uplink client. Fixed two real TS bugs while typechecking apps/web for the first time (missing @types/node for nuxt.config.ts's process.env access, untyped useFetch call inferring 'never'). Verified: cargo check (desktop), vue-tsc --noEmit (web + ui packages) all clean.
84 lines
1.9 KiB
TypeScript
84 lines
1.9 KiB
TypeScript
import { defineStore } from "pinia";
|
|
|
|
export interface PrinterTelemetry {
|
|
printerId: string;
|
|
farmId: string;
|
|
state: "idle" | "printing" | "paused" | "error" | "offline";
|
|
nozzleTempC: number;
|
|
bedTempC: number;
|
|
progressPct: number;
|
|
updatedAt: string;
|
|
}
|
|
|
|
interface TelemetryState {
|
|
socket: WebSocket | null;
|
|
connected: boolean;
|
|
printers: Record<string, PrinterTelemetry>;
|
|
}
|
|
|
|
const RECONNECT_DELAY_MS = 3_000;
|
|
|
|
export const useTelemetryStore = defineStore("telemetry", {
|
|
state: (): TelemetryState => ({
|
|
socket: null,
|
|
connected: false,
|
|
printers: {},
|
|
}),
|
|
|
|
getters: {
|
|
printerList: (state) => Object.values(state.printers),
|
|
},
|
|
|
|
actions: {
|
|
connect() {
|
|
if (this.socket) return;
|
|
|
|
const config = useRuntimeConfig();
|
|
const client = useSupabaseClient();
|
|
|
|
client.auth.getSession().then(({ data }) => {
|
|
const token = data.session?.access_token ?? "";
|
|
const url = `${config.public.wsBase}/ws/telemetry?token=${encodeURIComponent(token)}`;
|
|
this.open(url);
|
|
});
|
|
},
|
|
|
|
open(url: string) {
|
|
const socket = new WebSocket(url);
|
|
|
|
socket.onopen = () => {
|
|
this.connected = true;
|
|
};
|
|
|
|
socket.onmessage = (event) => {
|
|
try {
|
|
const payload = JSON.parse(event.data) as { type: string; data: PrinterTelemetry };
|
|
if (payload.type === "printer.telemetry") {
|
|
this.printers[payload.data.printerId] = payload.data;
|
|
}
|
|
} catch {
|
|
// Ignore malformed frames rather than crashing the UI.
|
|
}
|
|
};
|
|
|
|
socket.onclose = () => {
|
|
this.connected = false;
|
|
this.socket = null;
|
|
setTimeout(() => this.connect(), RECONNECT_DELAY_MS);
|
|
};
|
|
|
|
socket.onerror = () => {
|
|
socket.close();
|
|
};
|
|
|
|
this.socket = socket;
|
|
},
|
|
|
|
disconnect() {
|
|
this.socket?.close();
|
|
this.socket = null;
|
|
this.connected = false;
|
|
},
|
|
},
|
|
});
|