Spaces:
Sleeping
Sleeping
File size: 3,960 Bytes
494c89b 374416b 494c89b 374416b 494c89b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
"""
Kiro Account Manager - Main Application
FastAPI server with WebSocket support for real-time updates
"""
import os
import sys
import webbrowser
import asyncio
from pathlib import Path
from contextlib import asynccontextmanager
# Add parent to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse, JSONResponse
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
from app.api import accounts, quota, autoreg, patch, system
from app.websocket import get_manager
from version import __version__, __app_name__
# WebSocket manager for real-time logs
ws_manager = get_manager()
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup and shutdown events"""
print("\n" + "=" * 50)
print(f"🚀 {__app_name__} v{__version__}")
print("=" * 50)
yield
print("\n👋 Shutting down...")
# Create FastAPI app
app = FastAPI(
title=__app_name__,
description="Manage Kiro accounts, quotas, and auto-registration",
version=__version__,
lifespan=lifespan
)
# CORS for development
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include API routers
app.include_router(accounts.router, prefix="/api/accounts", tags=["Accounts"])
app.include_router(quota.router, prefix="/api/quota", tags=["Quota"])
app.include_router(autoreg.router, prefix="/api/autoreg", tags=["Auto-Registration"])
app.include_router(patch.router, prefix="/api/patch", tags=["Kiro Patch"])
app.include_router(system.router, prefix="/api/system", tags=["System"])
from app.utils import get_static_dir
# Static files
static_dir = get_static_dir()
if static_dir.exists():
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
@app.get("/")
async def root():
"""Serve main UI with no-cache headers"""
from fastapi.responses import HTMLResponse
index_file = get_static_dir() / "index.html"
content = index_file.read_text(encoding='utf-8')
return HTMLResponse(
content=content,
headers={
"Cache-Control": "no-cache, no-store, must-revalidate",
"Pragma": "no-cache",
"Expires": "0"
}
)
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
"""WebSocket for real-time logs and status updates"""
from app.websocket import handle_command
import json
await ws_manager.connect(websocket)
try:
while True:
# Receive and handle commands from frontend
data = await websocket.receive_text()
try:
msg = json.loads(data)
command = msg.get("command", "")
await handle_command(command, msg, websocket)
except json.JSONDecodeError:
# Legacy ping support
if data == "ping":
await websocket.send_text("pong")
except WebSocketDisconnect:
ws_manager.disconnect(websocket)
@app.get("/health")
async def health():
"""Health check endpoint"""
return {"status": "ok", "version": __version__}
def open_browser(port: int):
"""Open browser after short delay"""
import time
time.sleep(1.5)
webbrowser.open(f"http://127.0.0.1:{port}")
def run(host: str = "127.0.0.1", port: int = 8420, open_browser_flag: bool = True):
"""Run the application"""
if open_browser_flag:
import threading
threading.Thread(target=open_browser, args=(port,), daemon=True).start()
print(f"\n📡 Server: http://{host}:{port}")
print("Press Ctrl+C to stop\n")
uvicorn.run(
app,
host=host,
port=port,
log_level="warning",
access_log=False
)
if __name__ == "__main__":
run()
|