This commit is contained in:
MeBeBruno committed 2026-08-09 16:42:33 +02:00
commit 339e0c72ad
3 files changed
+56 -34

No files matched your search

+47 -30
View File
@@ -1,3 +1,6 @@
from gevent import monkey
monkey.patch_all()
import sqlite3
import string
import secrets
@@ -10,16 +13,17 @@ from passlib.hash import argon2
import pyotp
import qrcode
import qrcode.image.svg
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.gevent import GeventScheduler
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.date import DateTrigger
from flask import Flask, request, session, redirect, render_template, url_for, abort, send_from_directory
from flask_socketio import SocketIO, emit, join_room
application = Flask(__name__)
app = application # Fallback-Alias für Gunicorn und Pella
application.secret_key = secrets.token_hex(64)
websocket_manager = SocketIO(application, manage_session=False)
scheduler_instance = BackgroundScheduler(timezone="Europe/Berlin")
websocket_manager = SocketIO(application, manage_session=False, async_mode='gevent')
scheduler_instance = GeventScheduler(timezone="Europe/Berlin")
european_timezone = zoneinfo.ZoneInfo("Europe/Berlin")
IDENTIFIER_LENGTH = 5
@@ -62,7 +66,7 @@ def initialize_database():
""")
connection.execute("""
CREATE TABLE IF NOT EXISTS kill_log (
kill_identifier INTEGER PRIMARY KEY AUTOINCREMENT,
kill_id INTEGER PRIMARY KEY AUTOINCREMENT,
killer_identifier TEXT,
victim_identifier TEXT,
victim_previous_target TEXT,
@@ -240,13 +244,13 @@ def process_administrator_action(action_type, form_data):
new_target = victim["target_identifier"]
connection.execute("UPDATE player SET is_alive = 0, target_identifier = NULL, pending_attacker_identifier = NULL WHERE player_identifier = ?", (target_identifier,))
attacker_identifier = None
attacker_id = None
if attacker:
attacker_identifier = attacker["player_identifier"]
connection.execute("UPDATE player SET target_identifier = ? WHERE player_identifier = ?", (new_target, attacker_identifier))
attacker_id = attacker["player_identifier"]
connection.execute("UPDATE player SET target_identifier = ? WHERE player_identifier = ?", (new_target, attacker_id))
timestamp = datetime.now(european_timezone).isoformat()
connection.execute("INSERT INTO kill_log (killer_identifier, victim_identifier, victim_previous_target, kill_timestamp) VALUES (?, ?, ?, ?)", (attacker_identifier, target_identifier, new_target, timestamp))
connection.execute("INSERT INTO kill_log (killer_identifier, victim_identifier, victim_previous_target, kill_timestamp) VALUES (?, ?, ?, ?)", (attacker_id, target_identifier, new_target, timestamp))
alive_count_record = connection.execute("SELECT COUNT(*) as alive_count FROM player WHERE is_alive = 1 AND is_approved = 1").fetchone()
if alive_count_record["alive_count"] <= 1:
@@ -261,50 +265,50 @@ def process_administrator_action(action_type, form_data):
has_game_state_changed = True
elif action_type == "edit_kill":
kill_identifier = form_data.get("kill_identifier")
new_killer_identifier = form_data.get("new_killer_identifier")
if new_killer_identifier == "":
new_killer_identifier = None
kill_id = form_data.get("kill_id")
new_killer_id = form_data.get("new_killer_identifier")
if new_killer_id == "":
new_killer_id = None
new_timestamp = form_data.get("kill_timestamp")
old_kill = connection.execute("SELECT * FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)).fetchone()
old_kill = connection.execute("SELECT * FROM kill_log WHERE kill_id = ?", (kill_id,)).fetchone()
if old_kill:
old_killer_identifier = old_kill["killer_identifier"]
if old_killer_identifier != new_killer_identifier:
if old_killer_identifier:
connection.execute("UPDATE player SET score = MAX(0, score - 1) WHERE player_identifier = ?", (old_killer_identifier,))
if new_killer_identifier:
connection.execute("UPDATE player SET score = score + 1 WHERE player_identifier = ?", (new_killer_identifier,))
old_killer_id = old_kill["killer_identifier"]
if old_killer_id != new_killer_id:
if old_killer_id:
connection.execute("UPDATE player SET score = MAX(0, score - 1) WHERE player_identifier = ?", (old_killer_id,))
if new_killer_id:
connection.execute("UPDATE player SET score = score + 1 WHERE player_identifier = ?", (new_killer_id,))
connection.execute("UPDATE kill_log SET killer_identifier = ?, kill_timestamp = ? WHERE kill_identifier = ?", (new_killer_identifier, new_timestamp, kill_identifier))
connection.execute("UPDATE kill_log SET killer_identifier = ?, kill_timestamp = ? WHERE kill_id = ?", (new_killer_id, new_timestamp, kill_id))
connection.commit()
has_game_state_changed = True
elif action_type == "revoke_kill":
kill_identifier = form_data.get("kill_identifier")
kill_record = connection.execute("SELECT * FROM kill_log WHERE kill_identifier = ?", (kill_identifier,)).fetchone()
kill_id = form_data.get("kill_id")
kill_record = connection.execute("SELECT * FROM kill_log WHERE kill_id = ?", (kill_id,)).fetchone()
if kill_record:
if kill_record["killer_identifier"]:
connection.execute("UPDATE player SET score = MAX(0, score - 1) WHERE player_identifier = ?", (kill_record["killer_identifier"],))
victim_identifier = kill_record["victim_identifier"]
victim_id = kill_record["victim_identifier"]
target_to_restore = kill_record["victim_previous_target"]
player_pointing_to_target = connection.execute("SELECT player_identifier FROM player WHERE target_identifier = ?", (target_to_restore,)).fetchone()
connection.execute("UPDATE player SET is_alive = 1, target_identifier = ? WHERE player_identifier = ?", (target_to_restore, victim_identifier))
connection.execute("UPDATE player SET is_alive = 1, target_identifier = ? WHERE player_identifier = ?", (target_to_restore, victim_id))
if player_pointing_to_target:
connection.execute("UPDATE player SET target_identifier = ? WHERE player_identifier = ?", (victim_identifier, player_pointing_to_target["player_identifier"]))
connection.execute("UPDATE player SET target_identifier = ? WHERE player_identifier = ?", (victim_id, player_pointing_to_target["player_identifier"]))
connection.execute("DELETE FROM kill_log WHERE kill_identifier = ?", (kill_identifier,))
connection.execute("DELETE FROM kill_log WHERE kill_id = ?", (kill_id,))
alive_count = connection.execute("SELECT COUNT(*) as alive_count FROM player WHERE is_alive = 1 AND is_approved = 1").fetchone()["alive_count"]
if alive_count > 1:
status = connection.execute("SELECT configuration_value FROM game_configuration WHERE configuration_key = 'game_status'").fetchone()["configuration_value"]
if status == 'finished':
connection.execute("UPDATE game_configuration SET configuration_value = 'running' WHERE configuration_key = 'game_status'")
connection.execute("UPDATE player SET score = MAX(0, score - 3) WHERE is_alive = 1 AND is_approved = 1 AND player_identifier != ?", (victim_identifier,))
connection.execute("UPDATE player SET score = MAX(0, score - 3) WHERE is_alive = 1 AND is_approved = 1 AND player_identifier != ?", (victim_id,))
connection.commit()
has_game_state_changed = True
@@ -362,6 +366,11 @@ def scheduled_action_wrapper(action_type, form_data):
def serve_service_worker():
return send_from_directory(application.static_folder, "service_worker.js")
@application.route("/health")
@application.route("/ping")
def handle_health_check():
return "OK", 200
@application.route("/")
@require_player_authentication
def handle_index():
@@ -630,7 +639,15 @@ def handle_elimination_rejection():
emit("elimination_rejected", to=attacker_identifier)
connection.close()
if __name__ == "__main__":
# --- PRODUKTIONS-SETUP (GUNICORN) ---
with application.app_context():
initialize_database()
scheduler_instance.start()
websocket_manager.run(application, host="0.0.0.0", port=5000)
try:
if getattr(scheduler_instance, 'state', 0) == 0:
scheduler_instance.start()
except Exception:
pass
if __name__ == "__main__":
websocket_manager.run(application, host="0.0.0.0", port=5000)
+2
View File
@@ -0,0 +1,2 @@
worker_class = "geventwebsocket.gunicorn.workers.GeventWebSocketWorker"
workers = 1
+7 -4
View File
@@ -1,8 +1,11 @@
flask
flask-socketio
Flask
Flask-SocketIO
APScheduler
passlib
argon2-cffi
pyotp
apscheduler
qrcode
markdown
Markdown
gunicorn
gevent
gevent-websocket