Files
mywhoosh2garmin/app/main.py
Bastian Wagner ff5dab6f0d intervall
2026-08-15 21:44:13 +02:00

101 lines
3.4 KiB
Python

from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from starlette.middleware.sessions import SessionMiddleware
from app.config import Settings, get_settings
from app.db.session import create_db_engine, create_session_factory, initialize_schema
from app.fit.rewriter import convert_fit_device
from app.garmin.uploader import GarminUploader
from app.mywhoosh.client import MyWhooshClient
from app.notifications.emailer import EmailNotifier
from app.security.credentials import CredentialCipher
from app.sync.manager import SyncManager
from app.sync.scheduler import DayNightIntervalProvider, SyncScheduler
from app.web.account import router as account_router
from app.web.operations import router as operations_router
from app.web.routes import router as web_router
def create_app(settings: Settings | None = None) -> FastAPI:
resolved = settings or get_settings()
resolved.data_dir.mkdir(parents=True, exist_ok=True)
resolved.tokens_dir.mkdir(parents=True, exist_ok=True)
resolved.activities_dir.mkdir(parents=True, exist_ok=True)
@asynccontextmanager
async def lifespan(app: FastAPI):
cipher = CredentialCipher(resolved.credential_encryption_key)
def mywhoosh_factory(token_store):
return MyWhooshClient(token_store)
def garmin_factory(email, password, tokenstore):
return GarminUploader(email=email, password=password, tokenstore=tokenstore)
notifier = EmailNotifier(
host=resolved.smtp_host,
port=resolved.smtp_port,
username=resolved.smtp_username,
password=resolved.smtp_password,
from_address=resolved.smtp_from_address,
use_tls=resolved.smtp_use_tls,
)
sync_manager = SyncManager(
session_factory=app.state.session_factory,
credential_cipher=cipher,
settings=resolved,
mywhoosh_factory=mywhoosh_factory,
garmin_factory=garmin_factory,
fit_converter=convert_fit_device,
notifier=notifier,
)
app.state.sync_manager = sync_manager
interval_provider = DayNightIntervalProvider(
app.state.session_factory, default_minutes=resolved.sync_interval_minutes
)
scheduler = SyncScheduler(
sync_manager,
interval_seconds=resolved.sync_interval_minutes * 60,
interval_provider=interval_provider,
)
app.state.scheduler = scheduler
await scheduler.start()
yield
await scheduler.stop()
app = FastAPI(title="MyWhoosh Garmin Sync", lifespan=lifespan)
app.state.settings = resolved
engine = create_db_engine(resolved.database_url)
initialize_schema(engine)
app.state.db_engine = engine
app.state.session_factory = create_session_factory(engine)
app.add_middleware(
SessionMiddleware,
secret_key=resolved.secret_key,
same_site="lax",
https_only=resolved.session_https_only,
)
app.include_router(web_router)
app.include_router(operations_router)
app.include_router(account_router)
app.mount(
"/static",
StaticFiles(directory=str(Path(__file__).resolve().parent / "web" / "static")),
name="static",
)
@app.get("/healthz")
def healthz() -> dict[str, str]:
return {"status": "ok"}
return app