Files
Market-Data-Downloader/ui.py
2025-10-05 13:10:12 +01:00

180 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""
ui.py - Main Application Entry Point and FastAPI App Initialization
Orchestrates all components and initializes the FastAPI application
"""
import asyncio
import logging
from typing import Dict, Any, Optional
from pathlib import Path
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
from dotenv import load_dotenv
# Import application modules
from db import DatabaseManager
from utils import load_config, setup_logging
from main import BinanceDataCollector
# Import UI modules
from ui_models import serialize_for_json
from ui_routes import APIRoutes
from ui_websocket import handle_websocket_connection, broadcast_status_updates, websocket_connections
from ui_state import state_manager, get_current_status
# Load environment variables
load_dotenv('variables.env')
# Setup logging
setup_logging()
logger = logging.getLogger(__name__)
# Global application components
app = FastAPI(
title="Crypto Trading Data Collector",
version="3.1.0",
description="Real-time cryptocurrency market data collection and analysis platform"
)
db_manager: Optional[DatabaseManager] = None
data_collector: Optional[BinanceDataCollector] = None
config: Dict[str, Any] = {}
api_routes: Optional[APIRoutes] = None
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.on_event("startup")
async def startup_event():
"""Initialize application on startup"""
global db_manager, data_collector, config, api_routes
try:
logger.info("=" * 80)
logger.info("Starting Crypto Trading Data Collector v3.1.0")
logger.info("=" * 80)
# Load configuration
config = load_config()
logger.info("✓ Configuration loaded successfully")
# Initialize database
db_manager = DatabaseManager()
await db_manager.initialize()
logger.info("✓ Database initialized successfully")
# Initialize data collector
data_collector = BinanceDataCollector()
await data_collector.initialize()
logger.info("✓ Data collector initialized successfully")
# Initialize API routes
api_routes = APIRoutes(
app,
db_manager,
data_collector,
config,
state_manager
)
logger.info("✓ API routes registered successfully")
# Restore collection state if it was running before reload
if state_manager.get("is_collecting", False):
logger.info("Restoring collection state from persistent storage...")
try:
await data_collector.start_continuous_collection()
logger.info("✓ Collection state restored successfully")
except Exception as e:
logger.error(f"✗ Error restoring collection state: {e}")
state_manager.update(is_collecting=False)
# Start WebSocket broadcaster
async def status_getter():
return await get_current_status(db_manager, data_collector, config)
asyncio.create_task(broadcast_status_updates(status_getter))
logger.info("✓ WebSocket broadcaster started")
logger.info("=" * 80)
logger.info("FastAPI application startup complete - Ready to serve requests")
logger.info("=" * 80)
except Exception as e:
logger.error("=" * 80)
logger.error(f"FATAL ERROR during startup: {e}", exc_info=True)
logger.error("=" * 80)
raise
@app.on_event("shutdown")
async def shutdown_event():
"""Clean shutdown"""
global db_manager, data_collector
try:
logger.info("=" * 80)
logger.info("Shutting down Crypto Trading Data Collector")
logger.info("=" * 80)
# Save current state before shutdown
if data_collector:
state_manager.update(
is_collecting=data_collector.is_collecting if hasattr(data_collector, 'is_collecting') else False,
websocket_collection_running=data_collector.websocket_collection_running if hasattr(data_collector, 'websocket_collection_running') else False
)
logger.info("✓ State saved")
# Close database connections
if db_manager:
try:
await db_manager.close()
logger.info("✓ Database connections closed")
except Exception as e:
logger.error(f"✗ Error closing database: {e}")
logger.info("=" * 80)
logger.info("Shutdown complete")
logger.info("=" * 80)
except Exception as e:
logger.error(f"Error during shutdown: {e}", exc_info=True)
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
"""WebSocket endpoint for real-time updates"""
await handle_websocket_connection(websocket)
def main():
"""Main entry point for running the application"""
import os
# Get configuration from environment or use defaults
host = os.getenv("WEB_HOST", "0.0.0.0")
port = int(os.getenv("WEB_PORT", "8000"))
reload = os.getenv("WEB_RELOAD", "False").lower() == "true"
logger.info(f"Starting server on {host}:{port} (reload={reload})")
uvicorn.run(
"ui:app",
host=host,
port=port,
reload=reload,
log_level="info"
)
if __name__ == "__main__":
main()