from collections.abc import Iterator import anydi.ext.pydantic_settings import boto3 from anydi import Container, Module, Provider, provider from fansifter_common.adapters.aws.secretsmanager import SecretsManager from fansifter_common.adapters.db import Database from app.adapters.aws.kms import KMSClient from app.adapters.database.repository import AdAccountRepository from app.adapters.meta.client import FacebookClient from app.adapters.tiktok.client import TiktokClient from app.handlers import EventHandler from .settings import Settings class AppModule(Module): @provider(scope="singleton") def aws_session(self, settings: Settings) -> boto3.Session: return boto3.Session(region_name=settings.aws_region_name) @provider(scope="singleton") def secrets_manager(self, settings: Settings) -> SecretsManager: return SecretsManager(region_name=settings.aws_region_name) @provider(scope="singleton") def kms_client(self, settings: Settings, session: boto3.Session) -> KMSClient: return KMSClient( region_name=settings.aws_region_name, key_id=settings.kms_key_id, session=session, ) @provider(scope="singleton") def meta_client(self) -> Iterator[FacebookClient]: with FacebookClient() as client: yield client @provider(scope="singleton") def tiktok_client(self) -> Iterator[TiktokClient]: with TiktokClient() as client: yield client @provider(scope="singleton") def db(self, settings: Settings) -> Iterator[Database]: with Database( url=settings.postgres_url, engine_args={ "connect_args": {"sslmode": "allow" if settings.ssl_mode else "disable"} }, ) as db: yield db # @provider(scope="request") # def db_session_factory(self, db: Database) -> Iterator[None]: # with db.session_factory(): # yield @provider(scope="singleton") def ad_account_repository(self, db: Database) -> AdAccountRepository: return AdAccountRepository( db=db, ) @provider(scope="singleton") def handler( self, kms_client: KMSClient, db: Database, ad_account_repository: AdAccountRepository, facebook_client: FacebookClient, tiktok_client: TiktokClient, ) -> EventHandler: return EventHandler( db=db, kms_client=kms_client, ad_account_repository=ad_account_repository, facebook_client=facebook_client, tiktok_client=tiktok_client, ) def initialize_container(settings: Settings, *, testing: bool = False) -> Container: # Configure DI container container = Container( providers=[ Provider(lambda: settings, scope="singleton", interface=Settings), ], modules=[AppModule], testing=testing, ) # Install Pydantic settings anydi.ext.pydantic_settings.install(settings, container) return container