From e1f414f2e90420a3453f9a6463888216a5d72585 Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 23 Oct 2024 17:27:03 -0500 Subject: [PATCH] Setup module entrypoint, main.py becomes app.py, add FastAPI Cache with InMemory backend, /api/migration route --- backend/linkpulse/__main__.py | 26 ++++++++++ backend/linkpulse/app.py | 96 +++++++++++++++++++++++++++++++++++ backend/linkpulse/main.py | 46 ----------------- 3 files changed, 122 insertions(+), 46 deletions(-) create mode 100644 backend/linkpulse/__main__.py create mode 100644 backend/linkpulse/app.py delete mode 100644 backend/linkpulse/main.py diff --git a/backend/linkpulse/__main__.py b/backend/linkpulse/__main__.py new file mode 100644 index 0000000..40a4c98 --- /dev/null +++ b/backend/linkpulse/__main__.py @@ -0,0 +1,26 @@ +import sys + +def main(*args): + if args[0] == "serve": + import asyncio + from hypercorn import Config + from hypercorn.asyncio import serve + from linkpulse.app import app + + config = Config() + + asyncio.run(serve(app, config)) + elif args[0] == "migrate": + from linkpulse.migrate import main + main(*args[1:]) + else: + print("Invalid command: {}".format(args[0])) + +if __name__ == "__main__": + if len(sys.argv) == 1: + main("serve") + else: + # Check that args after aren't all whitespace + remaining_args = ' '.join(sys.argv[1:]).strip() + if len(remaining_args) > 0: + main(*sys.argv[1:]) \ No newline at end of file diff --git a/backend/linkpulse/app.py b/backend/linkpulse/app.py new file mode 100644 index 0000000..042c0ad --- /dev/null +++ b/backend/linkpulse/app.py @@ -0,0 +1,96 @@ +from contextlib import asynccontextmanager +from datetime import datetime +from typing import AsyncIterator +from fastapi import FastAPI, Request +from fastapi.middleware.cors import CORSMiddleware +from dotenv import load_dotenv +from fastapi_cache import FastAPICache +from fastapi_cache.backends.inmemory import InMemoryBackend +from fastapi_cache.decorator import cache +from peewee import PostgresqlDatabase + +load_dotenv(dotenv_path=".env") + +from linkpulse import models # type: ignore + +db: PostgresqlDatabase = models.BaseModel._meta.database + + +@asynccontextmanager +async def lifespan(_: FastAPI) -> AsyncIterator[None]: + FastAPICache.init(backend=InMemoryBackend(), prefix="fastapi-cache", cache_status_header="X-Cache") + yield + + +app = FastAPI(lifespan=lifespan) + +origins = [ + "http://localhost", + "http://localhost:5173", +] + +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.on_event("startup") +def startup(): + db.connect() + db.create_tables([models.IPAddress]) + + +@app.on_event("shutdown") +def shutdown(): + if not db.is_closed(): + db.close() + + +@app.get("/health") +async def health(): + return "OK" + + +@app.get("/api/migration") +@cache(expire=60) +async def get_migration(): + cursor = db.execute_sql( + "SELECT name, migrated_at FROM migratehistory ORDER BY migrated_at DESC LIMIT 1" + ) + name, migrated_at = cursor.fetchone() + return {"name": name, "migrated_at": migrated_at} + + +@app.get("/api/test") +async def get_current_time(request: Request): + current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + user_ip = request.headers.get("X-Forwarded-For") + if not user_ip: + # Fallback, probably not on a proxy + user_ip = request.client.host + + response = {"time": current_time, "ip": user_ip} + + # Create one record + new_ip, created = models.IPAddress.get_or_create( + ip=user_ip, defaults={"lastSeen": datetime.now()} + ) + if not created: + new_ip.lastSeen = datetime.now() + result = new_ip.save() + print(result, new_ip) + + # Query all records + for ip in models.IPAddress.select(): + print(ip.ip, ip.lastSeen) + + message = request.query_params.get("message") + if message: + response["message"] = message + + return response diff --git a/backend/linkpulse/main.py b/backend/linkpulse/main.py deleted file mode 100644 index 5a525c4..0000000 --- a/backend/linkpulse/main.py +++ /dev/null @@ -1,46 +0,0 @@ -from fastapi import FastAPI, Request -from fastapi.middleware.cors import CORSMiddleware -from datetime import datetime -from dotenv import load_dotenv -import os - -load_dotenv(dotenv_path="../.env") - -print(os.environ.get("ENVIRONMENT")) - -app = FastAPI() - -origins = [ - "http://localhost", - "http://localhost:5173", -] - -app.add_middleware( - CORSMiddleware, - allow_origins=origins, - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -@app.get("/health") -async def health(): - return "OK" - - -@app.get("/api/test") -async def get_current_time(request: Request): - current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - - user_ip = request.headers.get("X-Forwarded-For") - if not user_ip: - # Fallback, probably not on a proxy - user_ip = request.client.host - - response = {"time": current_time, "ip": user_ip} - - message = request.query_params.get("message") - if message: - response["message"] = message - - return response