full scoreboard update

This commit is contained in:
ilyastar9999
2025-12-03 10:56:33 +03:00
parent c5bcfab44c
commit ac332ab845
4 changed files with 81 additions and 4 deletions

View File

@@ -9,10 +9,12 @@ SECRET_TOKEN=asdasdasd
# Services Directory (where managed services will be stored) # Services Directory (where managed services will be stored)
SERVICES_DIR=/root/services 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_WS_URL=ws://10.60.0.1:8080/api/events
SCOREBOARD_API_URL=http://10.60.0.1:8080/api SCOREBOARD_API_URL=http://10.60.0.1:8080/api
USE_HTTP_POLLING=false
POLLING_INTERVAL=10 POLLING_INTERVAL=10
OUR_TEAM_ID=1 OUR_TEAM_ID=1
ALERT_THRESHOLD_POINTS=100 ALERT_THRESHOLD_POINTS=100

View File

@@ -48,9 +48,11 @@ services:
environment: environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-adctrl}:${POSTGRES_PASSWORD:-adctrl_secure_password}@postgres:5432/${POSTGRES_DB:-adctrl} DATABASE_URL: postgresql://${POSTGRES_USER:-adctrl}:${POSTGRES_PASSWORD:-adctrl_secure_password}@postgres:5432/${POSTGRES_DB:-adctrl}
SECRET_TOKEN: ${SECRET_TOKEN} 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_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} 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} POLLING_INTERVAL: ${POLLING_INTERVAL:-10}
OUR_TEAM_ID: ${OUR_TEAM_ID:-1} OUR_TEAM_ID: ${OUR_TEAM_ID:-1}
ALERT_THRESHOLD_POINTS: ${ALERT_THRESHOLD_POINTS:-100} ALERT_THRESHOLD_POINTS: ${ALERT_THRESHOLD_POINTS:-100}

View File

@@ -8,6 +8,7 @@ import asyncio
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Optional, Dict, Any from typing import Optional, Dict, Any
import aiohttp import aiohttp
import socketio
from fastapi import FastAPI, HTTPException, Depends, Header from fastapi import FastAPI, HTTPException, Depends, Header
from pydantic import BaseModel from pydantic import BaseModel
import asyncpg import asyncpg
@@ -16,9 +17,11 @@ from contextlib import asynccontextmanager
# Configuration # Configuration
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://adctrl:adctrl@postgres:5432/adctrl") DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://adctrl:adctrl@postgres:5432/adctrl")
SECRET_TOKEN = os.getenv("SECRET_TOKEN", "change-me-in-production") 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_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") 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_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 POLLING_INTERVAL = int(os.getenv("POLLING_INTERVAL", "10")) # seconds
OUR_TEAM_ID = int(os.getenv("OUR_TEAM_ID", "1")) OUR_TEAM_ID = int(os.getenv("OUR_TEAM_ID", "1"))
ALERT_THRESHOLD_POINTS = float(os.getenv("ALERT_THRESHOLD_POINTS", "100")) ALERT_THRESHOLD_POINTS = float(os.getenv("ALERT_THRESHOLD_POINTS", "100"))
@@ -272,6 +275,69 @@ async def http_polling_listener():
await asyncio.sleep(POLLING_INTERVAL) 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(): async def websocket_listener():
"""Listen to scoreboard WebSocket for events""" """Listen to scoreboard WebSocket for events"""
reconnect_delay = 5 reconnect_delay = 5
@@ -336,8 +402,14 @@ async def lifespan(app: FastAPI):
global db_pool, ws_task global db_pool, ws_task
db_pool = await asyncpg.create_pool(DATABASE_URL, min_size=2, max_size=10) 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 # 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"Starting HTTP polling mode (interval: {POLLING_INTERVAL}s)")
print(f"Scoreboard API: {SCOREBOARD_API_URL}") print(f"Scoreboard API: {SCOREBOARD_API_URL}")
ws_task = asyncio.create_task(http_polling_listener()) ws_task = asyncio.create_task(http_polling_listener())

View File

@@ -4,3 +4,4 @@ asyncpg==0.29.0
pydantic==2.5.3 pydantic==2.5.3
aiohttp==3.9.1 aiohttp==3.9.1
python-dotenv==1.0.0 python-dotenv==1.0.0
python-socketio[asyncio_client]==5.11.0