mirror of
https://github.com/Xevion/tcp-chat.git
synced 2025-12-06 15:16:43 -06:00
commit rest of old client/server fixes
This commit is contained in:
@@ -100,7 +100,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||
self.client.send(helpers.prepare_json(
|
||||
{
|
||||
'type': constants.Types.MESSAGE,
|
||||
'content': message
|
||||
'content': message.strip()
|
||||
}
|
||||
))
|
||||
|
||||
|
||||
10
constants.py
Normal file
10
constants.py
Normal file
@@ -0,0 +1,10 @@
|
||||
class Requests:
|
||||
REQUEST_NICK = 'REQUEST_NICK'
|
||||
REFRESH_CONNECTIONS_LIST = 'REFRESH_CLIENT_LIST'
|
||||
GET_HISTORY = 'GET_HISTORY'
|
||||
|
||||
class Types:
|
||||
REQUEST = 'REQUEST'
|
||||
NICKNAME = 'NICKNAME'
|
||||
USER_LIST = 'USER_LIST'
|
||||
MESSAGE = 'MESSAGE'
|
||||
14
helpers.py
14
helpers.py
@@ -1,7 +1,19 @@
|
||||
import json
|
||||
|
||||
HEADER_LENGTH = 10
|
||||
|
||||
|
||||
def prepare(message: str, encoding='ascii') -> bytes:
|
||||
def prepare(message: str, encoding='utf-8') -> bytes:
|
||||
"""Prepares a message for sending through a socket by adding a proper header and encoding it."""
|
||||
header = f'{len(message):<{HEADER_LENGTH}}'
|
||||
return (header + message).encode(encoding)
|
||||
|
||||
|
||||
def prepare_json(object) -> bytes:
|
||||
"""
|
||||
Prepares a object for sending as encoded JSON with a header.
|
||||
|
||||
:param object: A JSON-encodable object
|
||||
:return: Encoded JSON
|
||||
"""
|
||||
return prepare(json.dumps(object))
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from client.gui import MainWindow
|
||||
|
||||
app = QApplication([])
|
||||
app.setApplicationName("TCPChat Client")
|
||||
m = MainWindow()
|
||||
|
||||
app.exec_()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import socket
|
||||
import threading
|
||||
|
||||
import constants
|
||||
import helpers
|
||||
from config import config
|
||||
|
||||
@@ -15,9 +16,9 @@ client.connect(('127.0.0.1', 55555))
|
||||
def receive():
|
||||
while True:
|
||||
try:
|
||||
length = int(client.recv(HEADER_LENGTH).decode('ascii'))
|
||||
message = client.recv(length).decode('ascii')
|
||||
if message == 'NICK':
|
||||
length = int(client.recv(HEADER_LENGTH).decode('utf-8'))
|
||||
message = client.recv(length).decode('utf-8')
|
||||
if message == constants.Requests.REQUEST_NICK:
|
||||
client.send(helpers.prepare(nickname))
|
||||
else:
|
||||
print(message)
|
||||
@@ -30,7 +31,7 @@ def receive():
|
||||
# Sending Messages To Server
|
||||
def write():
|
||||
while True:
|
||||
message = '{}: {}'.format(nickname, input(''))
|
||||
message = input('> ')
|
||||
client.send(helpers.prepare(message))
|
||||
|
||||
|
||||
|
||||
93
oserver.py
93
oserver.py
@@ -1,6 +1,11 @@
|
||||
import json
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
import uuid
|
||||
|
||||
import constants
|
||||
import helpers
|
||||
from config import config
|
||||
|
||||
@@ -15,35 +20,60 @@ server.bind((host, port))
|
||||
server.listen()
|
||||
|
||||
# Lists For Clients and Their Nicknames
|
||||
clients = []
|
||||
nicknames = []
|
||||
clients = {}
|
||||
|
||||
|
||||
# Sending Messages To All Connected Clients
|
||||
def broadcast(message):
|
||||
print(f'Broadcasting: "{message}"')
|
||||
encoded = helpers.prepare(message)
|
||||
for client in clients:
|
||||
client.send(encoded)
|
||||
print(f'"{message}"')
|
||||
encoded = helpers.prepare_json({
|
||||
'type': constants.Types.MESSAGE,
|
||||
'content': message
|
||||
})
|
||||
for client in clients.values():
|
||||
client['client'].send(encoded)
|
||||
|
||||
|
||||
# Handling Messages From Clients
|
||||
def handle(client):
|
||||
def handle(client_id):
|
||||
client = clients[client_id]['client']
|
||||
nickname = clients[client_id]['nickname']
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Broadcasting Messages
|
||||
length = int(client.recv(HEADER_LENGTH).decode('ascii'))
|
||||
message = client.recv(length).decode('ascii')
|
||||
broadcast(message)
|
||||
length = int(client.recv(HEADER_LENGTH).decode('utf-8'))
|
||||
message = json.loads(client.recv(length).decode('utf-8'))
|
||||
|
||||
if message['type'] == constants.Types.REQUEST:
|
||||
if message['request'] == constants.Requests.REFRESH_CONNECTIONS_LIST:
|
||||
client.send(helpers.prepare_json(
|
||||
{
|
||||
'type': constants.Types.USER_LIST,
|
||||
'users': [
|
||||
clients[other]['nickname'] for other in clients.keys() if other != client_id
|
||||
]
|
||||
}
|
||||
))
|
||||
elif message['type'] == constants.Types.NICKNAME:
|
||||
|
||||
nickname = message['nickname']
|
||||
if not clients[client_id]['has_nickname']:
|
||||
print("Nickname is {}".format(nickname))
|
||||
broadcast("{} joined!".format(nickname))
|
||||
clients[client_id]['has_nickname'] = True
|
||||
else:
|
||||
print(f'{clients[client_id]["nickname"]} changed their name to {nickname}')
|
||||
clients[client_id]['nickname'] = nickname
|
||||
|
||||
elif message['type'] == constants.Types.MESSAGE:
|
||||
broadcast(f'<{nickname}>: {message["content"]}')
|
||||
|
||||
except:
|
||||
# Removing And Closing Clients
|
||||
index = clients.index(client)
|
||||
clients.remove(client)
|
||||
client.close()
|
||||
|
||||
nickname = nicknames[index]
|
||||
del clients[client_id]
|
||||
broadcast('{} left!'.format(nickname))
|
||||
nicknames.remove(nickname)
|
||||
break
|
||||
|
||||
|
||||
@@ -52,22 +82,33 @@ def receive():
|
||||
while True:
|
||||
# Accept Connection
|
||||
client, address = server.accept()
|
||||
print("Connected with {}".format(str(address)))
|
||||
print("New Client from {}".format(str(address)))
|
||||
|
||||
# Request And Store Nickname
|
||||
client.send(helpers.prepare('NICK'))
|
||||
length = int(client.recv(HEADER_LENGTH).decode('ascii'))
|
||||
nickname = client.recv(length).decode('ascii')
|
||||
nicknames.append(nickname)
|
||||
clients.append(client)
|
||||
client_id = str(uuid.uuid4())
|
||||
client.send(helpers.prepare_json(
|
||||
{
|
||||
'type': constants.Types.REQUEST,
|
||||
'request': constants.Requests.REQUEST_NICK
|
||||
}
|
||||
))
|
||||
|
||||
# Print And Broadcast Nickname
|
||||
print("Nickname is {}".format(nickname))
|
||||
broadcast("{} joined!".format(nickname))
|
||||
client.send(helpers.prepare('Connected to server!'))
|
||||
clients[client_id] = {
|
||||
'client': client,
|
||||
'nickname': client_id[:10],
|
||||
'first_seen': int(time.time()),
|
||||
'has_nickname': False
|
||||
}
|
||||
|
||||
client.send(helpers.prepare_json(
|
||||
{
|
||||
'type': constants.Types.MESSAGE,
|
||||
'content': 'Connected to server!'
|
||||
}
|
||||
))
|
||||
|
||||
# Start Handling Thread For Client
|
||||
thread = threading.Thread(target=handle, args=(client,))
|
||||
thread = threading.Thread(target=handle, args=(client_id,))
|
||||
thread.start()
|
||||
|
||||
|
||||
|
||||
120
server/MainWindow.ui
Normal file
120
server/MainWindow.ui
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>651</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Connections</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QTextEdit" name="messageBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QTextBrowser" name="messageHistory">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>5</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QListWidget" name="connectionsList">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Chat History</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionConnect_to"/>
|
||||
<addaction name="actionSave_chat_to"/>
|
||||
<addaction name="actionQuit"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionConnect_to">
|
||||
<property name="text">
|
||||
<string>Connect to...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_chat_to">
|
||||
<property name="text">
|
||||
<string>Export chat...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionQuit">
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Reference in New Issue
Block a user