from collections.abc import AsyncIterator, Iterator import sqlalchemy from anydi import Container, Module, Provider, provider from cachelib import BaseCache as Cache, NullCache, RedisCache, SimpleCache from fansifter_common.encrypter import Encrypter, JWTEncrypter from fansifter_common.legal_info.services import LegalInfoService from fansifter_common.utils.functional import lazy_proxy from jwtauth import JWTAuth from jwtauth.utils import ( get_default_audience, get_default_issuer, get_default_jwks_url, ) from preference_center.adapters.db import Database from preference_center.adapters.kafka import KafkaProducer from preference_center.config import Settings, settings class AppModule(Module): @provider(scope="singleton") def jwt_auth(self, settings: Settings) -> JWTAuth: return JWTAuth( jwks_url=get_default_jwks_url(settings.environment), audience=get_default_audience(settings.environment), issuer=get_default_issuer(settings.environment), ) @provider(scope="singleton") def cache(self, settings: Settings) -> Cache: if settings.cache_backend in ["locmem", "memory"]: return SimpleCache(default_timeout=settings.cache_default_timeout) elif settings.cache_backend == "redis": return RedisCache( host=settings.redis_host, port=settings.redis_port, db=settings.cache_redis_db, ssl=settings.redis_ssl, default_timeout=settings.cache_default_timeout, key_prefix=settings.cache_key_prefix, ) return NullCache() @provider(scope="singleton") def producer(self, settings: Settings) -> Iterator[KafkaProducer]: config = { "bootstrap.servers": settings.kafka_bootstrap_servers, } if settings.kafka_use_ssl: config["security.protocol"] = "SSL" producer = KafkaProducer(config) producer.start() yield producer producer.close() @provider(scope="singleton") def db(self, settings: Settings) -> Iterator[Database]: with Database( url=settings.snowflake_url, engine_args={ "echo": settings.snowflake_echo, "poolclass": sqlalchemy.pool.QueuePool, "pool_size": settings.snowflake_pool_size, "max_overflow": settings.snowflake_pool_max_overflow, "pool_recycle": settings.snowflake_pool_recycle, "pool_pre_ping": settings.snowflake_pool_pre_ping, "pool_reset_on_return": settings.snowflake_pool_reset_on_return, "connect_args": settings.snowflake_connect_args, }, ) as db: yield db @provider(scope="request") async def db_session_factory(self, db: Database) -> AsyncIterator[None]: with db.session_factory(): yield @provider(scope="singleton") def encrypter(self, settings: Settings) -> Encrypter: return JWTEncrypter(key=settings.secret_key.get_secret_value()) @provider(scope="singleton") def legal_info_service(self) -> LegalInfoService: return LegalInfoService() def make_container() -> Container: # Configure DI container return Container( providers=[ Provider(Settings, lambda: settings), ], modules=[AppModule], ) # Lazy container initialization container = lazy_proxy(make_container)