diff --git a/client/gui.py b/client/gui.py
index 1ee4cc5..bff2966 100644
--- a/client/gui.py
+++ b/client/gui.py
@@ -1,4 +1,5 @@
import json
+import logging
import socket
import traceback
@@ -13,6 +14,10 @@ from client.dialog import NicknameDialog
IP = '127.0.0.1'
PORT = 55555
+logging.basicConfig(level=logging.DEBUG,
+ format='[%(asctime)s] [%(levelname)s] [%(threadName)s] %(message)s')
+logger = logging.getLogger('gui')
+
HEADER_LENGTH = 10
@@ -21,11 +26,16 @@ class ReceiveWorker(QThread):
client_list = pyqtSignal(list)
error = pyqtSignal()
sent_nick = pyqtSignal()
+ logs = pyqtSignal(dict)
def __init__(self, client: socket.socket, nickname: str, parent=None):
QThread.__init__(self, parent)
self.client = client
self.nickname = nickname
+ self.__isRunning = True
+
+ def stop(self) -> None:
+ self.__isRunning = False
def __extract_message(self, data) -> dict:
return {
@@ -36,39 +46,58 @@ class ReceiveWorker(QThread):
'id': data['id']
}
+ def log(self, message: str, level: int = logging.INFO, error: Exception = None):
+ """Send a log message out from this QThread to the MainThread"""
+ self.logs.emit(
+ {
+ 'message': message,
+ 'level': level,
+ 'error': error
+ }
+ )
+
def run(self):
- while True:
- try:
- raw_length = self.client.recv(HEADER_LENGTH).decode('utf-8')
- if not raw_length:
- continue
- raw = self.client.recv(int(raw_length)).decode('utf-8')
- if not raw:
- continue
- message = json.loads(raw)
+ try:
+ while self.__isRunning:
+ try:
+ raw_length = self.client.recv(HEADER_LENGTH).decode('utf-8')
+ if not raw_length:
+ continue
+ raw = self.client.recv(int(raw_length)).decode('utf-8')
+ if not raw:
+ continue
+ message = json.loads(raw)
- if message['type'] == constants.Types.REQUEST:
- if message['request'] == constants.Requests.REQUEST_NICK:
- self.client.send(helpers.prepare_json(
- {
- 'type': constants.Types.NICKNAME,
- 'nickname': self.nickname
- }
- ))
- self.sent_nick.emit()
- elif message['type'] == constants.Types.MESSAGE:
- self.messages.emit(self.__extract_message(message))
- elif message['type'] == constants.Types.USER_LIST:
- self.client_list.emit(message['users'])
- elif message['type'] == constants.Types.MESSAGE_HISTORY:
- for submessage in message['messages']:
- self.messages.emit(self.__extract_message(submessage))
+ if message['type'] == constants.Types.REQUEST:
+ self.log(f'Data[{int(raw_length)}] received, {message["type"]}/{message["request"]}.', level=logging.DEBUG)
+ else:
+ self.log(f'Data[{int(raw_length)}] received, {message["type"]}.', level=logging.DEBUG)
- except Exception as e:
- traceback.print_exc()
- self.error.emit()
- self.client.close()
- break
+
+ if message['type'] == constants.Types.REQUEST:
+ if message['request'] == constants.Requests.REQUEST_NICK:
+ self.client.send(helpers.prepare_json(
+ {
+ 'type': constants.Types.NICKNAME,
+ 'nickname': self.nickname
+ }
+ ))
+ self.sent_nick.emit()
+ elif message['type'] == constants.Types.MESSAGE:
+ self.messages.emit(self.__extract_message(message))
+ elif message['type'] == constants.Types.USER_LIST:
+ self.client_list.emit(message['users'])
+ elif message['type'] == constants.Types.MESSAGE_HISTORY:
+ for submessage in message['messages']:
+ self.messages.emit(self.__extract_message(submessage))
+
+ except Exception as e:
+ self.log(str(e), level=logging.CRITICAL, error=e)
+ self.error.emit()
+ break
+ finally:
+ self.log('Closing socket.', level=logging.INFO)
+ self.client.close()
class MainWindow(QMainWindow, Ui_MainWindow):
@@ -83,7 +112,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.nicknameDialog = NicknameDialog(self)
self.nicknameDialog.exec_()
self.nickname = self.nicknameDialog.lineEdit.text().strip()
- if len(self.nickname) >= 3 or self.closed:
+ if len(self.nickname) >= 3:
+ self.closed = True
+ break
+ elif self.closed:
break
# Connect to server
@@ -94,6 +126,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.receiveThread = ReceiveWorker(self.client, self.nickname)
self.receiveThread.messages.connect(self.addMessage)
self.receiveThread.client_list.connect(self.update_connections)
+ self.receiveThread.logs.connect(self.log)
self.receiveThread.start()
self.connectionsListTimer = QTimer()
@@ -106,14 +139,23 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.messages = []
+ def log(self, log_data: dict) -> None:
+ logger.log(level=log_data['level'], msg=log_data['message'], exc_info=log_data['error'])
+
def _ready(self):
+ logger.debug('Nickname sent. Ready to communicate with server further...')
self.refresh_connections()
self.get_message_history()
def closeEvent(self, event):
- if self.nicknameDialog:
+ if self.nicknameDialog and not self.closed:
+ logger.debug('Closing nickname dialog before main window')
self.closed = True
self.nicknameDialog.close()
+ else:
+ self.receiveThread.stop()
+ self.connectionsListTimer.stop()
+
event.accept() # let the window close
def eventFilter(self, obj, event) -> bool:
@@ -130,11 +172,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def addMessage(self, message: dict) -> None:
self.messages.append(message)
- self.messageHistory.append(f'<{message["nickname"]}> {message["message"]}')
+ self.messageHistory.append(
+ f'<{message["nickname"]}> {message["message"]}')
def sendMessage(self, message: str) -> None:
message = message.strip()
if len(message) > 0:
+ logger.info(f'Sending message of length {len(message)}')
self.client.send(helpers.prepare_json(
{
'type': constants.Types.MESSAGE,
@@ -143,6 +187,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
))
def refresh_connections(self) -> None:
+ logger.info('Requesting connections list')
self.client.send(helpers.prepare_json(
{
'type': constants.Types.REQUEST,
@@ -151,6 +196,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
))
def get_message_history(self) -> None:
+ logger.info('Requesting message history')
self.client.send(helpers.prepare_json(
{
'type': constants.Types.REQUEST,