""" This module provides the CleverBRAG AMQP Adapter for handling API requests via AMQP. The code IS MEANT to be part of CleverBRAG codebase, and has direct dependencies on the CleverBRAG codebase. It is NOT MEANT to be used as a standalone module. It WILL NOT run outside the CleverBRAG context. """ from threading import Thread from typing import Any, List from uuid import UUID # CleverBrag specific imports import core from fastapi.routing import APIRoute from fastapi.security.http import HTTPAuthorizationCredentials from pydantic import BaseModel from shared.abstractions import R2RSerializable, User # AMQP specific imports from amqp.adapter.cleverthis_service_adapter import CleverThisServiceAdapter from amqp.config.amq_configuration import AMQConfiguration from amqp.service.amq_service import AMQService class BRAGArgument: """ This class is used to represent a BRAG API input argument. It is uses FastAPI annotation to define the arguments (the argument type) that are passed as input arguments to the BRAG endpoint. """ def __init__(self, arg: Any): self.arg = arg self.module = arg.__module__ self.cls = arg.__name__ if hasattr(arg, "__name__") else str(arg) self.is_r2r_serializable = issubclass(arg, R2RSerializable) self.is_builtin = self.module == "builtins" self.is_uuid = self.cls == "UUID" self.is_optional = self.cls == "Optional" self.is_list = self.cls == "list" self.is_dict = self.cls == "dict" self.is_base_model = issubclass(arg, BaseModel) self.is_nested = self.is_list or self.is_optional or self.is_dict if self.is_nested and hasattr(arg, "__args__"): self.nested = BRAGArgument(getattr(arg, "__args__")[0]) if self.is_dict: self.nested = (self.nested, BRAGArgument(getattr(arg, "__args__")[1])) else: self.nested = None self.is_nested = False def __repr__(self): return f"{self.module}.{self.cls}" + (f"[{self.nested}]" if self.is_nested else "") def convert_to_argument(arg: BRAGArgument, value: str) -> Any: """ Converts the argument to a string representation. """ try: if arg.cls == "str": return value elif arg.cls == "bool": return str(value).lower() == "true" elif arg.cls == "float": return float(value) elif arg.cls == "int": return int(value) elif arg.is_uuid: return UUID(value) elif arg.is_optional: return convert_to_argument(arg.nested, value) if arg.nested else None elif arg.is_list: return ( [convert_to_argument(arg.nested, v.strip()) for v in value.split(",")] if arg.nested else value.split() ) elif arg.is_dict: return ( { convert_to_argument(arg.nested[0], k.strip()): convert_to_argument( arg.nested[1], v.strip() ) for k, v in (item.split(":") for item in value.split(",")) } if arg.nested else dict(item.split(":") for item in value.split(",")) ) elif arg.is_base_model: return arg.arg.parse_raw(value) else: print(f"Unsupported argument type: {type(arg)}") except Exception as e: print(f"Error converting argument {arg}: {e}") return None class CleverBragAmqpAdapter(CleverThisServiceAdapter): """ CleverBRAG AMQP Adapter for CleverBRAG API. Implements the interface to CleverBRAG API. """ def __init__( self, amq_configuration: AMQConfiguration, routes: List[APIRoute], auth_provider: core.base.providers.auth.AuthProvider, extra_init_data: dict, ): super().__init__( amq_configuration, routes, None, "auth_user", extra_init_data=extra_init_data ) self.auth_provider = auth_provider _amq_service: AMQService = AMQService(amq_configuration, self) self.thread = Thread(target=_amq_service.run) self.thread.start() async def get_current_user(self, token: str) -> User: """ Overrides the default get_current_user method to use the token from the AMQP message. :param token: JWT token from the AMQP message :return: User object """ return await self.auth_provider.auth_wrapper( HTTPAuthorizationCredentials(scheme="Bearer", credentials=token) )