Merge pull request 'simplify_http_backend' (#5167) from Qubasa/clan-core:simplify_http_backend into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5167
This commit is contained in:
Luis Hebendanz
2025-09-16 14:09:27 +00:00
13 changed files with 41 additions and 22 deletions

View File

@@ -1,16 +1,15 @@
import logging import logging
import threading import threading
from abc import ABC, abstractmethod
from contextlib import ExitStack from contextlib import ExitStack
from dataclasses import dataclass, field from dataclasses import dataclass
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any, Protocol
from clan_lib.api import ApiError, ApiResponse, ErrorDataClass from clan_lib.api import ApiError, ApiResponse, ErrorDataClass
from clan_lib.api.tasks import WebThread from clan_lib.api.tasks import WebThread
from clan_lib.async_run import set_current_thread_opkey, set_should_cancel from clan_lib.async_run import set_current_thread_opkey, set_should_cancel
if TYPE_CHECKING: if TYPE_CHECKING:
from .middleware import Middleware from clan_app.middleware.base import Middleware
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -30,20 +29,17 @@ class BackendResponse:
_op_key: str _op_key: str
@dataclass class ApiBridge(Protocol):
class ApiBridge(ABC):
"""Generic interface for API bridges that can handle method calls from different sources.""" """Generic interface for API bridges that can handle method calls from different sources."""
middleware_chain: tuple["Middleware", ...] 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: ...
def send_api_response(self, response: BackendResponse) -> None:
"""Send response back to the client."""
def process_request(self, request: BackendRequest) -> None: def process_request(self, request: BackendRequest) -> None:
"""Process an API request through the middleware chain.""" """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: with ExitStack() as stack:
context = MiddlewareContext( 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_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.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, ArgumentParsingMiddleware,
LoggingMiddleware, LoggingMiddleware,
MethodExecutionMiddleware, MethodExecutionMiddleware,
) )
from clan_app.deps.http.http_server import HttpApiServer
from clan_app.deps.webview.webview import Size, SizeHint, Webview
log = logging.getLogger(__name__) 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 from clan_app.api.api_bridge import ApiBridge, BackendRequest, BackendResponse
if TYPE_CHECKING: if TYPE_CHECKING:
from clan_app.api.middleware import Middleware from clan_app.middleware.base import Middleware
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

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

View File

@@ -10,11 +10,11 @@ import pytest
from clan_lib.api import MethodRegistry, tasks from clan_lib.api import MethodRegistry, tasks
from clan_lib.async_run import is_async_cancelled 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, ArgumentParsingMiddleware,
MethodExecutionMiddleware, MethodExecutionMiddleware,
) )
from clan_app.deps.http.http_server import HttpApiServer
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

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

View File

@@ -1,6 +1,6 @@
import json import json
import logging import logging
from dataclasses import dataclass from dataclasses import dataclass, field
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from clan_lib.api import dataclass_to_dict 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 from clan_app.api.api_bridge import ApiBridge, BackendRequest, BackendResponse
if TYPE_CHECKING: if TYPE_CHECKING:
from clan_app.middleware.base import Middleware
from .webview import Webview from .webview import Webview
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -19,7 +21,8 @@ class WebviewBridge(ApiBridge):
"""Webview-specific implementation of the API bridge.""" """Webview-specific implementation of the API bridge."""
webview: "Webview" 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: def send_api_response(self, response: BackendResponse) -> None:
"""Send response back to the webview client.""" """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 .argument_parsing import ArgumentParsingMiddleware
from .base import Middleware, MiddlewareContext from .base import Middleware, MiddlewareContext