rapid interations of server side app and firefox extension
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
"""Main Quart application factory."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from quart import Quart, send_from_directory, send_file
|
||||
from quart_cors import cors
|
||||
|
||||
from app.config import get_settings
|
||||
from app.models import init_db
|
||||
from app.api import subscriptions, sources, downloads, credentials, settings as settings_api, platforms, websocket
|
||||
from app.api.websocket import start_redis_subscriber
|
||||
|
||||
# Path to static frontend files (built Vue app)
|
||||
STATIC_DIR = Path(__file__).parent.parent / "static"
|
||||
|
||||
|
||||
def create_app() -> Quart:
|
||||
"""Create and configure the Quart application."""
|
||||
app = Quart(__name__, static_folder=None) # Disable default static handling
|
||||
config = get_settings()
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=getattr(logging, config.log_level.upper()),
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
)
|
||||
|
||||
# Enable CORS for API routes only
|
||||
app = cors(app, allow_origin="*")
|
||||
|
||||
# Register API blueprints
|
||||
app.register_blueprint(subscriptions.bp, url_prefix="/api/subscriptions")
|
||||
app.register_blueprint(sources.bp, url_prefix="/api/sources")
|
||||
app.register_blueprint(downloads.bp, url_prefix="/api/downloads")
|
||||
app.register_blueprint(credentials.bp, url_prefix="/api/credentials")
|
||||
app.register_blueprint(settings_api.bp, url_prefix="/api/settings")
|
||||
app.register_blueprint(platforms.bp, url_prefix="/api/platforms")
|
||||
app.register_blueprint(websocket.bp, url_prefix="/ws")
|
||||
|
||||
@app.before_serving
|
||||
async def startup():
|
||||
"""Initialize database connection on startup."""
|
||||
app.db_engine = await init_db(config.async_database_url)
|
||||
app.logger.info("Database connection initialized")
|
||||
app.logger.info(f"Static files directory: {STATIC_DIR} (exists: {STATIC_DIR.exists()})")
|
||||
|
||||
# Start Redis subscriber for WebSocket events from Celery tasks
|
||||
app.redis_subscriber_task = asyncio.create_task(start_redis_subscriber())
|
||||
app.logger.info("Redis subscriber started for WebSocket events")
|
||||
|
||||
@app.after_serving
|
||||
async def shutdown():
|
||||
"""Close database connection on shutdown."""
|
||||
# Cancel Redis subscriber task
|
||||
if hasattr(app, "redis_subscriber_task"):
|
||||
app.redis_subscriber_task.cancel()
|
||||
try:
|
||||
await app.redis_subscriber_task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
app.logger.info("Redis subscriber stopped")
|
||||
|
||||
if hasattr(app, "db_engine"):
|
||||
await app.db_engine.dispose()
|
||||
app.logger.info("Database connection closed")
|
||||
|
||||
@app.route("/health")
|
||||
async def health_check():
|
||||
"""Health check endpoint."""
|
||||
return {"status": "healthy"}
|
||||
|
||||
@app.route("/api")
|
||||
async def api_info():
|
||||
"""API information endpoint."""
|
||||
return {
|
||||
"name": "Gallery Subscriber API",
|
||||
"version": "1.0.0",
|
||||
"endpoints": {
|
||||
"subscriptions": "/api/subscriptions",
|
||||
"sources": "/api/sources",
|
||||
"downloads": "/api/downloads",
|
||||
"credentials": "/api/credentials",
|
||||
"settings": "/api/settings",
|
||||
"platforms": "/api/platforms",
|
||||
"websocket": "/ws/events",
|
||||
},
|
||||
}
|
||||
|
||||
# Serve static assets (JS, CSS, images, fonts)
|
||||
@app.route("/assets/<path:filename>")
|
||||
async def serve_assets(filename):
|
||||
"""Serve static assets from the frontend build."""
|
||||
return await send_from_directory(STATIC_DIR / "assets", filename)
|
||||
|
||||
# Serve other static files (favicon, etc.)
|
||||
@app.route("/<path:filename>")
|
||||
async def serve_static(filename):
|
||||
"""Serve static files or fall back to index.html for Vue Router."""
|
||||
file_path = STATIC_DIR / filename
|
||||
if file_path.exists() and file_path.is_file():
|
||||
return await send_from_directory(STATIC_DIR, filename)
|
||||
# Fall back to index.html for Vue Router (SPA)
|
||||
return await send_file(STATIC_DIR / "index.html")
|
||||
|
||||
# Serve index.html for root path
|
||||
@app.route("/")
|
||||
async def serve_index():
|
||||
"""Serve the frontend index.html."""
|
||||
return await send_file(STATIC_DIR / "index.html")
|
||||
|
||||
return app
|
||||
|
||||
|
||||
# Create app instance for hypercorn
|
||||
app = create_app()
|
||||
Reference in New Issue
Block a user