Add batch image chooser gate

This commit is contained in:
2026-07-12 16:24:02 +02:00
parent 690278b592
commit dc2247d7b0
8 changed files with 920 additions and 13 deletions
+83 -1
View File
@@ -1,5 +1,7 @@
"""Blocking choice bus for the Image Gate node. Stdlib only — no comfy/torch."""
"""Blocking coordination for manual gate nodes. Stdlib only — no comfy/torch."""
import threading
import time
import uuid
class GateCancelled(Exception):
@@ -11,6 +13,11 @@ class GateBus:
masks = {} # node_id(str) -> PNG bytes
payloads = {} # node_id(str) -> arbitrary payload (e.g., edited text)
cancelled = False
active_tokens = {} # node_id(str) -> per-run token for scoped waiters
token_payloads = {} # (node_id, token) -> arbitrary payload
token_cancelled = set()
token_contexts = {} # (node_id, token) -> waiter-specific validation data
token_lock = threading.Lock()
@classmethod
def arm(cls, node_id):
@@ -57,3 +64,78 @@ class GateBus:
raise GateCancelled()
time.sleep(period)
return cls.payloads.pop(sid)
@classmethod
def arm_token(cls, node_id, context=None):
"""Open a run-scoped channel and invalidate any older run for the node."""
sid = str(node_id)
with cls.token_lock:
old_token = cls.active_tokens.get(sid)
if old_token is not None:
old_key = (sid, old_token)
cls.token_payloads.pop(old_key, None)
cls.token_cancelled.discard(old_key)
cls.token_contexts.pop(old_key, None)
token = uuid.uuid4().hex
key = (sid, token)
cls.active_tokens[sid] = token
cls.token_contexts[key] = context
return token
@classmethod
def token_context(cls, node_id, token):
sid = str(node_id)
with cls.token_lock:
if cls.active_tokens.get(sid) != token:
return None
return cls.token_contexts.get((sid, token))
@classmethod
def put_token_payload(cls, node_id, token, value):
sid = str(node_id)
with cls.token_lock:
if cls.active_tokens.get(sid) != token:
return False
cls.token_payloads[(sid, token)] = value
return True
@classmethod
def cancel_token(cls, node_id, token):
sid = str(node_id)
with cls.token_lock:
if cls.active_tokens.get(sid) != token:
return False
cls.token_cancelled.add((sid, token))
return True
@classmethod
def wait_token_payload(cls, node_id, token, period=0.1, should_cancel=None):
sid = str(node_id)
key = (sid, token)
while True:
with cls.token_lock:
superseded = cls.active_tokens.get(sid) != token
cancelled = key in cls.token_cancelled
if superseded or cancelled:
cls.token_cancelled.discard(key)
raise GateCancelled()
if key in cls.token_payloads:
return cls.token_payloads.pop(key)
if should_cancel is not None and should_cancel():
with cls.token_lock:
cls.token_cancelled.discard(key)
raise GateCancelled()
time.sleep(period)
@classmethod
def disarm_token(cls, node_id, token):
sid = str(node_id)
key = (sid, token)
with cls.token_lock:
if cls.active_tokens.get(sid) == token:
cls.active_tokens.pop(sid, None)
cls.token_payloads.pop(key, None)
cls.token_cancelled.discard(key)
cls.token_contexts.pop(key, None)