From ac332ab84521f96ea628fa8095f2c584cc2e5482 Mon Sep 17 00:00:00 2001 From: ilyastar9999 Date: Wed, 3 Dec 2025 10:56:33 +0300 Subject: [PATCH] full scoreboard update --- .env.example | 6 ++- docker-compose.yaml | 4 +- scoreboard_injector/main.py | 74 +++++++++++++++++++++++++++- scoreboard_injector/requirements.txt | 1 + 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 2cbbfdb..a339221 100644 --- a/.env.example +++ b/.env.example @@ -9,10 +9,12 @@ SECRET_TOKEN=asdasdasd # Services Directory (where managed services will be stored) SERVICES_DIR=/root/services -# Scoreboard Configuration +# Scoreboard Configuration (ForcAD uses Socket.IO) +SCOREBOARD_URL=http://94.228.113.149:8080 +USE_SOCKETIO=true +USE_HTTP_POLLING=false SCOREBOARD_WS_URL=ws://10.60.0.1:8080/api/events SCOREBOARD_API_URL=http://10.60.0.1:8080/api -USE_HTTP_POLLING=false POLLING_INTERVAL=10 OUR_TEAM_ID=1 ALERT_THRESHOLD_POINTS=100 diff --git a/docker-compose.yaml b/docker-compose.yaml index 2a8b294..33343f5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -48,9 +48,11 @@ services: environment: DATABASE_URL: postgresql://${POSTGRES_USER:-adctrl}:${POSTGRES_PASSWORD:-adctrl_secure_password}@postgres:5432/${POSTGRES_DB:-adctrl} SECRET_TOKEN: ${SECRET_TOKEN} + SCOREBOARD_URL: ${SCOREBOARD_URL:-http://10.60.0.1:8080} + USE_SOCKETIO: ${USE_SOCKETIO:-true} + USE_HTTP_POLLING: ${USE_HTTP_POLLING:-false} SCOREBOARD_WS_URL: ${SCOREBOARD_WS_URL:-ws://10.60.0.1:8080/api/events} SCOREBOARD_API_URL: ${SCOREBOARD_API_URL:-http://10.60.0.1:8080/api} - USE_HTTP_POLLING: ${USE_HTTP_POLLING:-false} POLLING_INTERVAL: ${POLLING_INTERVAL:-10} OUR_TEAM_ID: ${OUR_TEAM_ID:-1} ALERT_THRESHOLD_POINTS: ${ALERT_THRESHOLD_POINTS:-100} diff --git a/scoreboard_injector/main.py b/scoreboard_injector/main.py index 2e56789..174652d 100644 --- a/scoreboard_injector/main.py +++ b/scoreboard_injector/main.py @@ -8,6 +8,7 @@ import asyncio from datetime import datetime, timedelta from typing import Optional, Dict, Any import aiohttp +import socketio from fastapi import FastAPI, HTTPException, Depends, Header from pydantic import BaseModel import asyncpg @@ -16,9 +17,11 @@ from contextlib import asynccontextmanager # Configuration DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://adctrl:adctrl@postgres:5432/adctrl") SECRET_TOKEN = os.getenv("SECRET_TOKEN", "change-me-in-production") +SCOREBOARD_URL = os.getenv("SCOREBOARD_URL", "http://10.60.0.1:8080") # Base URL for Socket.IO SCOREBOARD_WS_URL = os.getenv("SCOREBOARD_WS_URL", "ws://scoreboard:8080/api/events") SCOREBOARD_API_URL = os.getenv("SCOREBOARD_API_URL", "http://10.60.0.1:8080/api") USE_HTTP_POLLING = os.getenv("USE_HTTP_POLLING", "false").lower() == "true" +USE_SOCKETIO = os.getenv("USE_SOCKETIO", "true").lower() == "true" # Use Socket.IO by default POLLING_INTERVAL = int(os.getenv("POLLING_INTERVAL", "10")) # seconds OUR_TEAM_ID = int(os.getenv("OUR_TEAM_ID", "1")) ALERT_THRESHOLD_POINTS = float(os.getenv("ALERT_THRESHOLD_POINTS", "100")) @@ -272,6 +275,69 @@ async def http_polling_listener(): await asyncio.sleep(POLLING_INTERVAL) +async def socketio_listener(): + """Listen to ForcAD scoreboard using Socket.IO""" + sio = socketio.AsyncClient(logger=False, engineio_logger=False) + + @sio.event(namespace='/game_events') + async def update_scoreboard(data): + """Handle scoreboard update events""" + try: + event_data = data.get('data', {}) + round_num = event_data.get('round', 0) + team_tasks = event_data.get('team_tasks', []) + + print(f"📊 Round {round_num} - Processing {len(team_tasks)} team updates") + + for team_task in team_tasks: + team_id = team_task.get('team_id') + task_id = team_task.get('task_id') + stolen = team_task.get('stolen', 0) + lost = team_task.get('lost', 0) + + if team_id == OUR_TEAM_ID and (stolen > 0 or lost > 0): + print(f" Team {team_id} Task {task_id}: stolen={stolen}, lost={lost}") + + except Exception as e: + print(f"Error processing update_scoreboard: {e}") + + @sio.event(namespace='/game_events') + async def init_scoreboard(data): + """Handle initial scoreboard data""" + try: + print("📡 Received initial scoreboard data") + event_data = data.get('data', {}) + teams = event_data.get('teams', []) + tasks = event_data.get('tasks', []) + + print(f" Teams: {', '.join([f\"{t.get('name')} (ID:{t.get('id')})\" for t in teams])}") + print(f" Tasks: {', '.join([t.get('name') for t in tasks])}") + + except Exception as e: + print(f"Error processing init_scoreboard: {e}") + + @sio.event + async def connect(): + print("✅ Connected to ForcAD scoreboard Socket.IO") + + @sio.event + async def disconnect(): + print("❌ Disconnected from scoreboard") + + while True: + try: + print(f"Connecting to {SCOREBOARD_URL}/socket.io ...") + await sio.connect( + SCOREBOARD_URL, + namespaces=['/game_events'], + transports=['websocket'] + ) + await sio.wait() + except Exception as e: + print(f"Socket.IO error: {e}") + print("Reconnecting in 5 seconds...") + await asyncio.sleep(5) + async def websocket_listener(): """Listen to scoreboard WebSocket for events""" reconnect_delay = 5 @@ -336,8 +402,14 @@ async def lifespan(app: FastAPI): global db_pool, ws_task db_pool = await asyncpg.create_pool(DATABASE_URL, min_size=2, max_size=10) + print(f"Our team ID: {OUR_TEAM_ID}") + # Start listener based on configuration - if USE_HTTP_POLLING: + if USE_SOCKETIO: + print(f"Starting Socket.IO mode") + print(f"Scoreboard URL: {SCOREBOARD_URL}") + ws_task = asyncio.create_task(socketio_listener()) + elif USE_HTTP_POLLING: print(f"Starting HTTP polling mode (interval: {POLLING_INTERVAL}s)") print(f"Scoreboard API: {SCOREBOARD_API_URL}") ws_task = asyncio.create_task(http_polling_listener()) diff --git a/scoreboard_injector/requirements.txt b/scoreboard_injector/requirements.txt index c5d9f83..9d390bd 100644 --- a/scoreboard_injector/requirements.txt +++ b/scoreboard_injector/requirements.txt @@ -4,3 +4,4 @@ asyncpg==0.29.0 pydantic==2.5.3 aiohttp==3.9.1 python-dotenv==1.0.0 +python-socketio[asyncio_client]==5.11.0