from collections.abc import Iterator import boto3 from anydi import Container, Module, Provider, provider from anydi.testing import TestContainer from confluent_kafka import Producer from fansifter_common.adapters.db.base import Database from fansifter_common.utils.functional import lazy_proxy from mypy_boto3_kms import KMSClient from app.adapters.db.twilio.repositories import TwilioAccountRepository from app.config import Settings, settings from app.handler import TwilioWebhooksOutboundHandler from app.validator import RequestValidator class AppModule(Module): @provider(scope="singleton") def kms_client(self, settings: Settings) -> KMSClient: return boto3.client("kms", region_name=settings.aws_region_name) # type: ignore @provider(scope="singleton") def kafka_producer(self, settings: Settings) -> Producer: producer = Producer( { "bootstrap.servers": settings.kafka_bootstrap_servers, "security.protocol": "ssl" if settings.kafka_use_ssl else "plaintext", } ) return producer @provider(scope="singleton") def pg_db( self, settings: Settings, ) -> Iterator[Database]: with Database( url=settings.postgres_url, engine_args=settings.postgres_engine_args, ) as db: yield db @provider(scope="singleton") def request_validator( self, db: Database, accounts_repository: TwilioAccountRepository, kms_client: KMSClient, settings: Settings, ) -> RequestValidator: return RequestValidator( db=db, accounts_repository=accounts_repository, kms_client=kms_client, kms_key_id=settings.kms_key_id, ) @provider(scope="singleton") def handler( self, settings: Settings, producer: Producer, request_validator: RequestValidator, ) -> TwilioWebhooksOutboundHandler: return TwilioWebhooksOutboundHandler( kafka_producer=producer, kafka_event_topic=settings.kafka_event_topic, request_validator=request_validator, ) def initialize_container() -> Container: # Configure DI container container = Container( providers=[ Provider(lambda: settings, scope="singleton", interface=Settings), ], modules=[AppModule], ) if settings.environment == "test": return TestContainer.from_container(container) return container container = lazy_proxy(initialize_container)