Files
Triple-C/app/src/hooks/useDocker.ts
Josh Knapp 3228e6cdd7
All checks were successful
Build App / build-macos (push) Successful in 2m22s
Build App / build-windows (push) Successful in 3m22s
Build App / build-linux (push) Successful in 5m56s
Sync Release to GitHub / sync-release (release) Successful in 1s
fix: Docker status never updates after Docker starts
Replace OnceLock with Mutex<Option<Docker>> in the Rust backend so
failed Docker connections are retried instead of cached permanently.
Add frontend polling (every 5s) when Docker is initially unavailable,
stopping once detected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:46:59 -08:00

123 lines
3.0 KiB
TypeScript

import { useCallback, useRef } from "react";
import { useShallow } from "zustand/react/shallow";
import { listen } from "@tauri-apps/api/event";
import { useAppState } from "../store/appState";
import * as commands from "../lib/tauri-commands";
export function useDocker() {
const {
dockerAvailable,
setDockerAvailable,
imageExists,
setImageExists,
} = useAppState(
useShallow(s => ({
dockerAvailable: s.dockerAvailable,
setDockerAvailable: s.setDockerAvailable,
imageExists: s.imageExists,
setImageExists: s.setImageExists,
}))
);
const checkDocker = useCallback(async () => {
try {
const available = await commands.checkDocker();
setDockerAvailable(available);
return available;
} catch {
setDockerAvailable(false);
return false;
}
}, [setDockerAvailable]);
const checkImage = useCallback(async () => {
try {
const exists = await commands.checkImageExists();
setImageExists(exists);
return exists;
} catch {
setImageExists(false);
return false;
}
}, [setImageExists]);
const buildImage = useCallback(
async (onProgress?: (msg: string) => void) => {
const unlisten = onProgress
? await listen<string>("image-build-progress", (event) => {
onProgress(event.payload);
})
: null;
try {
await commands.buildImage();
setImageExists(true);
} finally {
unlisten?.();
}
},
[setImageExists],
);
const pollingRef = useRef<ReturnType<typeof setInterval> | null>(null);
const startDockerPolling = useCallback(() => {
// Don't start if already polling
if (pollingRef.current) return () => {};
const interval = setInterval(async () => {
try {
const available = await commands.checkDocker();
if (available) {
clearInterval(interval);
pollingRef.current = null;
setDockerAvailable(true);
// Also check image once Docker is available
try {
const exists = await commands.checkImageExists();
setImageExists(exists);
} catch {
setImageExists(false);
}
}
} catch {
// Still not available, keep polling
}
}, 5000);
pollingRef.current = interval;
return () => {
clearInterval(interval);
pollingRef.current = null;
};
}, [setDockerAvailable, setImageExists]);
const pullImage = useCallback(
async (imageName: string, onProgress?: (msg: string) => void) => {
const unlisten = onProgress
? await listen<string>("image-pull-progress", (event) => {
onProgress(event.payload);
})
: null;
try {
await commands.pullImage(imageName);
setImageExists(true);
} finally {
unlisten?.();
}
},
[setImageExists],
);
return {
dockerAvailable,
imageExists,
checkDocker,
checkImage,
buildImage,
pullImage,
startDockerPolling,
};
}