mirror of
https://github.com/Xevion/tcp-chat.git
synced 2025-12-07 09:16:41 -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(
|
self.client.send(helpers.prepare_json(
|
||||||
{
|
{
|
||||||
'type': constants.Types.MESSAGE,
|
'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
|
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."""
|
"""Prepares a message for sending through a socket by adding a proper header and encoding it."""
|
||||||
header = f'{len(message):<{HEADER_LENGTH}}'
|
header = f'{len(message):<{HEADER_LENGTH}}'
|
||||||
return (header + message).encode(encoding)
|
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 socket
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
import constants
|
||||||
import helpers
|
import helpers
|
||||||
from config import config
|
from config import config
|
||||||
|
|
||||||
@@ -15,9 +16,9 @@ client.connect(('127.0.0.1', 55555))
|
|||||||
def receive():
|
def receive():
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
length = int(client.recv(HEADER_LENGTH).decode('ascii'))
|
length = int(client.recv(HEADER_LENGTH).decode('utf-8'))
|
||||||
message = client.recv(length).decode('ascii')
|
message = client.recv(length).decode('utf-8')
|
||||||
if message == 'NICK':
|
if message == constants.Requests.REQUEST_NICK:
|
||||||
client.send(helpers.prepare(nickname))
|
client.send(helpers.prepare(nickname))
|
||||||
else:
|
else:
|
||||||
print(message)
|
print(message)
|
||||||
@@ -30,7 +31,7 @@ def receive():
|
|||||||
# Sending Messages To Server
|
# Sending Messages To Server
|
||||||
def write():
|
def write():
|
||||||
while True:
|
while True:
|
||||||
message = '{}: {}'.format(nickname, input(''))
|
message = input('> ')
|
||||||
client.send(helpers.prepare(message))
|
client.send(helpers.prepare(message))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
93
oserver.py
93
oserver.py
@@ -1,6 +1,11 @@
|
|||||||
|
import json
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import constants
|
||||||
import helpers
|
import helpers
|
||||||
from config import config
|
from config import config
|
||||||
|
|
||||||
@@ -15,35 +20,60 @@ server.bind((host, port))
|
|||||||
server.listen()
|
server.listen()
|
||||||
|
|
||||||
# Lists For Clients and Their Nicknames
|
# Lists For Clients and Their Nicknames
|
||||||
clients = []
|
clients = {}
|
||||||
nicknames = []
|
|
||||||
|
|
||||||
|
|
||||||
# Sending Messages To All Connected Clients
|
# Sending Messages To All Connected Clients
|
||||||
def broadcast(message):
|
def broadcast(message):
|
||||||
print(f'Broadcasting: "{message}"')
|
print(f'"{message}"')
|
||||||
encoded = helpers.prepare(message)
|
encoded = helpers.prepare_json({
|
||||||
for client in clients:
|
'type': constants.Types.MESSAGE,
|
||||||
client.send(encoded)
|
'content': message
|
||||||
|
})
|
||||||
|
for client in clients.values():
|
||||||
|
client['client'].send(encoded)
|
||||||
|
|
||||||
|
|
||||||
# Handling Messages From Clients
|
# Handling Messages From Clients
|
||||||
def handle(client):
|
def handle(client_id):
|
||||||
|
client = clients[client_id]['client']
|
||||||
|
nickname = clients[client_id]['nickname']
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
# Broadcasting Messages
|
# Broadcasting Messages
|
||||||
length = int(client.recv(HEADER_LENGTH).decode('ascii'))
|
length = int(client.recv(HEADER_LENGTH).decode('utf-8'))
|
||||||
message = client.recv(length).decode('ascii')
|
message = json.loads(client.recv(length).decode('utf-8'))
|
||||||
broadcast(message)
|
|
||||||
|
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:
|
except:
|
||||||
# Removing And Closing Clients
|
# Removing And Closing Clients
|
||||||
index = clients.index(client)
|
|
||||||
clients.remove(client)
|
|
||||||
client.close()
|
client.close()
|
||||||
|
del clients[client_id]
|
||||||
nickname = nicknames[index]
|
|
||||||
broadcast('{} left!'.format(nickname))
|
broadcast('{} left!'.format(nickname))
|
||||||
nicknames.remove(nickname)
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
@@ -52,22 +82,33 @@ def receive():
|
|||||||
while True:
|
while True:
|
||||||
# Accept Connection
|
# Accept Connection
|
||||||
client, address = server.accept()
|
client, address = server.accept()
|
||||||
print("Connected with {}".format(str(address)))
|
print("New Client from {}".format(str(address)))
|
||||||
|
|
||||||
# Request And Store Nickname
|
# Request And Store Nickname
|
||||||
client.send(helpers.prepare('NICK'))
|
client_id = str(uuid.uuid4())
|
||||||
length = int(client.recv(HEADER_LENGTH).decode('ascii'))
|
client.send(helpers.prepare_json(
|
||||||
nickname = client.recv(length).decode('ascii')
|
{
|
||||||
nicknames.append(nickname)
|
'type': constants.Types.REQUEST,
|
||||||
clients.append(client)
|
'request': constants.Requests.REQUEST_NICK
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
# Print And Broadcast Nickname
|
clients[client_id] = {
|
||||||
print("Nickname is {}".format(nickname))
|
'client': client,
|
||||||
broadcast("{} joined!".format(nickname))
|
'nickname': client_id[:10],
|
||||||
client.send(helpers.prepare('Connected to server!'))
|
'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
|
# Start Handling Thread For Client
|
||||||
thread = threading.Thread(target=handle, args=(client,))
|
thread = threading.Thread(target=handle, args=(client_id,))
|
||||||
thread.start()
|
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