const RESTART_STATUS_URL = "/o1key/restart/status"; const RESTART_TIMEOUT_MS = 120_000; let restartInProgress = false; async function readJson(response) { const data = await response.json().catch(() => ({})); if (!response.ok) throw new Error(data.error || `请求失败 (${response.status})`); return data; } function delay(milliseconds) { return new Promise((resolve) => window.setTimeout(resolve, milliseconds)); } async function fetchWithTimeout(url, options = {}, timeout = 2_500) { const controller = new AbortController(); const timer = window.setTimeout(() => controller.abort(), timeout); try { return await fetch(url, { ...options, cache: "no-store", signal: controller.signal, }); } finally { window.clearTimeout(timer); } } async function getRestartStatus() { const separator = RESTART_STATUS_URL.includes("?") ? "&" : "?"; const response = await fetchWithTimeout( `${RESTART_STATUS_URL}${separator}_=${Date.now()}` ); return readJson(response); } function setRestartButtonState(button, busy) { if (!button) return; button.disabled = busy; button.setAttribute("aria-busy", String(busy)); button.setAttribute("aria-label", busy ? "ComfyUI 正在重启" : "重启"); button.setAttribute("title", busy ? "ComfyUI 正在重启" : "重启"); const icon = button.querySelector(".side-bar-button-icon"); if (icon) { icon.className = busy ? "pi pi-spinner pi-spin side-bar-button-icon" : "pi pi-refresh side-bar-button-icon"; } const label = button.querySelector(".side-bar-button-label"); if (label) label.textContent = busy ? "重启中" : "重启"; } async function waitForRestart(oldBootId) { const deadline = Date.now() + RESTART_TIMEOUT_MS; while (Date.now() < deadline) { try { const status = await getRestartStatus(); if (status.ready && status.boot_id && status.boot_id !== oldBootId) { const systemStatus = await fetchWithTimeout( `/api/system_stats?_=${Date.now()}` ); if (systemStatus.ok) return; } } catch { // 旧进程退出到新进程监听端口之间,接口暂时不可用是正常状态。 } await delay(1_000); } throw new Error("等待 ComfyUI 重启超时,请查看终端中的错误信息。"); } function reloadAfterRestart() { const url = new URL(window.location.href); url.searchParams.set("o1key_restart", Date.now().toString()); window.location.replace(url.toString()); } export async function startComfyUIRestart() { if (restartInProgress) throw new Error("ComfyUI 正在重启,请稍候。"); restartInProgress = true; let reloadRequested = false; const button = document.querySelector("#o1key-restart-button"); setRestartButtonState(button, true); try { let currentStatus = null; try { currentStatus = await getRestartStatus(); } catch { // POST 响应还会返回旧进程的 boot_id,因此预检失败不阻断重启。 } const response = await fetchWithTimeout("/o1key/restart", { method: "POST", headers: { "Content-Type": "application/json" }, body: "{}", }, 5_000); const result = await readJson(response); const oldBootId = result.boot_id || currentStatus?.boot_id; if (!oldBootId) throw new Error("无法确认当前 ComfyUI 进程标识。"); await waitForRestart(oldBootId); reloadAfterRestart(); reloadRequested = true; } catch (error) { setRestartButtonState(button, false); throw error; } finally { if (!reloadRequested) restartInProgress = false; } }