mirror of
https://github.com/Xevion/tcp-chat.git
synced 2026-01-31 06:26:11 -06:00
Improved formatting of users with colors, distinguishing of server messages, more message info
This commit is contained in:
+25
-11
@@ -17,9 +17,10 @@ HEADER_LENGTH = 10
|
|||||||
|
|
||||||
|
|
||||||
class ReceiveWorker(QThread):
|
class ReceiveWorker(QThread):
|
||||||
messages = pyqtSignal(str)
|
messages = pyqtSignal(str, str, str, int)
|
||||||
client_list = pyqtSignal(list)
|
client_list = pyqtSignal(list)
|
||||||
error = pyqtSignal()
|
error = pyqtSignal()
|
||||||
|
sent_nick = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, client: socket.socket, nickname: str, parent=None):
|
def __init__(self, client: socket.socket, nickname: str, parent=None):
|
||||||
QThread.__init__(self, parent)
|
QThread.__init__(self, parent)
|
||||||
@@ -29,9 +30,11 @@ class ReceiveWorker(QThread):
|
|||||||
def run(self):
|
def run(self):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
length = int(self.client.recv(HEADER_LENGTH).decode('utf-8'))
|
raw_length = self.client.recv(HEADER_LENGTH).decode('utf-8')
|
||||||
raw = self.client.recv(length).decode('utf-8')
|
if not raw_length:
|
||||||
if len(raw) == 0:
|
continue
|
||||||
|
raw = self.client.recv(int(raw_length)).decode('utf-8')
|
||||||
|
if not raw:
|
||||||
continue
|
continue
|
||||||
message = json.loads(raw)
|
message = json.loads(raw)
|
||||||
|
|
||||||
@@ -43,8 +46,9 @@ class ReceiveWorker(QThread):
|
|||||||
'nickname': self.nickname
|
'nickname': self.nickname
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
self.sent_nick.emit()
|
||||||
elif message['type'] == constants.Types.MESSAGE:
|
elif message['type'] == constants.Types.MESSAGE:
|
||||||
self.messages.emit(message['content'])
|
self.messages.emit(message['nickname'], message['content'], message['color'], message['time'])
|
||||||
elif message['type'] == constants.Types.USER_LIST:
|
elif message['type'] == constants.Types.USER_LIST:
|
||||||
self.client_list.emit(message['users'])
|
self.client_list.emit(message['users'])
|
||||||
except:
|
except:
|
||||||
@@ -61,9 +65,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
# Get Nickname
|
# Get Nickname
|
||||||
|
while True:
|
||||||
nicknameDialog = NicknameDialog(self)
|
nicknameDialog = NicknameDialog(self)
|
||||||
nicknameDialog.exec_()
|
nicknameDialog.exec_()
|
||||||
self.nickname = nicknameDialog.lineEdit.text()
|
self.nickname = nicknameDialog.lineEdit.text().strip()
|
||||||
|
if len(self.nickname) > 3:
|
||||||
|
break
|
||||||
|
|
||||||
# Connect to server
|
# Connect to server
|
||||||
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
@@ -78,10 +85,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.connectionsListTimer = QTimer()
|
self.connectionsListTimer = QTimer()
|
||||||
self.connectionsListTimer.timeout.connect(self.refreshConnectionsList)
|
self.connectionsListTimer.timeout.connect(self.refreshConnectionsList)
|
||||||
self.connectionsListTimer.start(1000 * 30)
|
self.connectionsListTimer.start(1000 * 30)
|
||||||
self.refreshConnectionsList()
|
self.receiveThread.sent_nick.connect(self.refreshConnectionsList)
|
||||||
|
|
||||||
|
self.messageBox.setPlaceholderText('Type your message here...')
|
||||||
self.messageBox.installEventFilter(self)
|
self.messageBox.installEventFilter(self)
|
||||||
|
|
||||||
|
self.messages = []
|
||||||
|
|
||||||
def eventFilter(self, obj, event):
|
def eventFilter(self, obj, event):
|
||||||
if event.type() == QEvent.KeyPress and obj is self.messageBox:
|
if event.type() == QEvent.KeyPress and obj is self.messageBox:
|
||||||
if event.key() == Qt.Key_Return and self.messageBox.hasFocus():
|
if event.key() == Qt.Key_Return and self.messageBox.hasFocus():
|
||||||
@@ -93,14 +103,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.messageBox.setTextCursor(cursor)
|
self.messageBox.setTextCursor(cursor)
|
||||||
return super().eventFilter(obj, event)
|
return super().eventFilter(obj, event)
|
||||||
|
|
||||||
def addMessage(self, message: str) -> None:
|
def addMessage(self, nickname: str, message: str, color: str, time: int) -> None:
|
||||||
self.messageHistory.append(message)
|
self.messages.append([nickname, message, color, time])
|
||||||
|
self.messageHistory.append(f'<<span style="color: {color}">{nickname}</span>> {message}')
|
||||||
|
|
||||||
def sendMessage(self, message: str) -> None:
|
def sendMessage(self, message: str) -> None:
|
||||||
|
message = message.strip()
|
||||||
|
if len(message) > 0:
|
||||||
self.client.send(helpers.prepare_json(
|
self.client.send(helpers.prepare_json(
|
||||||
{
|
{
|
||||||
'type': constants.Types.MESSAGE,
|
'type': constants.Types.MESSAGE,
|
||||||
'content': message.strip()
|
'content': message
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -114,4 +127,5 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
def updateConnectionsList(self, users):
|
def updateConnectionsList(self, users):
|
||||||
self.connectionsList.clear()
|
self.connectionsList.clear()
|
||||||
self.connectionsList.addItems(users)
|
|
||||||
|
self.connectionsList.addItems([user['nickname'] for user in users])
|
||||||
|
|||||||
@@ -3,8 +3,66 @@ class Requests:
|
|||||||
REFRESH_CONNECTIONS_LIST = 'REFRESH_CLIENT_LIST'
|
REFRESH_CONNECTIONS_LIST = 'REFRESH_CLIENT_LIST'
|
||||||
GET_HISTORY = 'GET_HISTORY'
|
GET_HISTORY = 'GET_HISTORY'
|
||||||
|
|
||||||
|
|
||||||
class Types:
|
class Types:
|
||||||
|
SERVER_MESSAGE = 'SERVER_MESSAGE'
|
||||||
REQUEST = 'REQUEST'
|
REQUEST = 'REQUEST'
|
||||||
NICKNAME = 'NICKNAME'
|
NICKNAME = 'NICKNAME'
|
||||||
USER_LIST = 'USER_LIST'
|
USER_LIST = 'USER_LIST'
|
||||||
MESSAGE = 'MESSAGE'
|
MESSAGE = 'MESSAGE'
|
||||||
|
|
||||||
|
|
||||||
|
class Colors:
|
||||||
|
AQUA = "#00ffff"
|
||||||
|
AZURE = "#f0ffff"
|
||||||
|
BEIGE = "#f5f5dc"
|
||||||
|
BLACK = "#000000"
|
||||||
|
BLUE = "#0000ff"
|
||||||
|
BROWN = "#a52a2a"
|
||||||
|
CYAN = "#00ffff"
|
||||||
|
DARKBLUE = "#00008b"
|
||||||
|
DARKCYAN = "#008b8b"
|
||||||
|
DARKGREY = "#a9a9a9"
|
||||||
|
DARKGREEN = "#006400"
|
||||||
|
DARKKHAKI = "#bdb76b"
|
||||||
|
DARKMAGENTA = "#8b008b"
|
||||||
|
DARKOLIVEGREEN = "#556b2f"
|
||||||
|
DARKORANGE = "#ff8c00"
|
||||||
|
DARKORCHID = "#9932cc"
|
||||||
|
DARKRED = "#8b0000"
|
||||||
|
DARKSALMON = "#e9967a"
|
||||||
|
DARKVIOLET = "#9400d3"
|
||||||
|
FUCHSIA = "#ff00ff"
|
||||||
|
GOLD = "#ffd700"
|
||||||
|
GREEN = "#008000"
|
||||||
|
INDIGO = "#4b0082"
|
||||||
|
KHAKI = "#f0e68c"
|
||||||
|
LIGHTBLUE = "#add8e6"
|
||||||
|
LIGHTCYAN = "#e0ffff"
|
||||||
|
LIGHTGREEN = "#90ee90"
|
||||||
|
LIGHTGREY = "#d3d3d3"
|
||||||
|
LIGHTPINK = "#ffb6c1"
|
||||||
|
LIGHTYELLOW = "#ffffe0"
|
||||||
|
LIME = "#00ff00"
|
||||||
|
MAGENTA = "#ff00ff"
|
||||||
|
MAROON = "#800000"
|
||||||
|
NAVY = "#000080"
|
||||||
|
OLIVE = "#808000"
|
||||||
|
ORANGE = "#ffa500"
|
||||||
|
PINK = "#ffc0cb"
|
||||||
|
PURPLE = "#800080"
|
||||||
|
VIOLET = "#800080"
|
||||||
|
RED = "#ff0000"
|
||||||
|
SILVER = "#c0c0c0"
|
||||||
|
WHITE = "#ffffff"
|
||||||
|
YELLOW = "#ffff00"
|
||||||
|
|
||||||
|
ALL_NAMES = ['Aqua', 'Azure', 'Beige', 'Black', 'Blue', 'Brown', 'Cyan', 'Dark Blue', 'Dark Cyan', 'Dark Grey',
|
||||||
|
'Dark Green', 'Dark Khaki', 'Dark Magenta', 'Dark Olive Green', 'Dark Orange', ' Dark Orchid', 'Dark Red', 'Dark Salmon',
|
||||||
|
'Dark Violet', 'Fuchsia', 'Gold', 'Green', 'Indigo', 'Khaki', 'Light Blue', 'Light Cyan',
|
||||||
|
'Light Green', 'Light Grey', 'Light Pink', 'Light Yellow', 'Lime', 'Magenta', 'Maroon', 'Navy',
|
||||||
|
'Olive', 'Orange', 'Pink', 'Purple', 'Violet', 'Red', 'Silver', 'White', 'Yellow']
|
||||||
|
ALL = [AQUA, AZURE, BEIGE, BLACK, BLUE, BROWN, CYAN, DARKBLUE, DARKCYAN, DARKGREY, DARKGREEN, DARKKHAKI,
|
||||||
|
DARKMAGENTA, DARKOLIVEGREEN, DARKORANGE, DARKORCHID, DARKRED, DARKSALMON, DARKVIOLET, FUCHSIA, GOLD, GREEN,
|
||||||
|
INDIGO, KHAKI, LIGHTBLUE, LIGHTCYAN, LIGHTGREEN, LIGHTGREY, LIGHTPINK, LIGHTYELLOW, LIME, MAGENTA, MAROON,
|
||||||
|
NAVY, OLIVE, ORANGE, PINK, PURPLE, VIOLET, RED, SILVER, WHITE, YELLOW, ]
|
||||||
|
|||||||
+56
-19
@@ -1,18 +1,19 @@
|
|||||||
import json
|
import json
|
||||||
|
import random
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import uuid
|
import uuid
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
import constants
|
import constants
|
||||||
import helpers
|
import helpers
|
||||||
from config import config
|
|
||||||
|
|
||||||
# Connection Data
|
# Connection Data
|
||||||
host = '127.0.0.1'
|
host = '127.0.0.1'
|
||||||
port = 55555
|
port = 55555
|
||||||
HEADER_LENGTH = int(config['DEFAULT']['HeaderLength'])
|
HEADER_LENGTH = 10
|
||||||
|
|
||||||
# Starting Server
|
# Starting Server
|
||||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
@@ -23,15 +24,9 @@ server.listen()
|
|||||||
clients = {}
|
clients = {}
|
||||||
|
|
||||||
|
|
||||||
# Sending Messages To All Connected Clients
|
def broadcast_data(data):
|
||||||
def broadcast(message):
|
|
||||||
print(f'"{message}"')
|
|
||||||
encoded = helpers.prepare_json({
|
|
||||||
'type': constants.Types.MESSAGE,
|
|
||||||
'content': message
|
|
||||||
})
|
|
||||||
for client in clients.values():
|
for client in clients.values():
|
||||||
client['client'].send(encoded)
|
client['client'].send(data)
|
||||||
|
|
||||||
|
|
||||||
# Handling Messages From Clients
|
# Handling Messages From Clients
|
||||||
@@ -51,29 +46,68 @@ def handle(client_id):
|
|||||||
{
|
{
|
||||||
'type': constants.Types.USER_LIST,
|
'type': constants.Types.USER_LIST,
|
||||||
'users': [
|
'users': [
|
||||||
clients[other]['nickname'] for other in clients.keys() if other != client_id
|
{
|
||||||
|
'nickname': other['nickname'],
|
||||||
|
'color': other['color']
|
||||||
|
} for other in clients.values()
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
elif message['type'] == constants.Types.NICKNAME:
|
elif message['type'] == constants.Types.NICKNAME:
|
||||||
|
|
||||||
nickname = message['nickname']
|
nickname = message['nickname']
|
||||||
if not clients[client_id]['has_nickname']:
|
if not clients[client_id]['has_nickname']:
|
||||||
print("Nickname is {}".format(nickname))
|
print("Nickname is {}".format(nickname))
|
||||||
broadcast("{} joined!".format(nickname))
|
broadcast_data(helpers.prepare_json(
|
||||||
|
{
|
||||||
|
'type': constants.Types.MESSAGE,
|
||||||
|
'nickname': 'Server',
|
||||||
|
'content': f'{nickname} joined!',
|
||||||
|
'color': constants.Colors.PINK,
|
||||||
|
'time': int(time.time())
|
||||||
|
}
|
||||||
|
))
|
||||||
clients[client_id]['has_nickname'] = True
|
clients[client_id]['has_nickname'] = True
|
||||||
else:
|
else:
|
||||||
print(f'{clients[client_id]["nickname"]} changed their name to {nickname}')
|
print(f'{clients[client_id]["nickname"]} changed their name to {nickname}')
|
||||||
clients[client_id]['nickname'] = nickname
|
clients[client_id]['nickname'] = nickname
|
||||||
|
|
||||||
elif message['type'] == constants.Types.MESSAGE:
|
elif message['type'] == constants.Types.MESSAGE:
|
||||||
broadcast(f'<{nickname}>: {message["content"]}')
|
if message['content'] == '/reroll':
|
||||||
|
color = random.choice(constants.Colors.ALL)
|
||||||
|
colorname = constants.Colors.ALL_NAMES[constants.Colors.ALL.index(color)]
|
||||||
|
clients[client_id]['color'] = color
|
||||||
|
broadcast_data(helpers.prepare_json(
|
||||||
|
{
|
||||||
|
'type': constants.Types.MESSAGE,
|
||||||
|
'nickname': 'Server',
|
||||||
|
'content': f'Changed your color to {colorname} ({color})',
|
||||||
|
'color': constants.Colors.PINK,
|
||||||
|
'time': int(time.time())
|
||||||
|
}
|
||||||
|
))
|
||||||
|
broadcast_data(helpers.prepare_json(
|
||||||
|
{
|
||||||
|
'type': constants.Types.MESSAGE,
|
||||||
|
'nickname': nickname,
|
||||||
|
'content': message["content"],
|
||||||
|
'color': clients[client_id]['color'],
|
||||||
|
'time': int(time.time())
|
||||||
|
}
|
||||||
|
))
|
||||||
except:
|
except:
|
||||||
# Removing And Closing Clients
|
traceback.print_exc()
|
||||||
|
print(f'Closing Client {clients[client_id]["nickname"]}')
|
||||||
client.close()
|
client.close()
|
||||||
del clients[client_id]
|
del clients[client_id]
|
||||||
broadcast('{} left!'.format(nickname))
|
broadcast_data(helpers.prepare_json(
|
||||||
|
{
|
||||||
|
'type': constants.Types.MESSAGE,
|
||||||
|
'nickname': 'Server',
|
||||||
|
'content': f'{nickname} left!',
|
||||||
|
'color': constants.Colors.PINK,
|
||||||
|
'time': int(time.time())
|
||||||
|
}
|
||||||
|
))
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
@@ -95,14 +129,17 @@ def receive():
|
|||||||
|
|
||||||
clients[client_id] = {
|
clients[client_id] = {
|
||||||
'client': client,
|
'client': client,
|
||||||
|
'id': client_id,
|
||||||
'nickname': client_id[:10],
|
'nickname': client_id[:10],
|
||||||
'first_seen': int(time.time()),
|
'first_seen': int(time.time()),
|
||||||
'has_nickname': False
|
'has_nickname': False,
|
||||||
|
'color': random.choice(constants.Colors.ALL)
|
||||||
}
|
}
|
||||||
|
pprint(clients[client_id])
|
||||||
|
|
||||||
client.send(helpers.prepare_json(
|
client.send(helpers.prepare_json(
|
||||||
{
|
{
|
||||||
'type': constants.Types.MESSAGE,
|
'type': constants.Types.SERVER_MESSAGE,
|
||||||
'content': 'Connected to server!'
|
'content': 'Connected to server!'
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|||||||
Reference in New Issue
Block a user