51 lines
2.4 KiB
TypeScript
51 lines
2.4 KiB
TypeScript
import { scopedFile } from '~/shared/studio2/contracts.mjs';
|
|
import { sharedGpuHeaders, withSharedGpuStart } from '../sharedGpu';
|
|
import { records, saveRecord } from './store';
|
|
|
|
/** Called only after the output and handoff frame are durably saved. */
|
|
export async function purge(r: any, includeCurrent = true) {
|
|
const config = useRuntimeConfig(), prefix = String(config.comfyFilenamePrefix);
|
|
const pending = r.cleanupPending || [];
|
|
const files = [...pending, ...(includeCurrent ? r.files || [] : [])].filter((file, i, all) => all.findIndex(f => f.filename === file.filename && f.subfolder === file.subfolder && f.type === file.type) === i);
|
|
r.cleanupPending = files;
|
|
r.purgeResult = 'Cleanup pending';
|
|
saveRecord(r);
|
|
if (!files.length) return;
|
|
try {
|
|
if (files.some(file => !scopedFile(file, prefix))) throw new Error('Cleanup manifest is outside this studio');
|
|
for (let offset = 0; offset < files.length; offset += 100) {
|
|
const batch = files.slice(offset, offset + 100);
|
|
const response = await fetch(String(config.comfyControlUrl).replace(/\/$/, '') + '/studio2/purge', {
|
|
method: 'POST', headers: { 'Content-Type': 'application/json', ...sharedGpuHeaders() },
|
|
body: JSON.stringify({ prefix, files: batch }), signal: AbortSignal.timeout(12000)
|
|
});
|
|
const result = await response.json() as any;
|
|
if (!response.ok || !result.ok || result.cleared !== batch.length) throw new Error(`Local cleanup was not confirmed (${response.status})`);
|
|
r.cleanupPending = files.slice(offset + batch.length);
|
|
saveRecord(r);
|
|
}
|
|
r.purgeResult = 'Cleared input + output';
|
|
r.cleanupError = '';
|
|
} catch (error: any) {
|
|
r.cleanupError = error.message || 'Local cleanup unavailable';
|
|
console.warn('[Studio 2 cleanup]', r.id, r.cleanupError);
|
|
}
|
|
saveRecord(r);
|
|
}
|
|
|
|
let retrying = false;
|
|
export async function retryCleanup() {
|
|
if (retrying) return;
|
|
retrying = true;
|
|
try {
|
|
const pending = records().filter(r => r.cleanupPending?.length && ['complete', 'failed', 'cancelled'].includes(r.state));
|
|
if (!pending.length) return;
|
|
await withSharedGpuStart(async () => {
|
|
for (const r of pending) {
|
|
// Never add a later failed shot's unsaved files to the saved cleanup manifest.
|
|
await purge(r, false);
|
|
}
|
|
}, async () => {});
|
|
} finally { retrying = false; }
|
|
}
|