from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass from backend.data.contracts import DataUsage from backend.data.policy import DataSourcePolicy from backend.data.providers import IfindProvider, TushareProvider from chart_data_provider import EastmoneyChartClient, MarketChartClient from ifind_client import IfindHttpClient from realtime_aggregator import WebRealtimeAggregator from tushare_client import TushareClient @dataclass(frozen=True) class DataGateway: policy: DataSourcePolicy tushare_provider: TushareProvider ifind_provider: IfindProvider chart_data: MarketChartClient realtime_observer: WebRealtimeAggregator @property def ifind(self) -> IfindHttpClient: return self.ifind_provider.client def tushare( self, dataset_id: str = "", usage: DataUsage = "calculation", ) -> TushareClient: if dataset_id: self.policy.assert_allowed(dataset_id, "tushare", usage) return self.tushare_provider.client() def assert_source(self, dataset_id: str, provider_id: str, usage: DataUsage) -> None: self.policy.assert_allowed(dataset_id, provider_id, usage) def build_data_gateway( credentials: dict[str, object], tushare_token_supplier: Callable[[], str] | None = None, ) -> DataGateway: ifind = IfindHttpClient( str(credentials.get("ifind_refresh_token") or ""), str(credentials.get("ifind_access_token") or ""), ) token_supplier = tushare_token_supplier or ( lambda: str(credentials.get("tushare_token") or "") ) return DataGateway( policy=DataSourcePolicy.load(), tushare_provider=TushareProvider(token_supplier), ifind_provider=IfindProvider(ifind), chart_data=MarketChartClient(ifind, EastmoneyChartClient()), realtime_observer=WebRealtimeAggregator(), )