From 28e93b1fa370091099fb9b654ef1c5c87534dfc6 Mon Sep 17 00:00:00 2001 From: Paul Brinkmeier Date: Sun, 15 Jan 2023 16:09:50 +0100 Subject: [PATCH] Set up simple chat server --- glebby-client/src/App.vue | 38 ++++++- glebby-client/src/components/Game.vue | 102 +++++++++++++++++ glebby-client/src/components/HelloWorld.vue | 15 --- glebby-server/glebby.py | 119 +++++++++++++++++++- 4 files changed, 250 insertions(+), 24 deletions(-) create mode 100644 glebby-client/src/components/Game.vue delete mode 100644 glebby-client/src/components/HelloWorld.vue diff --git a/glebby-client/src/App.vue b/glebby-client/src/App.vue index f5b68e7..d751ca4 100644 --- a/glebby-client/src/App.vue +++ b/glebby-client/src/App.vue @@ -1,7 +1,39 @@ - diff --git a/glebby-client/src/components/Game.vue b/glebby-client/src/components/Game.vue new file mode 100644 index 0000000..4c783e0 --- /dev/null +++ b/glebby-client/src/components/Game.vue @@ -0,0 +1,102 @@ + + + diff --git a/glebby-client/src/components/HelloWorld.vue b/glebby-client/src/components/HelloWorld.vue deleted file mode 100644 index 6ca4084..0000000 --- a/glebby-client/src/components/HelloWorld.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/glebby-server/glebby.py b/glebby-server/glebby.py index 2e7dd04..d124b00 100644 --- a/glebby-server/glebby.py +++ b/glebby-server/glebby.py @@ -1,16 +1,123 @@ -from flask import Flask, render_template -from flask_sock import Sock +import json import simple_websocket +from flask import Flask +from flask_sock import Sock +from queue import Queue +from threading import Thread, Lock + +class Client: + def __init__(self, sock, client_id): + self.sock = sock + self.data = { 'id': client_id, 'name': '' } + +class GlebbyState: + def __init__(self): + self.clients_lock = Lock() + self.clients = dict() + + self.next_client_id_lock = Lock() + self.next_client_id = 0 + + self.incoming_messages = Queue() + + # domain stuff + + def handle_message_from(self, client_id, payload): + print(f"{client_id}: {payload}") + + if payload['type'] == 'set-name': + self.clients[client_id].data['name'] = payload['name'] + self.broadcast(client_id, { + 'type': 'set-name', + 'name': payload['name'] + }) + elif payload['type'] == 'chat': + self.broadcast(client_id, { + 'type': 'chat', + 'message': payload['message'] + }) + else: + print("Unhandled!") + + def get_state_dto(self, client_id): + return { + 'yourId': client_id, + 'players': [ + self.clients[other_client_id].data + for other_client_id in self.clients + ] + } + + # message receiving and sending + + def put_incoming_message(self, client_id, payload): + self.incoming_messages.put({ + 'from': client_id, + 'payload': json.loads(payload) + }) + + def send_to(self, client_id_from, client_id_to, payload): + self.clients[client_id_to].sock.send(json.dumps({ + 'from': client_id_from, + 'payload': payload + })) + + def broadcast(self, client_id_from, payload): + with self.clients_lock: + for client_id_to in self.clients: + self.send_to(client_id_from, client_id_to, payload) + + # client management + + def _get_next_client_id(self): + with self.next_client_id_lock: + client_id = self.next_client_id + self.next_client_id += 1 + return client_id + + def add_client(self, sock): + client_id = self._get_next_client_id() + self.broadcast(client_id, {'type': 'join'}) + with self.clients_lock: + self.clients[client_id] = Client(sock, client_id) + self.send_to(None, client_id, { + 'type': 'init', + 'state': self.get_state_dto(client_id) + }) + return client_id + + def remove_client(self, client_id): + with self.clients_lock: + del self.clients[client_id] + self.broadcast(client_id, {'type': 'leave'}) + + # event thread stuff + + def start_event_thread(self): + event_thread = Thread(target=lambda: self._event_thread()) + event_thread.daemon = True + event_thread.start() + + def _event_thread(self): + while True: + msg = self.incoming_messages.get() + self.handle_message_from(msg['from'], msg['payload']) + +# Initialization + +state = GlebbyState() +state.start_event_thread() + app = Flask(__name__) sock = Sock(app) -@sock.route('/echo') +@sock.route('/glebby') def echo(sock): - print('New echo client') + client_id = state.add_client(sock) try: while True: data = sock.receive() - sock.send(data) + state.put_incoming_message(client_id, data) except simple_websocket.ConnectionClosed: - print("Client closed the connection") + state.remove_client(client_id)