stats/app.py
2025-01-31 16:51:57 +09:00

121 lines
3.5 KiB
Python

from typing import List, Union
from pathlib import Path
from datetime import datetime, timedelta, timezone
from urllib.parse import urlparse
from json import dumps
from pprint import pprint
from requests import post
from fastapi import FastAPI, Response, Header, status
from fastapi.responses import JSONResponse, PlainTextResponse, FileResponse
from contextlib import asynccontextmanager
def fastapi_serve(dir: str, ref: str, indexes: List[str] = ["index.html", "index.htm"]) -> Response:
url_path = urlparse(ref or "/").path
root = Path(dir)
try_files = []
if url_path.endswith("/"):
try_files += [root / url_path.lstrip("/") / i for i in indexes]
try_files += [root / url_path]
try_files_tried = [t for t in try_files if t.is_file()]
print(try_files, try_files_tried)
if not try_files_tried:
return PlainTextResponse("指定されたファイルが見つかりません", status.HTTP_404_NOT_FOUND)
path = try_files_tried[0]
print(path, "をサーブ中")
return FileResponse(path)
ctx = {}
@asynccontextmanager
async def lifespan(app: FastAPI):
ctx["daily"] = Path("analytics_daily.txt").read_text("UTF-8")
ctx["hourly"] = Path("analytics_hourly.txt").read_text("UTF-8")
pprint(ctx)
yield
ctx.clear()
app = FastAPI(lifespan=lifespan)
@app.get("/api/cloudflare")
async def cloudflare(zone_id: str, x_token: Union[str, None] = Header()):
now = datetime.now()
before = now - timedelta(**{ "days": 30 })
variables = {
"zoneTag": zone_id,
"from": before.astimezone(timezone.utc).strftime("%Y-%m-%d"),
"to": now.astimezone(timezone.utc).strftime("%Y-%m-%d"),
"limit": 30
}
result = post(
url="https://api.cloudflare.com/client/v4/graphql",
headers={
"Authorization": f"Bearer {x_token}"
},
data=dumps({
"query": ctx["daily"],
"variables": variables
})
)
json = result.json()
res = JSONResponse(json)
if "data" in json and not json["errors"]:
pass
else:
res.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
res.headers["Cache-Control"] = f"public, max-age=15, s-maxage=15"
res.headers["CDN-Cache-Control"] = f"max-age=15"
return res
@app.get("/api/cloudflare2")
async def cloudflare2(zone_id: str, x_token: Union[str, None] = Header()):
now = datetime.now()
before = now - timedelta(**{ "hours": 72 })
variables = {
"zoneTag": zone_id,
"from": before.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"to": now.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"limit": 72
}
result = post(
url="https://api.cloudflare.com/client/v4/graphql",
headers={
"Authorization": f"Bearer {x_token}"
},
data=dumps({
"query": ctx["hourly"],
"variables": variables
})
)
json = result.json()
res = JSONResponse(json)
if "data" in json and not json["errors"]:
pass
else:
res.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
res.headers["Cache-Control"] = f"public, max-age=15, s-maxage=15"
res.headers["CDN-Cache-Control"] = f"max-age=15"
return res
@app.get("/")
@app.get("/{ref:path}")
async def home(ref: str = None):
res = fastapi_serve("static", ref)
res.headers["Cache-Control"] = "public, max-age=3600, s-maxage=3600"
res.headers["CDN-Cache-Control"] = "max-age=3600"
return res