|
import { app } from "../../scripts/app.js";
|
|
import { GroupNodeHandler } from "../core/groupNode.js";
|
|
|
|
class Logger {
|
|
static ERROR = 0;
|
|
static PROBLEM = 1;
|
|
static INFORMATION = 2;
|
|
static DETAIL = 3;
|
|
|
|
static LEVEL = Logger.PROBLEM;
|
|
static TRACE = false;
|
|
|
|
static CAT_AMBIGUITY = 1;
|
|
static last_reported_category = {};
|
|
static category_cooloff = { 1 : 5000 }
|
|
|
|
static log(level, message, array, category) {
|
|
if (category && Logger.last_reported_category[category]) {
|
|
const elapsed = (new Date()) - Logger.last_reported_category[category];
|
|
if (elapsed < Logger.category_cooloff[category]) return;
|
|
}
|
|
if (level <= Logger.LEVEL) {
|
|
console.log(message);
|
|
if (array) for (var i=0; i<array.length; i++) { console.log(array[i]) }
|
|
if (category) Logger.last_reported_category[category] = new Date();
|
|
}
|
|
}
|
|
|
|
static log_call(level, method) {
|
|
if (level <= Logger.LEVEL) {
|
|
method.apply();
|
|
}
|
|
}
|
|
|
|
static log_error(level, message) {
|
|
if (level <= Logger.LEVEL) {
|
|
console.error(message);
|
|
}
|
|
}
|
|
|
|
static trace(message, array, node) {
|
|
if (Logger.TRACE) {
|
|
if (node) { console.log(`TRACE (${node.id}) : ${message}`) } else { console.log(`TRACE : ${message}`) }
|
|
if (array && Logger.LEVEL>=Logger.INFORMATION) for (var i=0; i<array.length; i++) { console.log(` ${i} = ${array[i]}`) }
|
|
}
|
|
}
|
|
}
|
|
|
|
class LoopError extends Error {
|
|
constructor(id, stack, ues) {
|
|
super("Loop detected");
|
|
this.id = id;
|
|
this.stack = [...stack];
|
|
this.ues = [...ues];
|
|
}
|
|
}
|
|
|
|
function find_all_upstream(node_id, links_added) {
|
|
const all_upstream = [];
|
|
const node = get_real_node(node_id);
|
|
node?.inputs?.forEach((input) => {
|
|
const link_id = input.link;
|
|
if (link_id) {
|
|
const link = app.graph.links[link_id];
|
|
if (link) all_upstream.push({id:link.origin_id, slot:link.origin_slot});
|
|
}
|
|
});
|
|
links_added.forEach((la)=>{
|
|
if (get_real_node(la.downstream).id==node.id) {
|
|
all_upstream.push({id:la.upstream, slot:la.upstream_slot, ue:la.controller.toString()})
|
|
}
|
|
});
|
|
if (node.id != get_group_node(node.id).id) {
|
|
const grp_nd = get_group_node(node.id).id;
|
|
const group_data = GroupNodeHandler.getGroupData(get_group_node(node.id));
|
|
const indx = group_data.nodeData.nodes.findIndex((n)=>n.pos[0]==node.pos[0] && n.pos[1]==node.pos[1]);
|
|
if (indx>=0) {
|
|
if (GroupNodeHandler.getGroupData(app.graph._nodes_by_id[grp_nd])?.linksTo?.[indx] ) {
|
|
Object.values(GroupNodeHandler.getGroupData(app.graph._nodes_by_id[grp_nd]).linksTo[indx]).forEach((internal_link) => {
|
|
all_upstream.push({id:`${grp_nd}:${internal_link[0]}`, slot:internal_link[1]});
|
|
});
|
|
}
|
|
if (GroupNodeHandler.getGroupData(app.graph._nodes_by_id[grp_nd]).oldToNewInputMap?.[indx]) {
|
|
Object.values(GroupNodeHandler.getGroupData(app.graph._nodes_by_id[grp_nd]).oldToNewInputMap?.[indx]).forEach((groupInput) => {
|
|
const link_id = get_group_node(node.id).inputs?.[groupInput]?.link;
|
|
if (link_id) {
|
|
const link = app.graph.links[link_id];
|
|
if (link) all_upstream.push({id:link.origin_id, slot:link.origin_slot});
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
return all_upstream;
|
|
}
|
|
|
|
function recursive_follow(node_id, start_node_id, links_added, stack, nodes_cleared, ues, count, slot) {
|
|
const node = get_real_node(node_id);
|
|
if (slot>=0 && GroupNodeHandler.isGroupNode(node)) {
|
|
const mapped = GroupNodeHandler.getGroupData(node).newToOldOutputMap[slot];
|
|
return recursive_follow(`${node.id}:${mapped.node.index}`, start_node_id, links_added, stack, nodes_cleared, ues, count, mapped.slot);
|
|
}
|
|
count += 1;
|
|
if (stack.includes(node.id.toString())) throw new LoopError(node.id, new Set(stack), new Set(ues));
|
|
if (nodes_cleared.has(node.id.toString())) return;
|
|
stack.push(node.id.toString());
|
|
|
|
find_all_upstream(node.id, links_added).forEach((upstream) => {
|
|
if (upstream.ue) ues.push(upstream.ue);
|
|
count = recursive_follow(upstream.id, start_node_id, links_added, stack, nodes_cleared, ues, count, upstream.slot);
|
|
if (upstream.ue) ues.pop();
|
|
})
|
|
|
|
nodes_cleared.add(node.id.toString());
|
|
stack.pop();
|
|
return count;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function node_in_loop(live_nodes, links_added) {
|
|
var nodes_to_check = [];
|
|
const nodes_cleared = new Set();
|
|
live_nodes.forEach((n)=>nodes_to_check.push(get_real_node(n.id).id));
|
|
var count = 0;
|
|
while (nodes_to_check.length>0) {
|
|
const node_id = nodes_to_check.pop();
|
|
count += recursive_follow(node_id, node_id, links_added, [], nodes_cleared, [], 0, -1);
|
|
nodes_to_check = nodes_to_check.filter((nid)=>!nodes_cleared.has(nid.toString()));
|
|
}
|
|
console.log(`node_in_loop made ${count} checks`)
|
|
}
|
|
|
|
|
|
|
|
|
|
function node_is_live(node){
|
|
if (!node) return false;
|
|
if (node.mode===0) return true;
|
|
if (node.mode===2 || node.mode===4) return false;
|
|
Logger.log(Logger.ERROR, `node ${node.id} has mode ${node.mode} - I only understand modes 0, 2 and 4`);
|
|
return true;
|
|
}
|
|
|
|
function node_is_bypassed(node) {
|
|
return (node.mode===4);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function handle_bypass(original_link, type) {
|
|
if (!type || !original_link) return null;
|
|
var link = original_link;
|
|
var parent = get_real_node(link.origin_id);
|
|
if (!parent) return null;
|
|
while (node_is_bypassed(parent)) {
|
|
if (!parent.inputs) return null;
|
|
var link_id;
|
|
if (parent?.inputs[link.origin_slot]?.type == type) link_id = parent.inputs[link.origin_slot].link;
|
|
else link_id = parent.inputs.find((input)=>input.type==type)?.link;
|
|
if (!link_id) { return null; }
|
|
link = app.graph.links[link_id];
|
|
parent = get_real_node(link.origin_id);
|
|
}
|
|
return link;
|
|
}
|
|
|
|
function all_group_nodes() {
|
|
return app.graph._nodes.filter((node) => GroupNodeHandler.isGroupNode(node));
|
|
}
|
|
|
|
function is_in_group(node_id, group_node) {
|
|
return group_node.getInnerNodes().find((inner_node) => (inner_node.id==node_id));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function get_group_node(node_id, level=Logger.ERROR) {
|
|
const nid = node_id.toString();
|
|
var gn = app.graph._nodes_by_id[nid];
|
|
if (!gn && nid.includes(':')) gn = app.graph._nodes_by_id[nid.split(':')[0]];
|
|
if (!gn) gn = all_group_nodes().find((group_node) => is_in_group(nid, group_node));
|
|
if (!gn) Logger.log(level, `get_group node couldn't find ${nid}`)
|
|
return gn;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function get_real_node(node_id, level=Logger.INFORMATION) {
|
|
const nid = node_id.toString();
|
|
var rn = app.graph._nodes_by_id[nid];
|
|
if (!rn && nid.includes(':')) rn = app.graph._nodes_by_id[nid.split(':')[0]]?.getInnerNodes()[nid.split(':')[1]]
|
|
if (!rn) {
|
|
all_group_nodes().forEach((node) => {
|
|
if (!rn) rn = node.getInnerNodes().find((inner_node) => (inner_node.id==nid));
|
|
})
|
|
}
|
|
if (!rn) Logger.log(level, `get_real_node couldn't find ${node_id} - ok during loading, shortly after node deletion etc.`)
|
|
return rn;
|
|
}
|
|
|
|
function get_all_nodes_within(node_id) {
|
|
const node = get_group_node(node_id);
|
|
if (GroupNodeHandler.isGroupNode(node)) return node.getInnerNodes();
|
|
return [];
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function is_connected(input) {
|
|
const link_id = input.link;
|
|
if (link_id === null) return false;
|
|
var the_link = app.graph.links[link_id];
|
|
if (!the_link) return false;
|
|
the_link = handle_bypass(the_link, the_link.type);
|
|
if (!the_link) return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
function is_UEnode(node_or_nodeType) {
|
|
const title = node_or_nodeType.type ?? node_or_nodeType.comfyClass;
|
|
return ((title) && (title.startsWith("Anything Everywhere") || title==="Seed Everywhere" || title==="Prompts Everywhere"))
|
|
}
|
|
function is_helper(node_or_nodeType) {
|
|
const title = node_or_nodeType.type ?? node_or_nodeType.comfyClass;
|
|
return ((title) && (title.startsWith("Simple String")))
|
|
}
|
|
function has_priority_boost(node_or_nodeType) {
|
|
const title = node_or_nodeType.type ?? node_or_nodeType.comfyClass;
|
|
return ((title) && (title == "Anything Everywhere?"))
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function inject(object, methodname, tracetext, injection, injectionthis, injectionarguments) {
|
|
const original = object[methodname];
|
|
object[methodname] = function() {
|
|
Logger.trace(`${tracetext} hijack`, arguments);
|
|
original?.apply(this, arguments);
|
|
injection.apply(injectionthis, injectionarguments);
|
|
}
|
|
}
|
|
|
|
|
|
export { node_in_loop, handle_bypass, node_is_live, is_connected, is_UEnode, is_helper, inject, Logger, get_real_node, get_group_node, get_all_nodes_within, has_priority_boost} |