"""Cache lazy di client exchange, una istanza per (exchange, env).""" from __future__ import annotations import asyncio import contextlib from collections import defaultdict from collections.abc import Awaitable, Callable from typing import Any, Literal Environment = Literal["testnet", "mainnet"] Builder = Callable[[str, Environment], Awaitable[Any]] class ClientRegistry: def __init__(self, *, builder: Builder) -> None: self._builder = builder self._clients: dict[tuple[str, Environment], Any] = {} self._locks: dict[tuple[str, Environment], asyncio.Lock] = defaultdict( asyncio.Lock ) async def get(self, exchange: str, env: Environment) -> Any: key = (exchange, env) if key in self._clients: return self._clients[key] async with self._locks[key]: if key in self._clients: # double-check return self._clients[key] client = await self._builder(exchange, env) self._clients[key] = client return client async def aclose(self) -> None: for client in self._clients.values(): close = getattr(client, "aclose", None) if close is None: continue with contextlib.suppress(Exception): await close() self._clients.clear()