summaryrefslogtreecommitdiffstats
path: root/presenter.py
diff options
context:
space:
mode:
Diffstat (limited to 'presenter.py')
-rw-r--r--presenter.py67
1 files changed, 67 insertions, 0 deletions
diff --git a/presenter.py b/presenter.py
new file mode 100644
index 0000000..613bd34
--- /dev/null
+++ b/presenter.py
@@ -0,0 +1,67 @@
+import json
+import queue
+from flask import Blueprint, Response, render_template
+from sqlalchemy import event
+
+from CTFd.models import Solves, Challenges, Teams
+from CTFd.utils.scores import get_standings
+
+presenter_blueprint = Blueprint(
+ "presenter",
+ __name__,
+ template_folder="templates"
+)
+
+listeners = []
+
+
+def sse_format(data):
+ return f"data: {json.dumps(data)}\n\n"
+
+
+@presenter_blueprint.route("/presenter")
+def presenter_view():
+ return render_template("presenter.html")
+
+
+@presenter_blueprint.route("/presenter/events")
+def presenter_events():
+ def stream():
+ q = queue.Queue()
+ listeners.append(q)
+ try:
+ while True:
+ data = q.get()
+ yield sse_format(data)
+ except GeneratorExit:
+ listeners.remove(q)
+
+ return Response(stream(), mimetype="text/event-stream")
+
+
+def broadcast(event):
+ for q in listeners:
+ q.put(event)
+
+
+@event.listens_for(Solves, "after_insert")
+def on_solve(mapper, connection, solve):
+ challenge = Challenges.query.get(solve.challenge_id)
+ team = Teams.query.get(solve.team_id)
+
+ if not challenge or not team:
+ return
+
+ first_blood = False
+ if Solves.query.filter_by(challenge_id=solve.challenge_id).count() == 1:
+ first_blood = True
+
+ broadcast(
+ {
+ "type": "solve",
+ "team": team.name,
+ "challenge": challenge.name,
+ "value": challenge.value,
+ "first": first_blood
+ }
+ )