mirror of
https://github.com/Xevion/tcp-chat.git
synced 2025-12-06 05:16:45 -06:00
98 lines
3.6 KiB
Python
98 lines
3.6 KiB
Python
import json
|
|
import logging
|
|
import socket
|
|
|
|
from PyQt5.QtCore import QThread, pyqtSignal
|
|
|
|
import constants
|
|
import helpers
|
|
|
|
|
|
class ReceiveWorker(QThread):
|
|
messages = pyqtSignal(dict)
|
|
client_list = pyqtSignal(list)
|
|
error = pyqtSignal()
|
|
sent_nick = pyqtSignal()
|
|
logs = pyqtSignal(dict)
|
|
data_stats = pyqtSignal(bool, int) # bool: True if sent stats change, False if received stats change
|
|
|
|
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 {
|
|
'nickname': data['nickname'],
|
|
'message': data['content'],
|
|
'color': data['color'],
|
|
'time': data['time'],
|
|
'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 send(self, data: bytes, **kwargs) -> None:
|
|
self.data_stats.emit(True, len(data))
|
|
self.client.send(data, **kwargs)
|
|
|
|
def run(self):
|
|
try:
|
|
while self.__isRunning:
|
|
try:
|
|
# Receive and parse the header
|
|
raw_header = self.client.recv(constants.HEADER_LENGTH)
|
|
raw_length = raw_header.decode('utf-8')
|
|
if not raw_length: continue
|
|
|
|
# Now receive the amount of data the header specified
|
|
raw_data = self.client.recv(int(raw_length))
|
|
raw = raw_data.decode('utf-8')
|
|
if not raw: continue
|
|
message = json.loads(raw)
|
|
|
|
self.data_stats.emit(False, len(raw_header) + len(raw_data))
|
|
|
|
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)
|
|
|
|
if message['type'] == constants.Types.REQUEST:
|
|
if message['request'] == constants.Requests.REQUEST_NICK:
|
|
self.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()
|