api: init notification queue

This commit is contained in:
Johannes Kirschbauer
2025-08-11 12:23:41 +02:00
parent 0859a86ce0
commit bb6fab1168
5 changed files with 66 additions and 2 deletions

View File

@@ -1,12 +1,14 @@
import functools
import json
import logging
import threading
from collections.abc import Callable
from dataclasses import dataclass, field
from enum import IntEnum
from time import sleep
from typing import TYPE_CHECKING, Any
from clan_lib.api import MethodRegistry
from clan_lib.api import MethodRegistry, message_queue
from clan_lib.api.tasks import WebThread
from clan_lib.log_manager import LogManager
@@ -69,6 +71,22 @@ class Webview:
if self.size:
self.set_size(self.size)
def __post_init__(self) -> None:
self.setup_notify() # Start the notification loop
def setup_notify(self) -> None:
def loop() -> None:
while True:
try:
msg = message_queue.get() # Blocks until available
js_code = f"window.notifyBus({json.dumps(msg)});"
self.eval(js_code)
except Exception as e:
print("Bridge notify error:", e)
sleep(0.01) # avoid busy loop
threading.Thread(target=loop, daemon=True).start()
@property
def handle(self) -> Any:
"""Get the webview handle, creating it if necessary."""
@@ -129,6 +147,7 @@ class Webview:
webview=self, middleware_chain=tuple(self._middleware), threads={}
)
self._bridge = bridge
return bridge
# Legacy methods for compatibility

View File

@@ -25,7 +25,6 @@ class WebviewBridge(ApiBridge):
def send_api_response(self, response: BackendResponse) -> None:
"""Send response back to the webview client."""
serialized = json.dumps(
dataclass_to_dict(response), indent=4, ensure_ascii=False
)

9
pkgs/clan-app/ui/index.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
import { ProcessMessage } from "./src/hooks/api";
export {};
declare global {
interface Window {
notifyBus: (data: ProcessMessage) => void;
}
}

View File

@@ -99,3 +99,14 @@ export const callApi = <K extends OperationNames>(
},
};
};
export interface ProcessMessage {
topic: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data: any;
origin: string | null;
}
window.notifyBus = (data) => {
console.debug("Channel function called with data:", data);
};

View File

@@ -5,11 +5,13 @@ from collections.abc import Callable
from dataclasses import dataclass
from functools import wraps
from inspect import Parameter, Signature, signature
from queue import Queue
from types import ModuleType
from typing import (
Annotated,
Any,
Literal,
TypedDict,
TypeVar,
get_type_hints,
)
@@ -31,6 +33,30 @@ T = TypeVar("T")
ResponseDataType = TypeVar("ResponseDataType")
class ProcessMessage(TypedDict):
"""
Represents a message to be sent to the UI.
Attributes:
- topic: The topic of the message, used to identify the type of message.
- data: The data to be sent with the message.
- origin: The API operation that this message is related to, if applicable.
"""
topic: str
data: Any
origin: str | None
message_queue: Queue[ProcessMessage] = Queue()
"""
A global message queue for sending messages to the UI
This can be used to send notifications or messages to the UI. Before returning a response.
The clan-app imports the queue as clan_lib.api.message_queue and subscribes to it.
"""
@dataclass
class ApiError:
message: str