diff --git a/README.md b/README.md index f963561..91b2c6e 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,17 @@ Version: 1.0.0 ## OVERVIEW - +With the python standard socket module, enable the user(s) to communicate with the terminal and other users via the local host. Allow each user to execuse commands such as "/quick", "/list", "/nickname ", and "dm ". ## GETTING STARTED - +To successfully execute this program, the user needs Python 3.6, a terminal that runs server.py and additional terminal to connect to the local host as users. ## ARCHITECTURE - +1. server.py: Setup the server on the local host +2. client.py: Setup the client, initiating the client with their conn and addr +3. Via terminal local host, connect the server with the user(s) ## API diff --git a/client.py b/client.py new file mode 100644 index 0000000..e386548 --- /dev/null +++ b/client.py @@ -0,0 +1,23 @@ +import random +import uuid + + +class Client: + """ + """ + + def __init__(self, conn=None, addr=None): + self.id = str(uuid.uuid4()) + self.nick = f'user_{random.random()}' + self.conn = conn + self.addr = addr + + def __str__(self): + pass + + def __repr__(self): + pass + + def change_nickname(self, nick): + self.nick = nick + return(self) diff --git a/server.py b/server.py new file mode 100644 index 0000000..1ebca9c --- /dev/null +++ b/server.py @@ -0,0 +1,102 @@ +from client import Client +import threading +import socket + +PORT = 4562 + + +class ChatServer(threading.Thread): + def __init__(self, port, host='localhost'): + super().__init__(daemon=True) + self.port = PORT + self.host = host + self.server = socket.socket( + socket.AF_INET, + socket.SOCK_STREAM, + socket.IPPROTO_TCP, + ) + self.client_pool = [] + + try: + self.server.bind((self.host, self.port)) + except socket.error: + print(f'bind failed { socket.error }') + + self.server.listen(10) + + def parser(self, id, nick, conn, message): + """Parse the message out to look for keywords.""" + if message.decode().startswith('/'): + data = message.decode().split(maxsplit=1) + + if data[0] == '/quit': + conn.sendall(b'You have left the chat.') + reply = nick.encode() + b'has left the channel.\n' + [c.conn.sendall(reply) for c in self.client_pool if len(self.client_pool)] + self.client_pool = [c for c in self.client_pool if c.id != id] + conn.close() + + if data[0] == '/list': + reply = '' + for c in self.client_pool: + reply += c.nick + ' \n' + [c.conn.sendall(reply.encode()) for c in self.client_pool if len(self.client_pool)] + return('') + + if data[0] == '/nickname': + for i in self.client_pool: + if i.id == id: + i.change_nickname(data[1]) + reply = 'Nickname updated to:' + data[1] + return reply + + if data[0] == '/dm': + for i in self.client_pool: + data = message.decode().split(maxsplit=2) + if i.nick.rstrip() == data[1]: + i.conn.sendall(data[2].encode()) + return(i.nick) + + else: + reply = nick.encode() + b': ' + message + [c.conn.sendall(reply) for c in self.client_pool if len(self.client_pool)] + return('') + + def run_thread(self, id, nick, conn, addr): + """changes the nickname and establishes connection""" + print('{} connected with {}:{}'.format(nick, addr[0], str(addr[1]))) + try: + while True: + data = conn.recv(4096) + parsed_nick = self.parser(id, nick, conn, data) + if len(parsed_nick): + nick = parsed_nick + + except (OSError): + conn.close() + + def run(self): + """ Runs the server.""" + print('Server running on {}'.format(PORT)) + while True: + conn, addr = self.server.accept() + client = Client(conn, addr) + self.client_pool.append(client) + threading.Thread( + target=self.run_thread, + args=(client.id, client.nick, client.conn, client.addr), + daemon=True + ).start() + + def exit(self): + """Close the connection.""" + self.server.close() + + +if __name__ == '__main__': + server = ChatServer(PORT) + try: + server.run() + except KeyboardInterrupt: + [c.conn.close() for c in server.client_pool if len(server.client_pool)] + server.exit() diff --git a/tcp_chat/__init__.py b/tcp_chat/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tcp_echo/__init__.py b/tcp_echo/__init__.py deleted file mode 100644 index e69de29..0000000