Files
openswarm/backend/apps/subscriptions/NineRouter/NineRouter.py
T

95 lines
3.1 KiB
Python

"""Singleton that owns 9Router process lifecycle and client access.
All interaction with 9Router from the subscriptions subapp goes through
NineRouter.get() so that mutable state (subprocess handle, background
ensure-task, HTTP client) lives in one place.
"""
import asyncio
from typing import ClassVar, Optional
from pydantic import BaseModel, Field, InstanceOf
from typeguard import typechecked
from backend.apps.subscriptions.NineRouter.helpers.NineRouterProcess.NineRouterProcess import NineRouterProcess
from backend.apps.subscriptions.NineRouter.helpers.NineRouterClient.NineRouterClient import NineRouterClient
class NineRouter(BaseModel):
p_instance: ClassVar[Optional["NineRouter"]] = None
p_process: NineRouterProcess = Field(default_factory=NineRouterProcess)
p_client: NineRouterClient = Field(default_factory=NineRouterClient)
p_ensure_task: Optional[InstanceOf[asyncio.Task]] = None
@classmethod
def get(cls) -> "NineRouter":
if cls.p_instance is None:
cls.p_instance = cls()
return cls.p_instance
# -- lifecycle -------------------------------------------------------------
@typechecked
def is_running(self) -> bool:
return self.p_process.is_running()
@typechecked
async def ensure_running(self) -> None:
await self.p_process.ensure_running()
@typechecked
async def stop(self) -> None:
self.cancel_ensure_task()
await self.p_client.aclose()
self.p_process.stop()
@typechecked
async def ensure_running_background(self) -> None:
"""Kick off ensure_running as a background task if not already in flight."""
if self.p_ensure_task is None or self.p_ensure_task.done():
self.p_ensure_task = asyncio.create_task(self.p_process.ensure_running())
@typechecked
def cancel_ensure_task(self) -> None:
if self.p_ensure_task and not self.p_ensure_task.done():
self.p_ensure_task.cancel()
# -- client ----------------------------------------------------------------
@typechecked
async def get_providers(self) -> list[dict] | dict:
return await self.p_client.get_providers()
@typechecked
async def get_models(self) -> list[dict]:
return await self.p_client.get_models()
@typechecked
async def start_oauth(self, provider: str) -> dict:
return await self.p_client.start_oauth(provider)
@typechecked
async def poll_oauth(
self,
provider: str,
device_code: str,
code_verifier: str | None = None,
extra_data: dict | None = None,
) -> dict:
return await self.p_client.poll_oauth(provider, device_code, code_verifier=code_verifier, extra_data=extra_data)
@typechecked
async def exchange_oauth(
self,
provider: str,
code: str,
redirect_uri: str,
code_verifier: str,
state: str = "",
) -> dict:
return await self.p_client.exchange_oauth(provider, code, redirect_uri, code_verifier, state)
@typechecked
async def disconnect_provider(self, provider_id: str) -> bool:
return await self.p_client.disconnect_provider(provider_id)