1 Event-Queue-und-TypeScript-API
frank edited this page 2026-07-13 14:39:57 +02:00

Event-Queue und TypeScript-API

FIFO-Semantik

Das Rust-Backend verwaltet genau eine globale, unbeschränkte In-Memory-Queue.

  1. Jedes AppEvent wird hinten eingereiht.
  2. Für den Kopf wird eine Momentaufnahme aller aktuell passenden Listener (type oder *) gebildet.
  3. Ohne Listener wird der Event als skipped abgeschlossen.
  4. Für jeden Listener entsteht eine Delivery mit eigener ID und Deadline.
  5. Der nächste Event beginnt erst, wenn alle Deliveries bestätigt oder automatisch freigegeben sind.

Automatische Freigabe erfolgt bei Listenerfehler, Timeout, Unsubscribe oder Browser-Disconnect. Disconnect gilt sofort als Bestätigung, damit ein OBS-Szenenwechsel nicht blockiert.

Timeouts beginnen bei der Auslieferung. Default sind 10 Sekunden; erlaubt sind 100 ms bis 300 Sekunden. delivery.signal wird zur Deadline abgebrochen.

Die Queue überlebt Browser-Reloads und Szenenwechsel, wird aber bei einem vollständigen Streamertool-Neustart geleert.

TypeScript-API

export interface StreamertoolEvent<T = unknown> {
  id: string;
  source: string;
  type: string;
  payload: T;
  createdAt: string;
}

export interface EventDelivery {
  readonly id: string;
  readonly listenerId: string;
  readonly deadline: string;
  readonly signal: AbortSignal;
  ack(): void;
}

export interface ListenerOptions { timeoutMs?: number }

export type EventHandler<T = unknown> = (
  event: StreamertoolEvent<T>,
  delivery: EventDelivery,
) => void | Promise<void>;

export interface StreamertoolEvents {
  on<T = unknown>(
    type: string | "*",
    handler: EventHandler<T>,
    options?: ListenerOptions,
  ): () => void;
}

delivery.ack() ist idempotent und bestätigt nur diesen Listener. Die Rückgabe oder Auflösung eines Promise bestätigt ausdrücklich nicht automatisch. Fehler geben die betroffene Delivery dagegen sofort frei.

Seriell anzeigen

const off = Streamertool.events.on("twitch.follow", (event, delivery) => {
  show(event.payload);
  setTimeout(() => {
    hide();
    delivery.ack();
  }, 5000);
}, { timeoutMs: 10000 });

Kontrolliert überlappen

Streamertool.events.on("twitch.chat.message", (event, delivery) => {
  appendMessage(event.payload);
  delivery.ack();       // nächster Event darf sofort starten
  animateMessageIn();   // Animation läuft trotzdem weiter
});

WebSocket-Frames

Client: register, unregister, ack, listenerError.

Server: ready, delivery und control. Alle Feldnamen sind camelCase. Registrierungen enthalten stabile Listener-ID, Event-Typ und Timeout; eine Delivery enthält Delivery-ID, Listener-ID, Deadline und den vollständigen Originalevent.