Three faults, all living in the length of the /prompt round trip -- a real
network delay during which the socket is already live and everything ComfyUI
broadcasts arrives.
* Cancel in that window POSTed `{"prompt_id": null}`, and ComfyUI reads a
missing prompt_id as a GLOBAL interrupt: it stops whatever any client is
running. On a shared box that is someone else's generation, and the clicking
user's own request may not even be queued yet. The cancel is remembered and
sent once the run has a name.
* `mine()` treated "no id yet" as "everything is mine", so a stranger's
execution_success and images flipped this run to Done -- showing another
client's picture, for a run that had not started. Messages arriving before the
id are now held and sorted out once it is known; dropping them instead would
lose a run short enough to finish inside the round trip. The buffer is bounded,
because on a shared server it fills with other people's traffic.
* The socket only opened at Generate, so the reattach the client id exists for
never happened: after a reload the app sat at Ready while its own generation
ran on, and pressing Generate queued a SECOND job beside it. It listens at
load and asks ComfyUI's own queue which run belongs to this client -- asked
rather than remembered, because a remembered id reattaches to a run that may
have finished while the page was gone.
Every existing test awaited start() before sending a message, so none of them
ever entered this window. The new ones hold the /prompt response open, which is
what a round trip actually is.
57 lines
2.2 KiB
JavaScript
57 lines
2.2 KiB
JavaScript
// This browser's identity to ComfyUI, and its socket.
|
|
//
|
|
// The id is REMEMBERED. ComfyUI addresses progress and results to the client
|
|
// that queued the run, so a reload with a new id is a reload that hears nothing
|
|
// about the generation already in flight -- the run continues, the GPU time is
|
|
// spent, and the app sits there saying Ready. v4 learned this the hard way and
|
|
// kept a fixed id for exactly this reason.
|
|
|
|
const KEY = "funpack.client-id";
|
|
|
|
export function clientId() {
|
|
try {
|
|
const kept = window.localStorage.getItem(KEY);
|
|
if (kept) return kept;
|
|
} catch { /* private mode: a fresh id per load, which still works */ }
|
|
|
|
const fresh = (globalThis.crypto && globalThis.crypto.randomUUID)
|
|
? globalThis.crypto.randomUUID()
|
|
: `funpack-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
try { window.localStorage.setItem(KEY, fresh); } catch { /* not fatal */ }
|
|
return fresh;
|
|
}
|
|
|
|
/** ComfyUI's socket, on whatever origin served this page. */
|
|
export function connect(id) {
|
|
const scheme = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
return new WebSocket(`${scheme}//${window.location.host}/ws?clientId=${encodeURIComponent(id)}`);
|
|
}
|
|
|
|
/**
|
|
* The prompt id this browser already has running, if any.
|
|
*
|
|
* Asked of ComfyUI's own queue rather than remembered locally: a run this page
|
|
* queued may have finished, been cancelled, or been dequeued while the page was
|
|
* gone, and a remembered id would reattach the UI to a run that no longer
|
|
* exists. `queue_running` items are
|
|
* [number, prompt_id, prompt, extra_data, outputs], and extra_data carries the
|
|
* client_id ComfyUI was given when the run was queued.
|
|
*/
|
|
export async function runningFor(id, { fetch: doFetch = globalThis.fetch, base = "" } = {}) {
|
|
let response;
|
|
try {
|
|
response = await doFetch(`${base}/queue`);
|
|
} catch {
|
|
return null; // no queue reachable: nothing to reattach to
|
|
}
|
|
if (!response.ok) return null;
|
|
|
|
const body = await response.json().catch(() => ({}));
|
|
for (const item of body.queue_running || []) {
|
|
if (!Array.isArray(item) || item.length < 4) continue;
|
|
const [, promptId, , extra] = item;
|
|
if (extra && extra.client_id === id) return promptId || null;
|
|
}
|
|
return null;
|
|
}
|