-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.py
140 lines (106 loc) · 4.54 KB
/
client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/env python3
import socket
import threading
import logging
from tkinter import *
from tkinter import ttk, scrolledtext
from config import Settings
'''
Main process that start client connection to the server
and handle it's input messages
'''
class Client:
clientSocket: socket.socket = None # Client's Socket.
def __init__(self, root: Tk) -> None:
'''
Initializes the Client and creates its GUI.
'''
try:
logging.basicConfig(level=logging.NOTSET, format='[CLIENT - %(levelname)s] %(message)s') # Initialize Logging.
# Connects the Client to the Server.
self.clientSocket = socket.socket()
self.clientSocket.connect((Settings.SERVER_ADDRESS, Settings.SERVER_PORT))
# Create the GUI Window.
# Set it not resizable and the action on close button pressed.
self.root = root
self.root.title(Settings.SERVER_NAME)
# Create the Message Box.
self.mainWindow = ttk.Frame(self.root, padding=10)
self.mainWindow.grid(row=0, column=0, columnspan=2, sticky=(N, S, E, W))
# Create the Users Message Area.
self.messageArea = scrolledtext.ScrolledText(self.mainWindow, wrap='word', state='disabled')
self.messageArea.grid(row=0, column=0, columnspan=2, sticky=(N, S, E, W))
# Create the Message Entry.
self.inputArea = ttk.Entry(self.mainWindow, width=50)
self.inputArea.grid(row=1, column=0, sticky=(E, W))
self.inputArea.bind('<Return>', self.sendMessage)
# Create the Send Message.
self.sendButton = ttk.Button(self.mainWindow, text="Send", command=self.sendMessage)
self.sendButton.grid(row=1, column=1, sticky=(E, W))
self.root.resizable(False, False)
self.root.protocol("WM_DELETE_WINDOW", self.closeConnection)
# Starts the manageMessage thread.
threading.Thread(target=self.manageMessage, args=[self.clientSocket], daemon=True).start()
logging.info('Connected to chat')
except Exception as e:
logging.error(f'Error connecting to server socket: {e}', exc_info=Settings.EXCEPTIONS_INFO)
self.clientSocket.close()
root.destroy()
def manageMessage(self, connection: socket.socket):
'''
Retrieve messages from the server.
'''
# Message Management infinite loop.
while True:
try:
msg = connection.recv(Settings.BUFFER_SIZE)
if msg:
self.displayMessage(msg.decode(Settings.MESSAGE_ENCODING))
else:
connection.close()
break
except Exception as e:
logging.error(f'Error handling message from server: {e}', exc_info=Settings.EXCEPTIONS_INFO)
connection.close()
break
def displayMessage(self, msg: str):
'''
Display received messages to the client's GUI.
'''
# Add the message to the text area.
self.messageArea.configure(state='normal')
self.messageArea.insert(END, msg + '\n')
self.messageArea.configure(state='disabled')
self.messageArea.yview(END)
def sendMessage(self, event: None = None):
'''
Send message to the server.
'''
# Get the message entry and send it as an encoded message.
msg = self.inputArea.get()
if not msg:
return
try:
self.clientSocket.send(msg.encode(Settings.MESSAGE_ENCODING))
self.inputArea.delete(0, END)
except Exception as e:
logging.error(f'Error occured when sending message: {e}.', exc_info=Settings.EXCEPTIONS_INFO)
def closeConnection(self, event: None = None):
'''
Close client's connection to the server.
'''
try:
self.clientSocket.close()
except Exception as e:
logging.error(f'Error occured while closing socket: {e}.', exc_info=Settings.EXCEPTIONS_INFO)
self.root.quit()
@staticmethod
def startClientGUI():
'''
Starts the client's GUI.
'''
root = Tk()
Client(root)
root.mainloop()
if __name__ == "__main__":
Client.startClientGUI()