summaryrefslogtreecommitdiff
path: root/src/srht_contrib/main.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/srht_contrib/main.py')
-rw-r--r--src/srht_contrib/main.py99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/srht_contrib/main.py b/src/srht_contrib/main.py
new file mode 100644
index 0000000..37c3492
--- /dev/null
+++ b/src/srht_contrib/main.py
@@ -0,0 +1,99 @@
+from __future__ import annotations
+
+from collections.abc import AsyncIterator
+from contextlib import asynccontextmanager
+
+from apscheduler.schedulers.background import BackgroundScheduler
+from fastapi import FastAPI
+from sqlalchemy import Engine
+from sqlalchemy.orm import Session, sessionmaker
+
+from srht_contrib.api.routes_contributions import router as contributions_router
+from srht_contrib.api.routes_health import router as health_router
+from srht_contrib.api.routes_repositories import router as repositories_router
+from srht_contrib.config import Settings, get_settings
+from srht_contrib.db import make_engine, validate_db
+from srht_contrib.jobs.poller import PollerService
+from srht_contrib.logging import configure_logging
+from srht_contrib.services.git import GitIngestionService
+from srht_contrib.services.srht_client import SourceHutGraphQLClient
+from srht_contrib.services.todo import TodoIngestionService
+from srht_contrib.utils.identity import ActorIdentityResolver
+
+
+def build_poller(settings: Settings) -> PollerService:
+ todo_client = SourceHutGraphQLClient(settings.todo_srht_endpoint, settings.srht_token)
+ git_client = SourceHutGraphQLClient(settings.git_srht_endpoint, settings.srht_token)
+ todo_service = TodoIngestionService(todo_client, settings)
+ git_service = GitIngestionService(git_client, settings)
+ return PollerService(todo_service=todo_service, git_service=git_service)
+
+
+def create_app(
+ settings: Settings | None = None,
+ *,
+ engine: Engine | None = None,
+ session_factory: sessionmaker[Session] | None = None,
+ poller: PollerService | None = None,
+) -> FastAPI:
+ app_settings = settings or get_settings()
+ configure_logging()
+ app_engine = engine or make_engine(app_settings)
+ app_session_factory = session_factory or sessionmaker(
+ bind=app_engine,
+ autoflush=False,
+ autocommit=False,
+ expire_on_commit=False,
+ )
+ actor_identity_resolver = ActorIdentityResolver(app_settings.actor_aliases_json)
+
+ @asynccontextmanager
+ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
+ validate_db(app_engine)
+ app_poller = poller or build_poller(app_settings)
+ app.state.poller = app_poller
+ app.state.settings = app_settings
+ app.state.engine = app_engine
+ app.state.session_factory = app_session_factory
+ app.state.actor_identity_resolver = actor_identity_resolver
+ scheduler: BackgroundScheduler | None = None
+ if app_settings.enable_scheduler:
+ scheduler = BackgroundScheduler()
+ scheduler.add_job(
+ _scheduled_poll,
+ "interval",
+ seconds=app_settings.poll_interval_seconds,
+ args=[app],
+ id="srht-poller",
+ replace_existing=True,
+ )
+ scheduler.start()
+ app.state.scheduler = scheduler
+ try:
+ yield
+ finally:
+ if scheduler is not None:
+ scheduler.shutdown(wait=False)
+ app_poller.todo_service.client.close()
+ app_poller.git_service.client.close()
+
+ app = FastAPI(title=app_settings.app_name, lifespan=lifespan)
+
+ app.include_router(health_router)
+ app.include_router(contributions_router)
+ app.include_router(repositories_router)
+ return app
+
+
+def _scheduled_poll(app: FastAPI) -> None:
+ settings: Settings = app.state.settings
+ poller: PollerService = app.state.poller
+ session_factory: sessionmaker[Session] = app.state.session_factory
+ db = session_factory()
+ try:
+ poller.poll_all(db, settings.default_actor)
+ finally:
+ db.close()
+
+
+app = create_app()