From d7bf0d9a818bbd96e6903fcbdb92e97129a98e10 Mon Sep 17 00:00:00 2001 From: myitinos Date: Tue, 23 Apr 2019 10:55:14 +0800 Subject: [PATCH] added client side script --- client/ChatConnection.py | 30 +++++++++++++ client/ChatInterface.py | 94 ++++++++++++++++++++++++++++++++++++++++ client/__main__.py | 20 +++++++++ 3 files changed, 144 insertions(+) create mode 100644 client/ChatConnection.py create mode 100644 client/ChatInterface.py create mode 100644 client/__main__.py diff --git a/client/ChatConnection.py b/client/ChatConnection.py new file mode 100644 index 0000000..f4e2da5 --- /dev/null +++ b/client/ChatConnection.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3.7 +import socket + + +class ChatConnection(object): + def __init__(self, host: str, port: int, buffSize=4096, encoding='utf8'): + self.soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.soc.connect((host, port)) + self.buffSize = buffSize + self.encoding = encoding + + def send(self, msg: str) -> None: + """ + Wrapper method of socket.send and encode the message + to set character encoding. + """ + self.soc.send(bytes(msg, self.encoding)) + + def recv(self) -> str: + """ + Wrapper method of socket.recv and encode the message + to set character encoding. + """ + return self.soc.recv(self.buffSize).decode(self.encoding) + + def close(self) -> None: + """ + Wrapper method to close the socket + """ + self.soc.close() diff --git a/client/ChatInterface.py b/client/ChatInterface.py new file mode 100644 index 0000000..ac3ac0c --- /dev/null +++ b/client/ChatInterface.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3.7 +import tkinter +import threading +from ChatConnection import ChatConnection + + +class ChatInterface(object): + def __init__(self, connection: ChatConnection): + # set connection to use + self.connection = connection + + # initialise tkinter window + self.window = tkinter.Tk() + self.window.title("Chatter") # window title + # set method to trigger when window is close + self.window.protocol("WM_DELETE_WINDOW", self.close) + # end of window initialisation + + # initialise message frame + self.messagesFrame = tkinter.Frame(self.window) + # # add scrollBar to see previously recovered messages + self.scrollBar = tkinter.Scrollbar(self.messagesFrame) + self.scrollBar.pack(side=tkinter.RIGHT, fill=tkinter.Y) + # # add messagesList to print recovered messages + self.messagesList = tkinter.Listbox( + self.messagesFrame, height=15, width=50, yscrollcommand=self.scrollBar.set) + self.messagesList.pack(side=tkinter.LEFT, fill=tkinter.BOTH) + self.messagesList.pack() + self.messagesFrame.pack() + # end of message frame initialisation + + # initialise input + self.input = tkinter.StringVar() + self.input.set("Type your messages here.") + # # initialise input frame + self.inputFrame = tkinter.Entry(self.window, textvariable=self.input) + self.inputFrame.bind("", self.send) + self.inputFrame.pack() + # # initialise send button + self.sendButton = tkinter.Button( + self.window, text="Send", command=self.send) + self.sendButton.pack() + # end of input initialisation + + def close(self, event=None) -> None: + """ + Set input to ':quit' and trigger send method + """ + self.input.set(":quit") + self.send() + + def send(self, event=None) -> None: + """ + Send message to connection + """ + msg = self.input.get() + # check if input is quit command + if msg != ':quit': + # clear the input bar + self.input.set('') + # output the client message to message list + self.messagesList.insert(tkinter.END, '[YOU] {}'.format(msg)) + # send the message to connection + self.connection.send(msg) + else: + # close the connection and window + self.connection.close() + self.window.quit() + + def listener(self) -> None: + """ + Listener method to keep receiving new message from + connection + """ + while True: + try: + # receive messages from connection + msg = self.connection.recv() + # add recevied message to message list + self.messagesList.insert(tkinter.END, msg[:-1]) + except OSError: + break + + def start(self) -> None: + """ + Start background listener and tkinter.mainloop + """ + # initialise background listener as daemon thread + backgroundListener = threading.Thread(target=self.listener) + backgroundListener.daemon = True + backgroundListener.start() + + # start tkinter main loop and open the GUI window + tkinter.mainloop() diff --git a/client/__main__.py b/client/__main__.py new file mode 100644 index 0000000..bf4a016 --- /dev/null +++ b/client/__main__.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3.7 +from ChatInterface import ChatInterface +from ChatConnection import ChatConnection + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("host", + metavar="HOST", + help='Host IP to connect to.', + type=str) + parser.add_argument("port", + metavar="PORT", + help='Host PORT to connect to.', + type=int) + args = parser.parse_args() + + ChatInterface(ChatConnection(args.host, args.port)).start()