diff --git a/scoreboard_injector/main.py b/scoreboard_injector/main.py index 8509190..d01f48d 100644 --- a/scoreboard_injector/main.py +++ b/scoreboard_injector/main.py @@ -193,7 +193,66 @@ async def socketio_listener(): task_names = {} team_names = {} - @sio.event(namespace='/game_events') + @sio.on('*', namespace='/live_events') + async def catch_all(event, data): + """Catch all events from live_events namespace""" + print(f"📡 Received event: {event}") + print(f" Data: {data}") + + # Parse the event format: ["event_type", {"data": ...}] + if isinstance(data, list) and len(data) >= 2: + event_type = data[0] + event_data = data[1].get('data', {}) if isinstance(data[1], dict) else {} + + if event_type == 'flag_stolen': + await process_flag_stolen(event_data) + elif isinstance(data, dict): + # Handle direct event data + if 'data' in data: + await process_flag_stolen(data['data']) + + async def process_flag_stolen(event_data): + """Process flag_stolen event""" + try: + attacker_id = event_data.get('attacker_id') + victim_id = event_data.get('victim_id') + task_id = event_data.get('task_id') + attacker_delta = event_data.get('attacker_delta', 0) + + if attacker_id is None or victim_id is None: + return + + service_name = task_names.get(task_id, f"task_{task_id}") + timestamp = datetime.utcnow() + + is_our_attack = attacker_id == OUR_TEAM_ID + is_attack_to_us = victim_id == OUR_TEAM_ID + + if is_our_attack or is_attack_to_us: + conn = await db_pool.acquire() + try: + attack_id = f"flag_{attacker_id}_{victim_id}_{task_id}_{int(timestamp.timestamp())}" + + await conn.execute(""" + INSERT INTO attacks (attack_id, attacker_team_id, victim_team_id, service_name, timestamp, points, is_our_attack, is_attack_to_us) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + ON CONFLICT (attack_id) DO NOTHING + """, attack_id, attacker_id, victim_id, service_name, timestamp, float(attacker_delta), is_our_attack, is_attack_to_us) + + if is_our_attack: + print(f" ✅ We stole flag from Team {victim_id} on {service_name} (+{attacker_delta:.2f} FP)") + elif is_attack_to_us: + print(f" ⚠️ Team {attacker_id} stole flag from us on {service_name} (-{attacker_delta:.2f} FP)") + if attacker_delta >= ALERT_THRESHOLD_POINTS: + await check_and_create_alerts(conn, attacker_id, service_name) + finally: + await db_pool.release(conn) + except Exception as e: + print(f"Error processing flag_stolen event: {e}") + import traceback + traceback.print_exc() + + @sio.event(namespace='/live_events') async def update_scoreboard(data): """Handle scoreboard update - compare with previous state to detect NEW attacks""" try: @@ -272,44 +331,49 @@ async def socketio_listener(): """, team_id, service_name, current_stolen, current_lost, current_fp_score) # Create single attack record when flags change (not first update) + # Only track attacks involving our team to avoid duplicates if not is_first_update and (new_stolen > 0 or new_lost > 0): timestamp = datetime.utcnow() is_our_attack = (new_stolen > 0 and team_id == OUR_TEAM_ID) is_attack_to_us = (new_lost > 0 and team_id == OUR_TEAM_ID) - # Determine attacker/victim and FP - if new_stolen > 0: - # This team stole flags (attacker) - attacker_id = team_id - victim_id = None # We don't know exact victim - fp_value = max(0, fp_change) - attack_type = "stolen" - else: - # This team lost flags (victim) - attacker_id = None # We don't know exact attacker - victim_id = team_id - fp_value = abs(min(0, fp_change)) - attack_type = "lost" + # Only create records for attacks involving OUR team + should_record = is_our_attack or is_attack_to_us - attack_id = f"r{round_num}_{attack_type}_team{team_id}_{service_name}_{int(timestamp.timestamp())}" - - await conn.execute(""" - INSERT INTO attacks (attack_id, attacker_team_id, victim_team_id, service_name, timestamp, points, is_our_attack, is_attack_to_us) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8) - ON CONFLICT (attack_id) DO NOTHING - """, attack_id, attacker_id, victim_id, service_name, timestamp, float(fp_value), is_our_attack, is_attack_to_us) - - if is_our_attack: - print(f" ✅ We stole {new_stolen} flags from {service_name} (+{fp_value:.2f} FP)") - elif is_attack_to_us: - print(f" ⚠️ We LOST {new_lost} flags on {service_name} (-{fp_value:.2f} FP)") - if fp_value >= ALERT_THRESHOLD_POINTS: - await check_and_create_alerts(conn, 0, service_name) + if should_record: + # Determine attacker/victim and FP + if new_stolen > 0: + # This team stole flags (attacker) + attacker_id = team_id + victim_id = None # We don't know exact victim + fp_value = max(0, fp_change) + attack_type = "stolen" + else: + # This team lost flags (victim) + attacker_id = None # We don't know exact attacker + victim_id = team_id + fp_value = abs(min(0, fp_change)) + attack_type = "lost" + + attack_id = f"r{round_num}_{attack_type}_team{team_id}_{service_name}_{int(timestamp.timestamp())}" + + await conn.execute(""" + INSERT INTO attacks (attack_id, attacker_team_id, victim_team_id, service_name, timestamp, points, is_our_attack, is_attack_to_us) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + ON CONFLICT (attack_id) DO NOTHING + """, attack_id, attacker_id, victim_id, service_name, timestamp, float(fp_value), is_our_attack, is_attack_to_us) + + if is_our_attack: + print(f" ✅ We stole {new_stolen} flags from {service_name} (+{fp_value:.2f} FP)") + elif is_attack_to_us: + print(f" ⚠️ We LOST {new_lost} flags on {service_name} (-{fp_value:.2f} FP)") + if fp_value >= ALERT_THRESHOLD_POINTS: + await check_and_create_alerts(conn, 0, service_name) elif new_stolen > 0: - print(f" 📌 Team {team_id} stole {new_stolen} flags from {service_name} (+{fp_value:.2f} FP)") - else: - print(f" 📌 Team {team_id} lost {new_lost} flags on {service_name} (-{fp_value:.2f} FP)") + print(f" 📌 Team {team_id} stole {new_stolen} flags from {service_name} (+{fp_change:.2f} FP)") + elif new_lost > 0: + print(f" 📌 Team {team_id} lost {new_lost} flags on {service_name} ({fp_change:.2f} FP)") finally: await db_pool.release(conn) @@ -318,7 +382,7 @@ async def socketio_listener(): import traceback traceback.print_exc() - @sio.event(namespace='/game_events') + @sio.event(namespace='/live_events') async def init_scoreboard(data): """Handle initial scoreboard data""" try: @@ -356,7 +420,7 @@ async def socketio_listener(): print(f"Connecting to {SCOREBOARD_URL}/socket.io ...") await sio.connect( SCOREBOARD_URL, - namespaces=['/game_events'], + namespaces=['/live_events'], transports=['websocket'] ) await sio.wait()