Question: The following are my files for a python chat server project Main.py ---------------------------------------------------------- import tkinter as tk from tkinter import messagebox import ChatClient as client
The following are my files for a python chat server project
Main.py
----------------------------------------------------------
import tkinter as tk from tkinter import messagebox import ChatClient as client import BaseDialog as dialog import BaseEntry as entry import threading class SocketThreadedTask(threading.Thread): def __init__(self, socket, callback): threading.Thread.__init__(self) self.socket = socket self.callback = callback def run(self): while True: try: message = self.socket.receive() if message == '/quit': self.callback(' > You have been disconnected from the server. ') self.socket.disconnect() break else: self.callback(message) except OSError: break class ChatDialog(dialog.BaseDialog): def body(self, master): tk.Label(master, text="Enter host:").grid(row=0, sticky="w") tk.Label(master, text="Enter port:").grid(row=1, sticky="w") self.hostEntryField = tk.Entry(master) self.portEntryField = tk.Entry(master) self.hostEntryField.grid(row=0, column=1) self.portEntryField.grid(row=1, column=1) return self.hostEntryField def validate(self): host = str(self.hostEntryField.get()) try: port = int(self.portEntryField.get()) if(port >= 0 and port < 65536): self.result = (host, port) return True else: tk.messagebox.showwarning("Error", "The port number has to be between 0 and 65535. Both values are inclusive.") return False except ValueError: tk.messagebox.showwarning("Error", "The port number has to be an integer.") return False class ChatWindow(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.initUI(parent) def initUI(self, parent): self.messageTextArea = tk.Text(parent, bg="white", state=tk.DISABLED, wrap=tk.WORD) self.messageTextArea.grid(row=0, column=0, columnspan=2, sticky="nsew") self.messageScrollbar = tk.Scrollbar(parent, orient=tk.VERTICAL, command=self.messageTextArea.yview) self.messageScrollbar.grid(row=0, column=3, sticky="ns") self.messageTextArea['yscrollcommand'] = self.messageScrollbar.set self.usersListBox = tk.Listbox(parent, bg="white") self.usersListBox.grid(row=0, column=4, padx=5, sticky="nsew") self.entryField = entry.BaseEntry(parent, placeholder="Enter message.", width=80) self.entryField.grid(row=1, column=0, padx=5, pady=10, sticky="we") self.send_message_button = tk.Button(parent, text="Send", width=10, bg="#CACACA", activebackground="#CACACA") self.send_message_button.grid(row=1, column=1, padx=5, sticky="we") def update_chat_window(self, message): self.messageTextArea.configure(state='normal') self.messageTextArea.insert(tk.END, message) self.messageTextArea.configure(state='disabled') def send_message(self, **callbacks): message = self.entryField.get() self.set_message("") callbacks['send_message_to_server'](message) def set_message(self, message): self.entryField.delete(0, tk.END) self.entryField.insert(0, message) def bind_widgets(self, callback): self.send_message_button['command'] = lambda sendCallback = callback : self.send_message(send_message_to_server=sendCallback) self.entryField.bind("", lambda event, sendCallback = callback : self.send_message(send_message_to_server=sendCallback)) self.messageTextArea.bind("<1>", lambda event: self.messageTextArea.focus_set()) class ChatGUI(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.initUI(parent) self.ChatWindow = ChatWindow(self.parent) self.clientSocket = client.Client() self.ChatWindow.bind_widgets(self.clientSocket.send) self.parent.protocol("WM_DELETE_WINDOW", self.on_closing) def initUI(self, parent): self.parent = parent self.parent.title("ChatApp") screenSizeX = self.parent.winfo_screenwidth() screenSizeY = self.parent.winfo_screenheight() frameSizeX = 800 frameSizeY = 600 framePosX = (screenSizeX - frameSizeX) / 2 framePosY = (screenSizeY - frameSizeY) / 2 self.parent.geometry('%dx%d+%d+%d' % (frameSizeX, frameSizeY, framePosX, framePosY)) self.parent.resizable(True, True) self.parent.columnconfigure(0, weight=1) self.parent.rowconfigure(0, weight=1) self.mainMenu = tk.Menu(self.parent) self.parent.config(menu=self.mainMenu) self.subMenu = tk.Menu(self.mainMenu, tearoff=0) self.mainMenu.add_cascade(label='File', menu=self.subMenu) self.subMenu.add_command(label='Connect', command=self.connect_to_server) self.subMenu.add_command(label='Exit', command=self.on_closing) def connect_to_server(self): if self.clientSocket.isClientConnected: tk.messagebox.showwarning("Info", "Already connected to the server.") return dialogResult = ChatDialog(self.parent).result if dialogResult: self.clientSocket.connect(dialogResult[0], dialogResult[1]) if self.clientSocket.isClientConnected: SocketThreadedTask(self.clientSocket, self.ChatWindow.update_chat_window).start() else: tk.messagebox.showwarning("Error", "Unable to connect to the server.") def on_closing(self): if self.clientSocket.isClientConnected: self.clientSocket.send('/quit') self.parent.quit() self.parent.destroy() if __name__ == "__main__": root = tk.Tk() chatGUI = ChatGUI(root) root.mainloop() --------------------------------------------------------------------------------
ChatServer.py
-----------------------------------------------------------------------------------
import socket import sys import threading import Channel class Server: SERVER_CONFIG = {"MAX_CONNECTIONS": 15} HELP_MESSAGE = """ > The list of commands available are: /help - Show the instructions /join [channel_name] - To create or switch to a channel. /quit - Exits the program. /list - Lists all available channels. """.encode('utf8') def __init__(self, host=socket.gethostbyname('localhost'), port=50000, allowReuseAddress=True): self.address = (host, port) self.channels = {} # Channel Name -> Channel self.channels_client_map = {} # Client Name -> Channel Name try: self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error as errorMessage: sys.stderr.write("Failed to initialize the server. Error - %s ", str(errorMessage)) raise if allowReuseAddress: self.serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: self.serverSocket.bind(self.address) except socket.error as errorMessage: sys.stderr.write('Failed to bind to ' + self.address + '. Error - %s ', str(errorMessage)) raise def listen_thread(self, defaultGreeting=" > Welcome to our chat app!!! What is your name? "): while True: print("Waiting for a client to establish a connection ") clientSocket, clientAddress = self.serverSocket.accept() print("Connection established with IP address {0} and port {1} ".format(clientAddress[0], clientAddress[1])) self.welcome_client(clientSocket) clientThread = threading.Thread(target=self.client_thread, args=(clientSocket,)) clientThread.start() def start_listening(self): self.serverSocket.listen(Server.SERVER_CONFIG["MAX_CONNECTIONS"]) listenerThread = threading.Thread(target=self.listen_thread) listenerThread.start() listenerThread.join() def welcome_client(self, clientSocket): clientSocket.sendall(" > Welcome to our chat app!!! What is your name? ".encode('utf8')) def client_thread(self, clientSocket, size=4096): clientName = clientSocket.recv(size).decode('utf8') welcomeMessage = '> Welcome %s, type /help for a list of helpful commands. ' % clientName clientSocket.send(welcomeMessage.encode('utf8')) while True: chatMessage = clientSocket.recv(size).decode('utf8').lower() if not chatMessage: break if '/quit' in chatMessage: self.quit(clientSocket, clientName) break elif '/list' in chatMessage: self.list_all_channels(clientSocket) elif '/help' in chatMessage: self.help(clientSocket) elif '/join' in chatMessage: self.join(clientSocket, chatMessage, clientName) else: self.send_message(clientSocket, chatMessage + ' ' , clientName) clientSocket.close() def quit(self, clientSocket, clientName): clientSocket.sendall('/quit'.encode('utf8')) self.remove_client(clientName) def list_all_channels(self, clientSocket): if len(self.channels) == 0: chatMessage = " > No rooms available. Create your own by typing /join [channel_name] " clientSocket.sendall(chatMessage.encode('utf8')) else: chatMessage = ' > Current channels available are: ' for channel in self.channels: chatMessage += " " + channel + ": " + str(len(self.channels[channel].clients)) + " user(s)" chatMessage += " " clientSocket.sendall(chatMessage.encode('utf8')) def help(self, clientSocket): clientSocket.sendall(Server.HELP_MESSAGE) def join(self, clientSocket, chatMessage, clientName): isInSameRoom = False if len(chatMessage.split()) >= 2: channelName = chatMessage.split()[1] if clientName in self.channels_client_map: # Here we are switching to a new channel. if self.channels_client_map[clientName] == channelName: clientSocket.sendall((" > You are already in channel: " + channelName).encode('utf8')) isInSameRoom = True else: # switch to a new channel oldChannelName = self.channels_client_map[clientName] self.channels[oldChannelName].remove_client_from_channel(clientName) # remove them from the previous channel if not isInSameRoom: if not channelName in self.channels: newChannel = Channel.Channel(channelName) self.channels[channelName] = newChannel self.channels[channelName].clients[clientName] = clientSocket self.channels[channelName].welcome_client(clientName) self.channels_client_map[clientName] = channelName else: self.help(clientSocket) def send_message(self, clientSocket, chatMessage, clientName): if clientName in self.channels_client_map: self.channels[self.channels_client_map[clientName]].broadcast_message(chatMessage, clientName + ": ") else: chatMessage = """ > You are currently not in any channels: Use /list to see a list of available channels. Use /join [channel name] to join a channels. """.encode('utf8') clientSocket.sendall(chatMessage) def remove_client(self, clientName): if clientName in self.channels_client_map: self.channels[self.channels_client_map[clientName]].remove_client_from_channel(clientName) del self.channels_client_map[clientName] print("Client: " + clientName + " has left ") def server_shutdown(self): print("Shutting down chat server. ") self.serverSocket.shutdown(socket.SHUT_RDWR) self.serverSocket.close() def main(): chatServer = Server() print(" Listening on port " + str(chatServer.address[1])) print("Waiting for connections... ") chatServer.start_listening() chatServer.server_shutdown() if __name__ == "__main__": main() ---------------------------------------------------------------------------
ChatClient.py
--------------------------------------------------------------------------
import socket import sys class Client: def __init__(self, name='client user'): self.socket = None self.isClientConnected = False def connect(self, host, port): try: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.connect((host, port)) self.isClientConnected = True except socket.error as errorMessage: if errorMessage.errno == socket.errno.ECONNREFUSED: sys.stderr.write('Connection refused to ' + str(host) + ' on port ' + str(port)) else: sys.stderr.write('Error, unable to connect: ' + str(errorMessage)) def disconnect(self): if self.isClientConnected: self.socket.close() self.isClientConnected = False def send(self, data): if self.isClientConnected: self.socket.send(data.encode('utf8')) def receive(self, size=4096): if not self.isClientConnected: return "" return self.socket.recv(size).decode('utf8') -----------------------------------------------------------------------------------------
Channel.py
------------------------------------------------------------------------------------------
class Channel: def __init__(self, name): self.clients = {} # Client Name -> Socket self.channel_name = name def welcome_client(self, clientName): for name, socket in self.clients.items(): if name is clientName: chatMessage = ' > {0} have joined the channel {1}! '.format("You", self.channel_name) socket.sendall(chatMessage.encode('utf8')) else: chatMessage = ' > {0} has joined the channel {1}! '.format(clientName, self.channel_name) socket.sendall(chatMessage.encode('utf8')) def broadcast_message(self, chatMessage, clientName=''): for name, socket in self.clients.items(): if name is clientName: socket.sendall(("You: " + chatMessage).encode('utf8')) else: socket.sendall((clientName + chatMessage).encode('utf8')) def remove_client_from_channel(self, clientName): del self.clients[clientName] leave_message = " " + clientName + " has left the channel " + self.channel_name + " " self.broadcast_message(leave_message) ------------------------------------------------------------------------------------------------------------------------------------------------------------------
BaseEntry.py
---------------------------------------------------------------------------------------------------------------------------------------------------------------
import tkinter as tk class BaseEntry(tk.Entry): def __init__(self, root=None, placeholder="PlaceHolder", color="grey", **options): super().__init__(root, options) self.placeholder = placeholder self.placeholder_color = color self.default_fg_color = self['fg'] self.bind("", self.focus_in) self.bind("", self.focus_out) self.put_placeholder() def put_placeholder(self): self.insert(0, self.placeholder) self['fg'] = self.placeholder_color def focus_in(self, *args): if self['fg'] == self.placeholder_color: self.delete('0', 'end') self['fg'] = self.default_fg_color def focus_out(self, *args): if not self.get(): self.put_placeholder() ------------------------------------------------------------------------------------------------------------------
BaseDiolog.py
----------------------------------------------------------------------------------------------------------------
import tkinter as tk class BaseDialog(tk.Toplevel): def __init__(self, parent, title = None): tk.Toplevel.__init__(self, parent) self.transient(parent) # associate this dialog with parent window if title: self.title(title) self.parent = parent self.result = None body = tk.Frame(self) self.initial_focus = self.body(body) body.pack(padx=5, pady=5) """ createa an ok and cancel button and also binds the return and escape key. """ self.buttonbox() self.grab_set() # makes the dialog modal. if not self.initial_focus: self.initial_focus = self self.protocol("WM_DELETE_WINDOW", self.cancel) # position the dialog relative to the parent window self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50)) # move the keyboard focus to the appropriate widget. self.initial_focus.focus_set() self.wait_window(self) def body(self, master): # create dialog body. return widget that should have initial focus. # This method is meant to be overriden. pass def buttonbox(self): # add standard button box. override if you don't want the standard buttons. box = tk.Frame(self) button = tk.Button(box, text="OK", width=10, bg="#CACACA", activebackground="#CACACA", command=self.ok, default=tk.ACTIVE) button.pack(side=tk.LEFT, padx=5, pady=5) button = tk.Button(box, text="Cancel", width=10, bg="#CACACA", activebackground="#CACACA", command=self.cancel) button.pack(side=tk.LEFT, padx=5, pady=5) self.bind("", self.ok) self.bind("", self.cancel) box.pack() def ok(self, event=None): if not self.validate(): self.initial_focus.focus_set() # put focus back return self.withdraw() self.update_idletasks() self.apply() self.cancel() def cancel(self, event=None): self.parent.focus_set() # puts focus back to the parent window. self.destroy() def validate(self): return True # override if necessary def apply(self): pass # override if necessary ------------------------------------------------------------------------ right now im using pycharm and when I run main I am supposed to get a list of commands, which I have but Im having trouble adding a few.
can someone help me add the following commands to the server
AWAY
CONNECT
DIE
INFO
The definitions of the commands can be found below
----------------------------------------------------------------------------------------------------------------------------------------------------------
AWAY[edit]
Syntax:
AWAY []
Provides the server with a message to automatically send in reply to a PRIVMSG directed at the user, but not to a channel they are on.[2] If is omitted, the away status is removed. Defined in RFC 1459.
CONNECT[edit]
Syntax:
CONNECT [ []] (RFC 1459)
CONNECT [] (RFC 2812)
Instructs the server (or the current server, if is omitted) to connect to on port .[3][4] This command should only be available to IRC operators. Defined in RFC 1459; the parameter became mandatory in RFC 2812.
DIE[edit]
Syntax:
DIE
Instructs the server to shut down.[5] This command may only be issued by IRC server operators. Defined in RFC 2812.
INFO[edit]
Syntax:
INFO [
Returns information about the
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
please help
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
