mirror of
https://github.com/jhbruhn/respira.git
synced 2026-01-27 02:13:41 +00:00
Add error handling and documentation to event subscriptions based on Copilot review feedback. Changes: - Added try-catch blocks to all event callbacks for graceful error handling - Added comments documenting that subscriptions persist for app lifetime - Improved JSDoc for onPatternDeleted function with lifecycle details - Added error logging to help debug potential issues Benefits: - Prevents silent failures in event callbacks - Clear documentation about subscription lifecycle - Better developer experience with error messages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
210 lines
6.2 KiB
TypeScript
210 lines
6.2 KiB
TypeScript
import { create } from "zustand";
|
|
import type { PesPatternData } from "../formats/import/pesImporter";
|
|
import { uuidToString } from "../services/PatternCacheService";
|
|
import { onPatternDeleted } from "./storeEvents";
|
|
|
|
/**
|
|
* Machine Cache Store
|
|
*
|
|
* Manages pattern caching and resume functionality.
|
|
* Handles checking for cached patterns on the machine and loading them.
|
|
* Extracted from useMachineStore for better separation of concerns.
|
|
*/
|
|
|
|
interface MachineCacheState {
|
|
// Resume state
|
|
resumeAvailable: boolean;
|
|
resumeFileName: string | null;
|
|
resumedPattern: {
|
|
pesData: PesPatternData;
|
|
uploadedPesData?: PesPatternData;
|
|
patternOffset?: { x: number; y: number };
|
|
patternRotation?: number;
|
|
} | null;
|
|
|
|
// Actions
|
|
checkResume: () => Promise<PesPatternData | null>;
|
|
loadCachedPattern: () => Promise<{
|
|
pesData: PesPatternData;
|
|
uploadedPesData?: PesPatternData;
|
|
patternOffset?: { x: number; y: number };
|
|
patternRotation?: number;
|
|
} | null>;
|
|
|
|
// Helper methods for inter-store communication
|
|
setResumeAvailable: (available: boolean, fileName: string | null) => void;
|
|
clearResumeState: () => void;
|
|
}
|
|
|
|
export const useMachineCacheStore = create<MachineCacheState>((set, get) => ({
|
|
// Initial state
|
|
resumeAvailable: false,
|
|
resumeFileName: null,
|
|
resumedPattern: null,
|
|
|
|
/**
|
|
* Check for resumable pattern on the machine
|
|
* Queries the machine for its current pattern UUID and checks if we have it cached
|
|
*/
|
|
checkResume: async (): Promise<PesPatternData | null> => {
|
|
try {
|
|
// Import here to avoid circular dependency
|
|
const { useMachineStore } = await import("./useMachineStore");
|
|
const { service, storageService } = useMachineStore.getState();
|
|
|
|
console.log("[Resume] Checking for cached pattern...");
|
|
|
|
const machineUuid = await service.getPatternUUID();
|
|
console.log(
|
|
"[Resume] Machine UUID:",
|
|
machineUuid ? uuidToString(machineUuid) : "none",
|
|
);
|
|
|
|
if (!machineUuid) {
|
|
console.log("[Resume] No pattern loaded on machine");
|
|
set({ resumeAvailable: false, resumeFileName: null });
|
|
return null;
|
|
}
|
|
|
|
const uuidStr = uuidToString(machineUuid);
|
|
const cached = await storageService.getPatternByUUID(uuidStr);
|
|
|
|
if (cached) {
|
|
console.log(
|
|
"[Resume] Pattern found in cache:",
|
|
cached.fileName,
|
|
"Offset:",
|
|
cached.patternOffset,
|
|
"Rotation:",
|
|
cached.patternRotation,
|
|
"Has uploaded data:",
|
|
!!cached.uploadedPesData,
|
|
);
|
|
console.log("[Resume] Auto-loading cached pattern...");
|
|
set({
|
|
resumeAvailable: true,
|
|
resumeFileName: cached.fileName,
|
|
resumedPattern: {
|
|
pesData: cached.pesData,
|
|
uploadedPesData: cached.uploadedPesData,
|
|
patternOffset: cached.patternOffset,
|
|
patternRotation: cached.patternRotation,
|
|
},
|
|
});
|
|
|
|
// Fetch pattern info from machine
|
|
try {
|
|
const info = await service.getPatternInfo();
|
|
useMachineStore.setState({ patternInfo: info });
|
|
console.log("[Resume] Pattern info loaded from machine");
|
|
} catch (err) {
|
|
console.error("[Resume] Failed to load pattern info:", err);
|
|
}
|
|
|
|
return cached.pesData;
|
|
} else {
|
|
console.log("[Resume] Pattern on machine not found in cache");
|
|
set({ resumeAvailable: false, resumeFileName: null });
|
|
return null;
|
|
}
|
|
} catch (err) {
|
|
console.error("[Resume] Failed to check resume:", err);
|
|
set({ resumeAvailable: false, resumeFileName: null });
|
|
return null;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Load cached pattern data
|
|
* Used when the user wants to restore a previously uploaded pattern
|
|
*/
|
|
loadCachedPattern: async (): Promise<{
|
|
pesData: PesPatternData;
|
|
uploadedPesData?: PesPatternData;
|
|
patternOffset?: { x: number; y: number };
|
|
patternRotation?: number;
|
|
} | null> => {
|
|
const { resumeAvailable } = get();
|
|
if (!resumeAvailable) return null;
|
|
|
|
try {
|
|
// Import here to avoid circular dependency
|
|
const { useMachineStore } = await import("./useMachineStore");
|
|
const { service, storageService, refreshPatternInfo } =
|
|
useMachineStore.getState();
|
|
|
|
const machineUuid = await service.getPatternUUID();
|
|
if (!machineUuid) return null;
|
|
|
|
const uuidStr = uuidToString(machineUuid);
|
|
const cached = await storageService.getPatternByUUID(uuidStr);
|
|
|
|
if (cached) {
|
|
console.log(
|
|
"[Resume] Loading cached pattern:",
|
|
cached.fileName,
|
|
"Offset:",
|
|
cached.patternOffset,
|
|
"Rotation:",
|
|
cached.patternRotation,
|
|
"Has uploaded data:",
|
|
!!cached.uploadedPesData,
|
|
);
|
|
await refreshPatternInfo();
|
|
return {
|
|
pesData: cached.pesData,
|
|
uploadedPesData: cached.uploadedPesData,
|
|
patternOffset: cached.patternOffset,
|
|
patternRotation: cached.patternRotation,
|
|
};
|
|
}
|
|
|
|
return null;
|
|
} catch (err) {
|
|
console.error(
|
|
"[Resume] Failed to load cached pattern:",
|
|
err instanceof Error ? err.message : "Unknown error",
|
|
);
|
|
return null;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Set resume availability
|
|
* Used by other stores to update resume state
|
|
*/
|
|
setResumeAvailable: (available: boolean, fileName: string | null) => {
|
|
set({
|
|
resumeAvailable: available,
|
|
resumeFileName: fileName,
|
|
...(available === false && { resumedPattern: null }),
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Clear resume state
|
|
* Called when pattern is deleted from machine
|
|
*/
|
|
clearResumeState: () => {
|
|
set({
|
|
resumeAvailable: false,
|
|
resumeFileName: null,
|
|
resumedPattern: null,
|
|
});
|
|
},
|
|
}));
|
|
|
|
// Subscribe to pattern deleted event.
|
|
// This subscription is intended to persist for the lifetime of the application,
|
|
// so the unsubscribe function returned by `onPatternDeleted` is intentionally
|
|
// not stored or called.
|
|
onPatternDeleted(() => {
|
|
try {
|
|
useMachineCacheStore.getState().clearResumeState();
|
|
} catch (error) {
|
|
console.error(
|
|
"[MachineCacheStore] Failed to clear resume state on pattern deleted event:",
|
|
error,
|
|
);
|
|
}
|
|
});
|