from collections.abc import Iterator import httpx from anydi import Container, Module, Provider, provider from jinja2sql import Jinja2SQL from app.connectors.aws.s3 import S3Client from app.connectors.database.base import ReportingDB from app.connectors.database.repository import AdReportingRepository from app.handler import AdThumbnailDownloadHandler from app.processors import ( CreativeProcessorsType, GoogleCreativeProcessor, MetaCreativeProcessor, TiktokCreativeProcessor, ) from .settings import Settings class AppModule(Module): @provider(scope="singleton") def web_client(self) -> httpx.AsyncClient: return httpx.AsyncClient() @provider(scope="singleton") def s3_client(self, settings: Settings, web_client: httpx.AsyncClient) -> S3Client: return S3Client( web_client=web_client, aws_region=settings.aws_region_name, aws_access_key_id=settings.aws_access_key_id, aws_secret_access_key=settings.aws_secret_access_key, aws_session_token=settings.aws_session_token, ) @provider(scope="singleton") def jinja2sql(self, settings: Settings) -> Jinja2SQL: jinja2sql = Jinja2SQL(searchpath=settings.jinja2sql_template_searchpath) return jinja2sql @provider(scope="singleton") def reporting_db( self, settings: Settings, jinja2sql: Jinja2SQL ) -> Iterator[ReportingDB]: with ReportingDB( url=settings.snowflake_url, engine_args={ "connect_args": settings.snowflake_connect_args, }, jinja2sql=jinja2sql, ) as db: yield db @provider(scope="request") def reporting_db_session_factory(self, db: ReportingDB) -> Iterator[None]: with db.session_factory(): yield @provider(scope="singleton") def ad_reporting_repository( self, db: ReportingDB, settings: Settings ) -> AdReportingRepository: return AdReportingRepository( db=db, meta_connection_table=settings.meta_connection_table, tiktok_connection_table=settings.tiktok_connection_table, google_connection_table=settings.google_connection_table, max_fails_count=settings.max_fails_count, ) @provider(scope="singleton") def processors( self, settings: Settings, web_client: httpx.AsyncClient, s3_client: S3Client, ) -> CreativeProcessorsType: return { "META": MetaCreativeProcessor( web_client=web_client, s3_client=s3_client, assets_s3_bucket_name=settings.assets_s3_bucket_name, assets_s3_raw_path=settings.assets_s3_raw_path, assets_s3_thumbnail_path=settings.assets_s3_thumbnail_path, ), "TIKTOK": TiktokCreativeProcessor( web_client=web_client, s3_client=s3_client, assets_s3_bucket_name=settings.assets_s3_bucket_name, assets_s3_raw_path=settings.assets_s3_raw_path, assets_s3_thumbnail_path=settings.assets_s3_thumbnail_path, ), "GOOGLE": GoogleCreativeProcessor( web_client=web_client, s3_client=s3_client, assets_s3_bucket_name=settings.assets_s3_bucket_name, assets_s3_raw_path=settings.assets_s3_raw_path, assets_s3_thumbnail_path=settings.assets_s3_thumbnail_path, ), } @provider(scope="singleton") def ad_thumbnail_download_handler( self, settings: Settings, db: ReportingDB, ad_reporting_repository: AdReportingRepository, processors: CreativeProcessorsType, ) -> AdThumbnailDownloadHandler: return AdThumbnailDownloadHandler( db=db, ad_reporting_repository=ad_reporting_repository, processors=processors, chunk_size=settings.db_fetch_chunk_size, threads_count=settings.threads_count, ) def initialize_container(settings: Settings) -> Container: # Configure DI container return Container( providers=[ Provider(lambda: settings, scope="singleton", interface=Settings), ], modules=[AppModule], )