mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-07-13 20:21:16 -03:00
fix(registry): handle compound subgraph node IDs, add proactive node push from graph hooks
- Handle compound node IDs (e.g. "252:0") from expanded group subgraphs to fix 400 Bad Request on workflows with group nodes - Frontend proactively pushes node data via afterConfigureGraph and LiteGraph hooks (onNodeAdded/onNodeRemoved/graphChanged), eliminating WebSocket round-trip latency for most "Send to Workflow" operations - Add content-fingerprint dedup to skip duplicate register-nodes POSTs - Fast-path cache returns immediately when tabs are registered (including 0-node registrations), avoiding unnecessary WS refresh cycles - Distinguish "Empty Registry" from other errors in standalone UI toast - Reduce WS refresh timeout 2s→0.5s, add cooldown and lock to prevent concurrent refresh storms - All [LM:Registry] logs at DEBUG level
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { getAllGraphNodes, getNodeReference, getNodeFromGraph } from "./utils.js";
|
||||
import { getAllGraphNodes, getNodeReference, getNodeFromGraph, chainCallback } from "./utils.js";
|
||||
import { ensureLmStyles } from "./lm_styles_loader.js";
|
||||
|
||||
const DEBOUNCE_DELAY = 500;
|
||||
|
||||
const LORA_NODE_CLASSES = new Set([
|
||||
"Lora Loader (LoraManager)",
|
||||
"Lora Stacker (LoraManager)",
|
||||
@@ -79,6 +81,7 @@ app.registerExtension({
|
||||
|
||||
setup() {
|
||||
ensureLmStyles();
|
||||
this._log("extension initialized, clientId=%s", api.clientId ?? api.initialClientId ?? "(pending)");
|
||||
|
||||
api.addEventListener("lora_registry_refresh", () => {
|
||||
this.refreshRegistry();
|
||||
@@ -88,10 +91,64 @@ app.registerExtension({
|
||||
this.applyWidgetUpdate(event?.detail ?? {});
|
||||
});
|
||||
|
||||
// React to marker changes from the Node Marker extension
|
||||
window.addEventListener("lm_marker_changed", () => {
|
||||
this.refreshRegistry();
|
||||
});
|
||||
|
||||
this._hookGraphChanges();
|
||||
},
|
||||
|
||||
async afterConfigureGraph(_missingNodeTypes, _app) {
|
||||
this._log("afterConfigureGraph: workflow loaded (%s missing types)", _missingNodeTypes?.length ?? 0);
|
||||
await this.refreshRegistry();
|
||||
},
|
||||
|
||||
_hookGraphChanges() {
|
||||
const graph = app.graph;
|
||||
if (!graph) {
|
||||
this._log("app.graph not available, skipping proactive hooks");
|
||||
return;
|
||||
}
|
||||
|
||||
let hooksInstalled = 0;
|
||||
|
||||
const scheduleRefresh = (source) => {
|
||||
if (this._debounceTimer != null) {
|
||||
clearTimeout(this._debounceTimer);
|
||||
}
|
||||
this._debounceTimer = setTimeout(() => {
|
||||
this._debounceTimer = null;
|
||||
this.refreshRegistry();
|
||||
}, DEBOUNCE_DELAY);
|
||||
};
|
||||
|
||||
try {
|
||||
chainCallback(graph, "onNodeAdded", () => scheduleRefresh("onNodeAdded"));
|
||||
chainCallback(graph, "onNodeRemoved", () => scheduleRefresh("onNodeRemoved"));
|
||||
hooksInstalled += 2;
|
||||
} catch (e) {
|
||||
this._log("failed to chain LiteGraph hooks: %s", e.message);
|
||||
}
|
||||
|
||||
if (typeof api.addEventListener === "function") {
|
||||
try {
|
||||
api.addEventListener("graphChanged", () => scheduleRefresh("graphChanged"));
|
||||
hooksInstalled += 1;
|
||||
} catch (_e) {
|
||||
// graphChanged may not be available on older ComfyUI versions
|
||||
}
|
||||
}
|
||||
|
||||
this._log("%s proactive hooks installed on graph", hooksInstalled);
|
||||
},
|
||||
|
||||
_log(format, ...args) {
|
||||
const ts = new Date().toISOString().slice(11, 23);
|
||||
let msg = format;
|
||||
for (const arg of args) {
|
||||
msg = msg.replace(/%s/g, String(arg));
|
||||
}
|
||||
console.debug(`[LM:Registry ${ts}] ${msg}`);
|
||||
},
|
||||
|
||||
async refreshRegistry() {
|
||||
@@ -115,7 +172,6 @@ app.registerExtension({
|
||||
const hasTextWidget = TEXT_CAPABLE_CLASSES.has(node.comfyClass);
|
||||
const markerRole = node.properties?.lm_marker_role ?? null;
|
||||
|
||||
// Skip nodes with no relevant capability UNLESS they are marked
|
||||
if (!supportsLora && !hasTargetWidget && !hasTextWidget && !markerRole) {
|
||||
continue;
|
||||
}
|
||||
@@ -146,6 +202,17 @@ app.registerExtension({
|
||||
});
|
||||
}
|
||||
|
||||
const clientId = api.clientId ?? api.initialClientId ?? "";
|
||||
|
||||
// Content-based dedup: skip POST if identical to last sent payload.
|
||||
const fingerprint = JSON.stringify(
|
||||
workflowNodes.map(n => `${n.graph_id}:${n.node_id}|${n.marker_role ?? ""}|${n.mode ?? 0}`).sort()
|
||||
);
|
||||
if (fingerprint === this._lastFingerprint) {
|
||||
return;
|
||||
}
|
||||
this._lastFingerprint = fingerprint;
|
||||
|
||||
const response = await fetch("/api/lm/register-nodes", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
@@ -153,7 +220,7 @@ app.registerExtension({
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nodes: workflowNodes,
|
||||
client_id: api.clientId ?? api.initialClientId ?? "",
|
||||
client_id: clientId,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user