Compare commits

...

12 Commits

16 changed files with 52 additions and 33 deletions

View File

@@ -8,7 +8,7 @@ The service consists of two roles:
- A `server` role: This is the DNS-server that will be queried when trying to
resolve clan-internal services. It defines the top-level domain.
- A `default` role: This does two things. First, it sets up the nameservers so
thatclan-internal queries are resolved via the `server` machine, while
that clan-internal queries are resolved via the `server` machine, while
external queries are resolved as normal via DHCP. Second, it allows exposing
services (see example below).

12
devFlake/flake.lock generated
View File

@@ -84,11 +84,11 @@
},
"nixpkgs-dev": {
"locked": {
"lastModified": 1757752761,
"narHash": "sha256-HBM2YTKSegLZjdamfqH9KADj2zQBQBNQHmwdrYkatpg=",
"lastModified": 1757924820,
"narHash": "sha256-to/hwbY9/jsRaejPa5oJmPUFZsJfFCB3WReKhD0+/+E=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4b46c744cbd5f9336027dff287e74ead84d80041",
"rev": "aa54acd34af0e86f49d55ea52823031e2da399df",
"type": "github"
},
"original": {
@@ -107,11 +107,11 @@
]
},
"locked": {
"lastModified": 1757624466,
"narHash": "sha256-25ExS2AkQD05Jf0Y2Wnn5KHpucN2d3ObEQOVaDh7ubg=",
"lastModified": 1757885130,
"narHash": "sha256-56CMb5W/pgjKLh0bx2ekhn5rde/YmgR63HAqrY9/BCw=",
"owner": "NuschtOS",
"repo": "search",
"rev": "da8bcb74407e41d334fc79081fdd8948b795bd6f",
"rev": "fae3c59a646e00c4b1d359c50b27458a0713d2fd",
"type": "github"
},
"original": {

8
flake.lock generated
View File

@@ -13,11 +13,11 @@
]
},
"locked": {
"lastModified": 1757300813,
"narHash": "sha256-JYQl+8nJYImg/inqotu9nEPcTXrRJixFN6sOfn6Tics=",
"rev": "b5f2157bcd26c73551374cd6e5b027b0119b2f3d",
"lastModified": 1757905600,
"narHash": "sha256-Yd7buL9N7N7IaDVViItqP9HsECfnlDFykxvvNgMYcKk=",
"rev": "c10c4002bdc5aef040fcbb814d5f482e82dc8345",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/b5f2157bcd26c73551374cd6e5b027b0119b2f3d.tar.gz"
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/c10c4002bdc5aef040fcbb814d5f482e82dc8345.tar.gz"
},
"original": {
"type": "tarball",

View File

@@ -1,16 +1,15 @@
import logging
import threading
from abc import ABC, abstractmethod
from contextlib import ExitStack
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Protocol
from clan_lib.api import ApiError, ApiResponse, ErrorDataClass
from clan_lib.api.tasks import WebThread
from clan_lib.async_run import set_current_thread_opkey, set_should_cancel
if TYPE_CHECKING:
from .middleware import Middleware
from clan_app.middleware.base import Middleware
log = logging.getLogger(__name__)
@@ -30,20 +29,17 @@ class BackendResponse:
_op_key: str
@dataclass
class ApiBridge(ABC):
class ApiBridge(Protocol):
"""Generic interface for API bridges that can handle method calls from different sources."""
middleware_chain: tuple["Middleware", ...]
threads: dict[str, WebThread] = field(default_factory=dict)
threads: dict[str, WebThread]
@abstractmethod
def send_api_response(self, response: BackendResponse) -> None:
"""Send response back to the client."""
def send_api_response(self, response: BackendResponse) -> None: ...
def process_request(self, request: BackendRequest) -> None:
"""Process an API request through the middleware chain."""
from .middleware import MiddlewareContext # noqa: PLC0415
from clan_app.middleware.base import MiddlewareContext # noqa: PLC0415
with ExitStack() as stack:
context = MiddlewareContext(

View File

@@ -0,0 +1,20 @@
"""Compatibility wrapper for relocated middleware components.
This module preserves the legacy import path ``clan_app.api.middleware`` while
the actual middleware implementations now live in ``clan_app.middleware``.
"""
from __future__ import annotations
from warnings import warn
import clan_app.middleware as _middleware
from clan_app.middleware import * # noqa: F403
warn(
"clan_app.api.middleware is deprecated; use clan_app.middleware instead",
DeprecationWarning,
stacklevel=2,
)
__all__ = _middleware.__all__

View File

@@ -12,13 +12,13 @@ from clan_lib.log_manager import LogGroupConfig, LogManager
from clan_lib.log_manager import api as log_manager_api
from clan_app.api.file_gtk import get_clan_folder, get_system_file
from clan_app.api.middleware import (
from clan_app.deps.http.http_server import HttpApiServer
from clan_app.deps.webview.webview import Size, SizeHint, Webview
from clan_app.middleware import (
ArgumentParsingMiddleware,
LoggingMiddleware,
MethodExecutionMiddleware,
)
from clan_app.deps.http.http_server import HttpApiServer
from clan_app.deps.webview.webview import Size, SizeHint, Webview
log = logging.getLogger(__name__)

View File

@@ -21,7 +21,7 @@ from clan_lib.async_run import (
from clan_app.api.api_bridge import ApiBridge, BackendRequest, BackendResponse
if TYPE_CHECKING:
from clan_app.api.middleware import Middleware
from clan_app.middleware.base import Middleware
log = logging.getLogger(__name__)

View File

@@ -8,7 +8,7 @@ from clan_lib.api import MethodRegistry
from clan_lib.api.tasks import WebThread
if TYPE_CHECKING:
from clan_app.api.middleware import Middleware
from clan_app.middleware.base import Middleware
from .http_bridge import HttpBridge

View File

@@ -10,11 +10,11 @@ import pytest
from clan_lib.api import MethodRegistry, tasks
from clan_lib.async_run import is_async_cancelled
from clan_app.api.middleware import (
from clan_app.deps.http.http_server import HttpApiServer
from clan_app.middleware import (
ArgumentParsingMiddleware,
MethodExecutionMiddleware,
)
from clan_app.deps.http.http_server import HttpApiServer
log = logging.getLogger(__name__)

View File

@@ -19,7 +19,7 @@ from ._webview_ffi import (
from .webview_bridge import WebviewBridge
if TYPE_CHECKING:
from clan_app.api.middleware import Middleware
from clan_app.middleware.base import Middleware
log = logging.getLogger(__name__)

View File

@@ -1,6 +1,6 @@
import json
import logging
from dataclasses import dataclass
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
from clan_lib.api import dataclass_to_dict
@@ -9,6 +9,8 @@ from clan_lib.api.tasks import WebThread
from clan_app.api.api_bridge import ApiBridge, BackendRequest, BackendResponse
if TYPE_CHECKING:
from clan_app.middleware.base import Middleware
from .webview import Webview
log = logging.getLogger(__name__)
@@ -19,7 +21,8 @@ class WebviewBridge(ApiBridge):
"""Webview-specific implementation of the API bridge."""
webview: "Webview"
threads: dict[str, WebThread] # Inherited from ApiBridge
middleware_chain: tuple["Middleware", ...]
threads: dict[str, WebThread] = field(default_factory=dict)
def send_api_response(self, response: BackendResponse) -> None:
"""Send response back to the webview client."""

View File

@@ -1,4 +1,4 @@
"""Middleware components for the webview API bridge."""
"""Middleware components shared by API bridge implementations."""
from .argument_parsing import ArgumentParsingMiddleware
from .base import Middleware, MiddlewareContext