693f720cbd
- bincio/render/ogimage.py: generate 400x400 elevation-coloured PNG with Pillow
- bincio/serve/routers/ogimage.py: /activity/{id}/ OG HTML stub for bot UAs;
/og-image/{user}/{id}.png serves pre-generated images with on-demand fallback
- scripts/generate_og_images.py: batch pre-generation, incremental (mtime skip)
- scripts/strava_elevation_audit.py: add source/threshold/MA columns and pct stats
- pyproject.toml: add Pillow>=10 to serve extras
74 lines
1.7 KiB
Python
74 lines
1.7 KiB
Python
"""bincio serve — multi-user FastAPI application server.
|
|
|
|
Handles auth, user management, and auth-gated write operations.
|
|
nginx serves static files; this server only handles /api/* routes.
|
|
|
|
Run via `bincio serve` CLI command.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import glob as _glob
|
|
import threading
|
|
from pathlib import Path
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.middleware.gzip import GZipMiddleware
|
|
|
|
from bincio.serve import deps, tasks
|
|
from bincio.serve.routers import (
|
|
activities,
|
|
admin,
|
|
auth,
|
|
download,
|
|
feed,
|
|
garmin,
|
|
ideas,
|
|
me,
|
|
ogimage,
|
|
segments,
|
|
strava,
|
|
uploads,
|
|
)
|
|
|
|
app = FastAPI(title="BincioActivity Serve")
|
|
|
|
|
|
@app.on_event("startup")
|
|
async def _on_startup() -> None:
|
|
"""Startup tasks: clean orphaned tmp zips; launch site-rebuild worker if --webroot set."""
|
|
data_dir = deps._get_data_dir()
|
|
for p in _glob.glob(str(data_dir / "*" / "tmp*.zip")):
|
|
try:
|
|
Path(p).unlink()
|
|
except OSError:
|
|
pass
|
|
if deps.webroot is not None:
|
|
threading.Thread(target=tasks._site_rebuild_worker, daemon=True, name="site-rebuild").start()
|
|
|
|
|
|
app.add_middleware(GZipMiddleware, minimum_size=1024)
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origin_regex=r"https?://localhost(:\d+)?|https://[a-z0-9-]+\.bincio\.org",
|
|
allow_credentials=True,
|
|
allow_methods=["GET", "POST", "DELETE"],
|
|
allow_headers=["Content-Type"],
|
|
)
|
|
|
|
for _router in [
|
|
feed.router,
|
|
auth.router,
|
|
me.router,
|
|
admin.router,
|
|
activities.router,
|
|
download.router,
|
|
uploads.router,
|
|
segments.router,
|
|
strava.router,
|
|
garmin.router,
|
|
ideas.router,
|
|
ogimage.router,
|
|
]:
|
|
app.include_router(_router)
|