from collections.abc import Iterator import boto3 import redis import sqlalchemy.pool from anydi import Container, Module, Provider, provider from fansifter_common import context from fansifter_common.adapters.aws.secretsmanager import SecretsManager from fansifter_common.adapters.ows_account import OwsAccountClient from fansifter_common.adapters.sendgrid import SendGridClient from fansifter_common.adapters.stripo import StripoClient from fansifter_common.constants import PROD_ENVIRONMENT, QA_ENVIRONMENT from fansifter_common.encrypter import JWTEncrypter from fansifter_common.legal_info.services import LegalInfoService from fansifter_common.m2m_token import M2MTokenManager from fansifter_common.translation.services import TranslationService from fansifter_common.utils.functional import lazy_proxy from owsclient import OwsClient from app.adapters.aws.s3 import S3Client from app.adapters.db import Database from app.config import Settings, 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 s3_client(self, aws_session: boto3.Session, settings: Settings) -> S3Client: return S3Client(session=aws_session, region_name=settings.aws_region_name) @provider(scope="singleton") def m2m_token_manager( self, settings: Settings, secrets_manager: SecretsManager ) -> M2MTokenManager: return M2MTokenManager( secrets_manager=secrets_manager, secret_name_key=settings.m2m_token_secret_key_name, secret_expire_name_key=settings.m2m_token_secret_expiry_key_name, ) @provider(scope="singleton") def ows_client( self, settings: Settings, m2m_token_manager: M2MTokenManager ) -> OwsClient: return OwsClient( environment=settings.environment, service_name=settings.service_name, m2m_token_manager=m2m_token_manager if settings.environment in [QA_ENVIRONMENT, PROD_ENVIRONMENT] else None, correlation_id_getter=context.get_correlation_id, request_context_getter=context.get_request_context, ) @provider(scope="singleton") def ows_account_client(self, ows_client: OwsClient) -> OwsAccountClient: return OwsAccountClient(ows_client=ows_client) @provider(scope="singleton") def sendgrid_client(self, settings: Settings) -> Iterator[SendGridClient]: with SendGridClient( sme_api_key=settings.sendgrid_sme_api_key, orchard_api_key=settings.sendgrid_orchard_api_key, awal_api_key=settings.sendgrid_awal_api_key, unsubscribe_host=settings.unsubscribe_host, preference_center_url=settings.preference_center_url, reply_to_sme_domain=settings.reply_to_sme_domain, reply_to_orchard_domain=settings.reply_to_orchard_domain, reply_to_awal_domain=settings.reply_to_awal_domain, reply_to_header_enabled=settings.reply_to_header_enabled, reply_to_secret_key=settings.reply_to_secret_key, ) as sendgrid_client: yield sendgrid_client @provider(scope="singleton") def stripo_client(self, settings: Settings) -> Iterator[StripoClient]: with StripoClient( base_url=settings.stripo_base_url, client_id=settings.stripo_client_id, client_secret=settings.stripo_client_secret, ) as stripo_client: yield stripo_client @provider(scope="singleton") def preference_center_encrypter(self, settings: Settings) -> JWTEncrypter: return JWTEncrypter( key=settings.preference_center_secret_key, ) @provider(scope="singleton") def legal_info_service(self) -> LegalInfoService: return LegalInfoService() @provider(scope="singleton") def translation_service(self, settings: Settings) -> TranslationService: return TranslationService(translations_path=settings.translations_path) @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") def db_session_factory(self, db: Database) -> Iterator[None]: with db.session_factory(): yield @provider(scope="singleton") def redis_client(self, settings: Settings) -> redis.Redis: return redis.Redis( host=settings.redis_host, port=settings.redis_port, db=settings.redis_db, ssl=settings.redis_ssl, ) def make_container() -> Container: # Configure DI container return Container( providers=[ Provider(Settings, factory=lambda: settings, scope="singleton"), ], modules=[AppModule], ) container = lazy_proxy(make_container)