230 lines
7.7 KiB
Python
230 lines
7.7 KiB
Python
from flask_socketio import SocketIO, emit, join_room, leave_room
|
|
from flask import request
|
|
from app.services import SessionService
|
|
import threading
|
|
import json
|
|
from redis import Redis
|
|
|
|
|
|
class SocketController:
|
|
def __init__(
|
|
self,
|
|
socketio: SocketIO,
|
|
session_service: SessionService,
|
|
):
|
|
self.socketio = socketio
|
|
self.session_service = session_service
|
|
self._register_events()
|
|
|
|
def _register_events(self):
|
|
@self.socketio.on("connect")
|
|
def on_connect():
|
|
print(f"Client connected: {request.sid}")
|
|
emit("connection_response", {"status": "connected", "sid": request.sid})
|
|
|
|
@self.socketio.on("disconnect")
|
|
def on_disconnect():
|
|
print(f"Client disconnected: {request.sid}")
|
|
|
|
@self.socketio.on("join_room")
|
|
def handle_join_room(data):
|
|
session_code = data.get("session_code")
|
|
user_id = data.get("user_id")
|
|
|
|
if not session_code or not user_id:
|
|
emit("error", {"message": "session_code and user_id are required"})
|
|
return
|
|
|
|
session = self.session_service.join_session(
|
|
session_code=session_code,
|
|
user_id=user_id,
|
|
)
|
|
|
|
if session is None:
|
|
emit("error", {"message": "Failed to join session or session inactive"})
|
|
return
|
|
|
|
session_id = session["session_id"]
|
|
|
|
join_room(session_id)
|
|
|
|
if session["is_admin"]:
|
|
message = "Admin has joined the room."
|
|
else:
|
|
message = f"User {session['username']} has joined the room."
|
|
|
|
emit(
|
|
"room_message",
|
|
{
|
|
"type": "join",
|
|
"message": message,
|
|
"room": session_id,
|
|
"argument": "adm_update",
|
|
"data": {
|
|
"session_info": session["session_info"],
|
|
"quiz_info": session["quiz_info"],
|
|
},
|
|
},
|
|
to=request.sid,
|
|
)
|
|
|
|
emit(
|
|
"room_message",
|
|
{
|
|
"type": "participan_join",
|
|
"message": message,
|
|
"room": session_id,
|
|
"argument": "adm_update",
|
|
"data": {
|
|
"participants": session["session_info"]["participants"],
|
|
},
|
|
},
|
|
room=session_id,
|
|
skip_sid=request.sid,
|
|
)
|
|
|
|
# @self.socketio.on("submit_answer")
|
|
# def handle_submit_answer(data):
|
|
# session_code = data.get("session_id")
|
|
# user_id = data.get("user_id")
|
|
# question_index = data.get("question_index")
|
|
# user_answer = data.get("answer")
|
|
|
|
# if not all(
|
|
# [
|
|
# session_code,
|
|
# user_id,
|
|
# question_index is not None,
|
|
# user_answer is not None,
|
|
# ]
|
|
# ):
|
|
# emit(
|
|
# "error",
|
|
# {
|
|
# "message": "session_id, user_id, question_index, and answer are required"
|
|
# },
|
|
# )
|
|
# return
|
|
|
|
# quiz_service = QuizService(self.redis_repo)
|
|
# question = quiz_service.get_question(session_code, question_index)
|
|
|
|
# if question is None:
|
|
# emit("error", {"message": "Question not found"})
|
|
# return
|
|
|
|
# is_correct = quiz_service.is_correct(user_answer, question)
|
|
|
|
# print(
|
|
# f"User {user_id} answered Q{question_index} with '{user_answer}' -> {'✔' if is_correct else '✖'}"
|
|
# )
|
|
|
|
# quiz_service.save_answer(
|
|
# session_code, user_id, question_index, user_answer, is_correct
|
|
# )
|
|
# scores = quiz_service.update_score(session_code, user_id, is_correct)
|
|
|
|
# emit(
|
|
# "answer_submitted",
|
|
# {
|
|
# "user_id": user_id,
|
|
# "question_index": question_index,
|
|
# "answer": user_answer,
|
|
# "correct": is_correct,
|
|
# },
|
|
# room=request.sid,
|
|
# )
|
|
|
|
# admin_sid = self.admin_sids.get(session_code)
|
|
# if admin_sid:
|
|
# emit("score_update", scores, room=admin_sid)
|
|
|
|
@self.socketio.on("leave_room")
|
|
def handle_leave_room(data):
|
|
session_id = data.get("session_id")
|
|
user_id = data.get("user_id")
|
|
username = data.get("username", "anonymous")
|
|
|
|
leave_result = self.session_service.leave_session(
|
|
session_id=session_id,
|
|
user_id=user_id,
|
|
)
|
|
leave_room(session_id)
|
|
if leave_result["is_success"]:
|
|
emit(
|
|
"room_message",
|
|
{
|
|
"type": "participan_leave",
|
|
"message": f"{username} has left the room.",
|
|
"room": session_id,
|
|
"argument": "adm_update",
|
|
"data": {
|
|
"participants": leave_result["participants"],
|
|
},
|
|
},
|
|
room=session_id,
|
|
skip_sid=request.sid,
|
|
)
|
|
emit(
|
|
"room_message",
|
|
{
|
|
"type": "leave",
|
|
"message": f"{username} has left the room.",
|
|
"room": session_id,
|
|
"argument": "adm_update",
|
|
"data": None,
|
|
},
|
|
room=session_id,
|
|
to=request.sid,
|
|
)
|
|
|
|
@self.socketio.on("send_message")
|
|
def on_send_message(data):
|
|
session_code = data.get("session_id")
|
|
message = data.get("message")
|
|
username = data.get("username", "anonymous")
|
|
emit(
|
|
"receive_message",
|
|
{"message": message, "from": username},
|
|
room=session_code,
|
|
)
|
|
|
|
@self.socketio.on("end_session")
|
|
def handle_end_session(data):
|
|
session_code = data.get("session_id")
|
|
user_id = data.get("user_id")
|
|
if not session_code or not user_id:
|
|
emit("error", {"message": "session_id and user_id required"})
|
|
return
|
|
|
|
# Validasi user berhak mengakhiri session
|
|
self.session_service.end_session(session_id=session_code, user_id=user_id)
|
|
|
|
# Bersihkan semua data session di Redis
|
|
for key in [
|
|
self._answers_key(session_code),
|
|
self._scores_key(session_code),
|
|
self._questions_key(session_code),
|
|
]:
|
|
self.redis_repo.delete_key(key)
|
|
|
|
emit(
|
|
"room_closed",
|
|
{"message": "Session has ended.", "room": session_code},
|
|
room=session_code,
|
|
)
|
|
|
|
@self.socketio.on("start_quiz")
|
|
def handle_start_quiz(data):
|
|
session_id = data.get("session_id")
|
|
if not session_id:
|
|
emit("error", {"message": "session_id is required"})
|
|
return
|
|
|
|
emit("quiz_started", {"message": "Quiz has started!"}, room=session_id)
|
|
threading.Thread(
|
|
target=self.session_service.simulate_quiz_flow,
|
|
args=(session_id, self.socketio),
|
|
daemon=True,
|
|
).start()
|