import uuid from abc import ABC, abstractmethod from typing import Any import httpx from apps.api.src.models.plugin_instance import PluginInstance from apps.api.src.models.service_connection import ServiceConnection from apps.api.src.security.encryption import decrypt_dict from apps.api.src.services import secret_service class PluginContext: def __init__( self, instance: PluginInstance, connection: ServiceConnection | None, credentials: dict[str, Any] | None, http_client: httpx.AsyncClient, ): self.instance = instance self.connection = connection self.credentials = credentials or {} self.http_client = http_client class PluginConnector(ABC): id: str = "" name: str = "" default_timeout: float = 30.0 def __init__(self, context: PluginContext): self.context = context async def get_credentials(self) -> dict[str, Any]: return self.context.credentials def get_client(self) -> httpx.AsyncClient: return self.context.http_client @abstractmethod async def healthcheck(self) -> dict[str, Any]: pass @abstractmethod async def fetch_widget_data(self, widget_type: str, settings: dict[str, Any]) -> dict[str, Any]: pass async def close(self) -> None: pass async def build_context( db, instance: PluginInstance, ) -> PluginContext: connection = instance.service_connection credentials = None if connection and connection.credentials_id: secret_value = await secret_service.decrypt_secret_value(db, connection.credentials_id) credentials = decrypt_dict(secret_value) client = httpx.AsyncClient( verify=connection.verify_tls if connection else True, timeout=connection.timeout_seconds if connection else 30, follow_redirects=False, ) return PluginContext(instance, connection, credentials, client)