✨ Implemented basic connection recovery
This commit is contained in:
@@ -80,6 +80,54 @@ class _JoinGameData(BaseModel):
|
|||||||
custom_field: str | None
|
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
|
@sio.event
|
||||||
async def join_game(sid: str, data: dict):
|
async def join_game(sid: str, data: dict):
|
||||||
redis_res = await redis.get(f"game:{data['game_pin']}")
|
redis_res = await redis.get(f"game:{data['game_pin']}")
|
||||||
@@ -177,7 +225,8 @@ async def join_game(sid: str, data: dict):
|
|||||||
@sio.event
|
@sio.event
|
||||||
async def start_game(sid: str, _data: dict):
|
async def start_game(sid: str, _data: dict):
|
||||||
session = await sio.get_session(sid)
|
session = await sio.get_session(sid)
|
||||||
if session["admin"]:
|
if not session["admin"]:
|
||||||
|
return
|
||||||
game_data = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}"))
|
game_data = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}"))
|
||||||
game_data.started = True
|
game_data.started = True
|
||||||
await redis.set(f"game:{session['game_pin']}", game_data.json(), ex=7200)
|
await redis.set(f"game:{session['game_pin']}", game_data.json(), ex=7200)
|
||||||
@@ -225,10 +274,14 @@ async def register_as_admin(sid: str, data: dict):
|
|||||||
@sio.event
|
@sio.event
|
||||||
async def get_question_results(sid: str, data: dict):
|
async def get_question_results(sid: str, data: dict):
|
||||||
session = await sio.get_session(sid)
|
session = await sio.get_session(sid)
|
||||||
if session["admin"]:
|
if not session["admin"]:
|
||||||
redis_res = AnswerDataList.parse_raw(
|
return
|
||||||
await redis.get(f"game_session:{session['game_pin']}:{data['question_number']}")
|
|
||||||
)
|
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 = PlayGame.parse_raw(await redis.get(f"game:{session['game_pin']}"))
|
||||||
game_data.question_show = False
|
game_data.question_show = False
|
||||||
await redis.set(f"game:{session['game_pin']}", game_data.json())
|
await redis.set(f"game:{session['game_pin']}", game_data.json())
|
||||||
@@ -252,12 +305,12 @@ class ReturnQuestion(QuizQuestion):
|
|||||||
|
|
||||||
@validator("answers")
|
@validator("answers")
|
||||||
def answers_not_none_if_abcd_type(cls, v, values):
|
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")
|
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")
|
raise ValueError("Answer must be from type RangeQuizAnswer if type is RANGE")
|
||||||
# skipcq: PTC-W0047
|
# 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
|
pass
|
||||||
return v
|
return v
|
||||||
|
|
||||||
@@ -266,7 +319,8 @@ class ReturnQuestion(QuizQuestion):
|
|||||||
async def set_question_number(sid, data: str):
|
async def set_question_number(sid, data: str):
|
||||||
# data is just a number (as a str) of the question
|
# data is just a number (as a str) of the question
|
||||||
session = await sio.get_session(sid)
|
session = await sio.get_session(sid)
|
||||||
if session["admin"]:
|
if not session["admin"]:
|
||||||
|
return
|
||||||
game_pin = session["game_pin"]
|
game_pin = session["game_pin"]
|
||||||
game_data = PlayGame.parse_raw(await redis.get(f"game:{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.current_question = int(float(data))
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
import KahootResults from '$lib/play/results_kahoot.svelte';
|
import KahootResults from '$lib/play/results_kahoot.svelte';
|
||||||
import { getLocalization } from '$lib/i18n';
|
import { getLocalization } from '$lib/i18n';
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
const { t } = getLocalization();
|
const { t } = getLocalization();
|
||||||
|
|
||||||
// Exports
|
// Exports
|
||||||
@@ -74,14 +73,38 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
socket.emit('echo_time_sync', data);
|
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-events
|
||||||
socket.on('joined_game', (data) => {
|
socket.on('joined_game', (data) => {
|
||||||
gameData = data;
|
gameData = data;
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
plausible('Joined Game', { props: { game_id: gameData.game_id } });
|
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', () => {
|
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;
|
game_pin_valid = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -120,6 +143,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
});
|
});
|
||||||
socket.on('final_results', (data) => {
|
socket.on('final_results', (data) => {
|
||||||
final_results = data;
|
final_results = data;
|
||||||
|
Cookies.remove("joined_game")
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('solutions', (data) => {
|
socket.on('solutions', (data) => {
|
||||||
@@ -149,7 +173,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
{#if !gameMeta.started && gameData === undefined}
|
{#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])}
|
{:else if JSON.stringify(final_results) !== JSON.stringify([null])}
|
||||||
<ShowEndScreen bind:data={scores} show_final_results={true} bind:username />
|
<ShowEndScreen bind:data={scores} show_final_results={true} bind:username />
|
||||||
{:else if gameData !== undefined && question_index === ''}
|
{:else if gameData !== undefined && question_index === ''}
|
||||||
|
|||||||
Reference in New Issue
Block a user