Skip to content

Commit

Permalink
Merge pull request #281 from mawoka-myblock/auto-reconnect
Browse files Browse the repository at this point in the history
  • Loading branch information
mawoka-myblock authored Sep 12, 2023
2 parents 78dc3a4 + f712bdf commit 4e43b7b
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 45 deletions.
140 changes: 97 additions & 43 deletions classquiz/socket_server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,54 @@ class _JoinGameData(BaseModel):
custom_field: str | None


class _RejoinGameData(BaseModel):
old_sid: str
game_pin: str
username: str


@sio.event
async def rejoin_game(sid: str, data: dict):
redis_res = await redis.get(f"game:{data['game_pin']}")
if redis_res is None:
await sio.emit("game_not_found", room=sid)
return
try:
data = _RejoinGameData(**data)
except ValidationError as e:
await sio.emit("error", room=sid)
print(e)
redis_sid_key = f"game_session:{data.game_pin}:players:{data.username}"
old_sid = await redis.get(redis_sid_key)
if old_sid != data.old_sid:
return
encrypted_datetime = fernet.encrypt(datetime.now().isoformat().encode("utf-8")).decode("utf-8")
await sio.emit("time_sync", encrypted_datetime, room=sid)
await redis.set(redis_sid_key, sid)
deleted_num = await redis.srem(
f"game_session:{data.game_pin}:players", GamePlayer(username=data.username, sid=data.old_sid).json()
)
print(deleted_num)
await redis.sadd(f"game_session:{data.game_pin}:players", GamePlayer(username=data.username, sid=sid).json())
game_data = PlayGame.parse_raw(redis_res)
session = {
"game_pin": data.game_pin,
"username": data.username,
"sid_custom": sid,
"admin": False,
}
await sio.save_session(sid, session)
sio.enter_room(sid, data.game_pin)
await sio.emit(
"rejoined_game",
{
**json.loads(game_data.json(exclude={"quiz_id", "questions", "user_id"})),
"question_count": len(game_data.questions),
},
room=sid,
)


@sio.event
async def join_game(sid: str, data: dict):
redis_res = await redis.get(f"game:{data['game_pin']}")
Expand Down Expand Up @@ -177,12 +225,13 @@ async def join_game(sid: str, data: dict):
@sio.event
async def start_game(sid: str, _data: dict):
session = await sio.get_session(sid)
if session["admin"]:
game_data = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}"))
game_data.started = True
await redis.set(f"game:{session['game_pin']}", game_data.json(), ex=7200)
await redis.delete(f"game_in_lobby:{game_data.user_id.hex}")
await sio.emit("start_game", room=session["game_pin"])
if not session["admin"]:
return
game_data = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}"))
game_data.started = True
await redis.set(f"game:{session['game_pin']}", game_data.json(), ex=7200)
await redis.delete(f"game_in_lobby:{game_data.user_id.hex}")
await sio.emit("start_game", room=session["game_pin"])


class _RegisterAsAdminData(BaseModel):
Expand Down Expand Up @@ -225,15 +274,19 @@ async def register_as_admin(sid: str, data: dict):
@sio.event
async def get_question_results(sid: str, data: dict):
session = await sio.get_session(sid)
if session["admin"]:
redis_res = AnswerDataList.parse_raw(
await redis.get(f"game_session:{session['game_pin']}:{data['question_number']}")
)
game_data = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}"))
game_data.question_show = False
await redis.set(f"game:{session['game_pin']}", game_data.json())
game_pin = session["game_pin"]
await sio.emit("question_results", redis_res.dict()["__root__"], room=game_pin)
if not session["admin"]:
return

redis_res = await redis.get(f"game_session:{session['game_pin']}:{data['question_number']}")
if redis_res is None:
redis_res = []
else:
redis_res = AnswerDataList.parse_raw(redis_res)
game_data = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}"))
game_data.question_show = False
await redis.set(f"game:{session['game_pin']}", game_data.json())
game_pin = session["game_pin"]
await sio.emit("question_results", redis_res.dict()["__root__"], room=game_pin)


class ABCDQuizAnswerWithoutSolution(BaseModel):
Expand All @@ -252,12 +305,12 @@ class ReturnQuestion(QuizQuestion):

@validator("answers")
def answers_not_none_if_abcd_type(cls, v, values):
if values["type"] == QuizQuestionType.ABCD and type(v[0]) != ABCDQuizAnswerWithoutSolution:
if values["type"] == QuizQuestionType.ABCD and type(v[0]) is not ABCDQuizAnswerWithoutSolution:
raise ValueError("Answers can't be none if type is ABCD")
if values["type"] == QuizQuestionType.RANGE and type(v) != RangeQuizAnswerWithoutSolution:
if values["type"] == QuizQuestionType.RANGE and type(v) is not RangeQuizAnswerWithoutSolution:
raise ValueError("Answer must be from type RangeQuizAnswer if type is RANGE")
# skipcq: PTC-W0047
if values["type"] == QuizQuestionType.VOTING and type(v[0]) != VotingQuizAnswer:
if values["type"] == QuizQuestionType.VOTING and type(v[0]) is not VotingQuizAnswer:
pass
return v

Expand All @@ -266,37 +319,38 @@ def answers_not_none_if_abcd_type(cls, v, values):
async def set_question_number(sid, data: str):
# data is just a number (as a str) of the question
session = await sio.get_session(sid)
if session["admin"]:
game_pin = session["game_pin"]
game_data = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}"))
game_data.current_question = int(float(data))
game_data.question_show = True
await redis.set(f"game:{session['game_pin']}", game_data.json(), ex=7200)
await redis.set(f"game:{session['game_pin']}:current_time", datetime.now().isoformat(), ex=7200)
temp_return = game_data.dict(include={"questions"})["questions"][int(float(data))]
if game_data.questions[int(float(data))].type == QuizQuestionType.SLIDE:
await sio.emit(
"set_question_number",
{
"question_index": int(float(data)),
},
room=sid,
)
return
if game_data.questions[int(float(data))].type == QuizQuestionType.VOTING:
for i in range(len(temp_return["answers"])):
temp_return["answers"][i] = VotingQuizAnswer(**temp_return["answers"][i])
temp_return["type"] = game_data.questions[int(float(data))].type
if temp_return["type"] == QuizQuestionType.ORDER:
random.shuffle(temp_return["answers"])
if not session["admin"]:
return
game_pin = session["game_pin"]
game_data = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}"))
game_data.current_question = int(float(data))
game_data.question_show = True
await redis.set(f"game:{session['game_pin']}", game_data.json(), ex=7200)
await redis.set(f"game:{session['game_pin']}:current_time", datetime.now().isoformat(), ex=7200)
temp_return = game_data.dict(include={"questions"})["questions"][int(float(data))]
if game_data.questions[int(float(data))].type == QuizQuestionType.SLIDE:
await sio.emit(
"set_question_number",
{
"question_index": int(float(data)),
"question": ReturnQuestion(**temp_return).dict(),
},
room=game_pin,
room=sid,
)
return
if game_data.questions[int(float(data))].type == QuizQuestionType.VOTING:
for i in range(len(temp_return["answers"])):
temp_return["answers"][i] = VotingQuizAnswer(**temp_return["answers"][i])
temp_return["type"] = game_data.questions[int(float(data))].type
if temp_return["type"] == QuizQuestionType.ORDER:
random.shuffle(temp_return["answers"])
await sio.emit(
"set_question_number",
{
"question_index": int(float(data)),
"question": ReturnQuestion(**temp_return).dict(),
},
room=game_pin,
)


class _SubmitAnswerDataOrderType(BaseModel):
Expand Down
28 changes: 26 additions & 2 deletions frontend/src/routes/play/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ SPDX-License-Identifier: MPL-2.0
import KahootResults from '$lib/play/results_kahoot.svelte';
import { getLocalization } from '$lib/i18n';
import Cookies from 'js-cookie';
const { t } = getLocalization();
// Exports
Expand Down Expand Up @@ -74,14 +73,38 @@ SPDX-License-Identifier: MPL-2.0
socket.emit('echo_time_sync', data);
});
socket.on("connect", () => {
console.log("Connected!")
const cookie_data = Cookies.get("joined_game")
if (!cookie_data) {
return
}
const data = JSON.parse(cookie_data)
socket.emit("rejoin_game", {old_sid: data.sid, username: data.username, game_pin: data.game_pin})
})
// Socket-events
socket.on('joined_game', (data) => {
gameData = data;
// eslint-disable-next-line no-undef
plausible('Joined Game', { props: { game_id: gameData.game_id } });
Cookies.set("joined_game", JSON.stringify({sid: socket.id, username, game_pin}), {expires: 3600})
});
socket.on('rejoined_game', (data) => {
gameData = data;
if (data.started) {
gameMeta.started = true
}
});
socket.on('game_not_found', () => {
const cookie_data = Cookies.get("joined_game")
if (cookie_data) {
Cookies.remove("joined_game")
window.location.reload()
return
}
game_pin_valid = false;
});
Expand Down Expand Up @@ -120,6 +143,7 @@ SPDX-License-Identifier: MPL-2.0
});
socket.on('final_results', (data) => {
final_results = data;
Cookies.remove("joined_game")
});
socket.on('solutions', (data) => {
Expand Down Expand Up @@ -149,7 +173,7 @@ SPDX-License-Identifier: MPL-2.0
>
<div>
{#if !gameMeta.started && gameData === undefined}
<JoinGame {game_pin} bind:game_mode bind:username />
<JoinGame bind:game_pin bind:game_mode bind:username />
{:else if JSON.stringify(final_results) !== JSON.stringify([null])}
<ShowEndScreen bind:data={scores} show_final_results={true} bind:username />
{:else if gameData !== undefined && question_index === ''}
Expand Down

0 comments on commit 4e43b7b

Please sign in to comment.