From 09ae7bfaa82a59de988a7988312d241b07a0697c Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Sun, 10 Jan 2021 17:01:53 +0100 Subject: make reconnects more reliable * Keep track of a logical clock of draw events * The clock tells all clients if their stored last_drawn words are outdated * Try to reestablish a websocket when an error occurs or the socket gets closed * Alert the user about broken connections and try to reload the page * Don't display the amount of words in the schuessel instead show how many words are still to guess. This is equal for any client. * Rename words_drawn to words_guessed * Ran yapf on schuessel.py and server.py --- cyberschuessel/schuessel.py | 51 ++++--- cyberschuessel/templates/index.html | 287 +++++++++++++++++++++--------------- 2 files changed, 196 insertions(+), 142 deletions(-) diff --git a/cyberschuessel/schuessel.py b/cyberschuessel/schuessel.py index fc3812d..c79815f 100644 --- a/cyberschuessel/schuessel.py +++ b/cyberschuessel/schuessel.py @@ -1,4 +1,3 @@ -import itertools import json import logging import random @@ -13,20 +12,22 @@ class Schuessel: def __init__(self): self.phase = 0 self.words = [] - self.drawn = [] + self.guessed = [] + self.draw_counter = 0 - self.counter = itertools.count() + self.session_counter = 0 self.clients = {} def reset(self): self.phase = 0 self.words = [] - self.drawn = [] + self.guessed = [] def schuessel_state(self): return { 'words': len(self.words), - 'drawn': len(self.drawn), + 'guessed': len(self.guessed), + 'draw_counter': self.draw_counter, 'phase': self.phase } @@ -39,23 +40,27 @@ class Schuessel: # first draw -> start game if self.phase == 0: self.phase = 1 - # we ignore invalid last_words - elif last_word and last_word in self.words: - self.drawn.append(last_word) - del (self.words[self.words.index(last_word)]) + + # we ignore invalid or outdated last_words + elif last_word and last_word['word'] in self.words and last_word[ + 'draw_counter'] == self.draw_counter: + self.guessed.append(last_word['word']) + del (self.words[self.words.index(last_word['word'])]) if len(self.words) == 0: # empty schuessel - if len(self.drawn) == 0: - return + if len(self.guessed) == 0: + return None, False - # move drawn words back into the schuessel - tmp = self.drawn - self.drawn = self.words + # move guessed words back into the schuessel + tmp = self.guessed + self.guessed = self.words self.words = tmp self.phase = self.phase + 1 phase_change = True + self.draw_counter += 1 + word = random.choice(self.words) return word, phase_change @@ -70,7 +75,7 @@ class Schuessel: for session_id in broken_sessions: log.info(f'remove broken session_id {session_id}') - del(self.clients[session_id]) + del (self.clients[session_id]) async def close_all(self): for ws in list(self.clients.values()): @@ -84,7 +89,9 @@ class Schuessel: await ws.prepare(request) - session_id = next(self.counter) + session_id = self.session_counter + self.session_counter += 1 + self.clients[session_id] = ws init_msg = {'action': 'init'} @@ -93,7 +100,7 @@ class Schuessel: try: await ws.send_json(init_msg) except ConnectionResetError: - del(self.clients[session_id]) + del (self.clients[session_id]) return ws async for msg in ws: @@ -102,7 +109,7 @@ class Schuessel: data = json.loads(msg.data) if data['action'] == 'draw': - last_word = data.get('last_word', '') + last_word = data['last_word'] new_word, phase_change = self.draw(last_word) drawn_msg = {'action': 'drawn'} @@ -118,9 +125,10 @@ class Schuessel: 'action': 'draw', 'drawn_word': new_word, 'phase_change': phase_change, + 'draw_counter': self.draw_counter, }) except ConnectionResetError: - del(self.clients[session_id]) + del (self.clients[session_id]) return ws elif data['action'] == 'add': @@ -131,12 +139,13 @@ class Schuessel: elif data['action'] == 'reset': self.reset() - reset_msg = {'action': 'reset'} + reset_msg = {'action': 'init'} reset_msg.update(self.schuessel_state()) await self.broadcast(reset_msg) else: - log.error(f'unknown action received: {data} from {session_id}') + log.error( + f'unknown action received: {data} from {session_id}') elif msg.type == aiohttp.WSMsgType.ERROR: del (self.clients[session_id]) print( diff --git a/cyberschuessel/templates/index.html b/cyberschuessel/templates/index.html index 1eb36b2..2cfb3a0 100644 --- a/cyberschuessel/templates/index.html +++ b/cyberschuessel/templates/index.html @@ -9,7 +9,7 @@ Cyberschuessel - +