119 lines
3.4 KiB
Python
119 lines
3.4 KiB
Python
import os
|
|
import logging
|
|
import asyncio
|
|
from dotenv import load_dotenv
|
|
from aiohttp import web
|
|
from providers import create_providers
|
|
from cache import Cache
|
|
from errors import ErrorLogger
|
|
from router import Router
|
|
from http_proxy import setup_routes
|
|
from ws_proxy import setup_ws_routes
|
|
|
|
|
|
@web.middleware
|
|
async def cors_middleware(request, handler):
|
|
"""Add CORS headers to all responses"""
|
|
if request.method == 'OPTIONS':
|
|
# Handle preflight requests
|
|
return web.Response(headers={
|
|
'Access-Control-Allow-Origin': '*',
|
|
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
'Access-Control-Allow-Headers': '*',
|
|
'Access-Control-Max-Age': '86400'
|
|
})
|
|
|
|
response = await handler(request)
|
|
response.headers['Access-Control-Allow-Origin'] = '*'
|
|
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
|
|
response.headers['Access-Control-Allow-Headers'] = '*'
|
|
return response
|
|
|
|
|
|
def load_config() -> dict:
|
|
load_dotenv()
|
|
|
|
return {
|
|
"rpc_port": int(os.getenv("RPC_PORT", 8545)),
|
|
"ws_port": int(os.getenv("WS_PORT", 8546)),
|
|
"cache_size_gb": int(os.getenv("CACHE_SIZE_GB", 100)),
|
|
"backoff_minutes": int(os.getenv("BACKOFF_MINUTES", 30)),
|
|
"log_level": os.getenv("LOG_LEVEL", "INFO"),
|
|
"error_db_path": os.getenv("ERROR_DB_PATH", "./errors.db"),
|
|
}
|
|
|
|
|
|
def setup_logging(log_level: str) -> None:
|
|
logging.basicConfig(
|
|
level=getattr(logging, log_level.upper()),
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
)
|
|
|
|
|
|
def create_rpc_app(config: dict, router: Router) -> web.Application:
|
|
app = web.Application(middlewares=[cors_middleware])
|
|
app['router'] = router
|
|
app['config'] = config
|
|
setup_routes(app)
|
|
return app
|
|
|
|
def create_ws_app(config: dict, router: Router) -> web.Application:
|
|
app = web.Application(middlewares=[cors_middleware])
|
|
app['router'] = router
|
|
app['config'] = config
|
|
setup_ws_routes(app)
|
|
return app
|
|
|
|
|
|
|
|
|
|
async def run_servers(config: dict) -> None:
|
|
# Create shared components
|
|
providers = create_providers()
|
|
cache = Cache(size_limit_gb=config["cache_size_gb"])
|
|
error_logger = ErrorLogger(db_path=config["error_db_path"])
|
|
router = Router(providers, cache, error_logger)
|
|
|
|
# Create separate apps
|
|
rpc_app = create_rpc_app(config, router)
|
|
ws_app = create_ws_app(config, router)
|
|
|
|
# Create runners
|
|
rpc_runner = web.AppRunner(rpc_app)
|
|
ws_runner = web.AppRunner(ws_app)
|
|
|
|
await rpc_runner.setup()
|
|
await ws_runner.setup()
|
|
|
|
# Create sites
|
|
rpc_site = web.TCPSite(rpc_runner, '0.0.0.0', config["rpc_port"])
|
|
ws_site = web.TCPSite(ws_runner, '0.0.0.0', config["ws_port"])
|
|
|
|
# Start both servers
|
|
await rpc_site.start()
|
|
await ws_site.start()
|
|
|
|
logger = logging.getLogger(__name__)
|
|
logger.info(f"RPC server started on port {config['rpc_port']}")
|
|
logger.info(f"WebSocket server started on port {config['ws_port']}")
|
|
logger.info(f"Cache size limit: {config['cache_size_gb']}GB")
|
|
logger.info(f"Provider backoff time: {config['backoff_minutes']} minutes")
|
|
|
|
# Keep servers running
|
|
try:
|
|
await asyncio.Event().wait()
|
|
except KeyboardInterrupt:
|
|
pass
|
|
finally:
|
|
await rpc_runner.cleanup()
|
|
await ws_runner.cleanup()
|
|
|
|
def main() -> None:
|
|
config = load_config()
|
|
setup_logging(config["log_level"])
|
|
|
|
asyncio.run(run_servers(config))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |