diff --git a/clientWin.py b/clientWin.py new file mode 100644 index 0000000..fd87cbe --- /dev/null +++ b/clientWin.py @@ -0,0 +1,275 @@ +import socket +import os +import shutil +import hashlib +import json +import getpass +from pathlib import Path +import threading +import sys + +wit = "\x1b[97m" +blauw_bg = "\x1b[44m" +groen = "\x1b[92m" +rood = "\x1b[91m" +reset = "\x1b[0m" + +commands = ["/add", "/quit", "/break", "/users", "/rm"] +chat_users = [] +chat_messages = [] +lock = threading.Lock() + +def completer(text, state): + buffer = readline.get_line_buffer() + parts = buffer.split() + + if not buffer.startswith("/"): + return None + + if len(parts) == 1: + matches = [cmd for cmd in commands if cmd.startswith(parts[0])] + return matches[state] if state < len(matches) else None + + if parts[0] == "/add" and len(parts) >= 2: + current_input = parts[-1] + matches = [user for user in chat_users if user.startswith(current_input)] + return matches[state] if state < len(matches) else None + + return None + + +import pyreadline3 +from pyreadline3.rlmain import Readline + +readline = Readline() + +readline.set_completer(completer) +readline.parse_and_bind("tab: complete") + + +# Windows setup +readline.set_completer(completer) +readline.set_completer_delims(" \t\n") +readline.parse_and_bind("tab: complete") + +def clear(): + os.system("cls") + +def term_size(): + size = shutil.get_terminal_size() + return size.columns, size.lines + +def print_white(text=""): + print(wit + text + reset) + +def recv_json(sock): + buffer = b"" + while True: + part = sock.recv(4096) + if not part: + break + buffer += part + try: + return json.loads(buffer.decode("utf-8")) + except json.JSONDecodeError: + continue + return {} + +def login(): + base_dir = Path(__file__).parent + passwd_file = base_dir / "passwd.json" + if not passwd_file.exists(): + return None + try: + with passwd_file.open("r", encoding="utf-8") as f: + data = json.load(f) + except: + data = {} + + user = input(wit + "user: " + reset) + password = getpass.getpass(wit + "password: " + reset) + password_hash = hashlib.sha256(password.encode("utf-8")).hexdigest() + + if user in data and data[user] == password_hash: + return user + return None + +def signup(): + base_dir = Path(__file__).parent + passwd_file = base_dir / "passwd.json" + + if passwd_file.exists(): + try: + with passwd_file.open("r", encoding="utf-8") as f: + data = json.load(f) + except: + data = {} + else: + data = {} + + user = input(wit + "Gebruiker: " + reset) + if user in data: + return + + password = getpass.getpass(wit + "Wachtwoord: " + reset) + data[user] = hashlib.sha256(password.encode("utf-8")).hexdigest() + + with passwd_file.open("w", encoding="utf-8") as f: + json.dump(data, f, indent=4) + +current_user = None + +while not current_user: + clear() + w, _ = term_size() + print(blauw_bg + wit + "Terminal Chat ".center(w) + reset) + print() + print(groen + "========================================") + print(" Welcome to the Terminal Chat") + print("========================================" + reset) + print() + print_white("1. Login") + print_white("2. Sign up") + print() + keuze = input(wit + " > " + reset) + print() + + if keuze == "1": + current_user = login() + elif keuze == "2": + signup() + +host = "192.168.254.36" +port = 44703 + +try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((host, port)) + s.sendall(current_user.encode("utf-8")) +except Exception as e: + print("Connection failed:", e) + exit() + +chat_data = recv_json(s) +chat_names = list(chat_data.keys()) + +def draw_chat_window(messages, chatname): + with lock: + current_input = readline.get_line_buffer() + + clear() + w, h = term_size() + print(blauw_bg + wit + chatname.center(w) + reset) + + available_lines = h - 3 + to_display = messages[-available_lines:] + + for msg in to_display: + user = msg["user"] + text = msg["message"] + if user == current_user: + print(wit + f" {text} [you]".rjust(w) + reset) + else: + print_white(f"[{user}] {text}") + + print("-" * w) + + readline.insert_text(current_input) + readline.redisplay() + +def chat_session(chatkeuze): + global chat_messages, chat_users + + s.sendall(json.dumps({ + "action": "openchat", + "chat_name": chatkeuze + }).encode("utf-8")) + + chat_data = recv_json(s) + + if chatkeuze in chat_data: + chat_messages = chat_data[chatkeuze].get("messages", []) + chat_users = chat_data[chatkeuze].get("users", []) + + def receive_messages(sock): + global chat_messages, chat_users + while True: + try: + decoded = recv_json(sock) + if not decoded: + break + + if isinstance(decoded, dict) and chatkeuze in decoded: + with lock: + chat_messages = decoded[chatkeuze].get("messages", []) + chat_users = decoded[chatkeuze].get("users", []) + draw_chat_window(chat_messages, chatkeuze) + + except: + break + + threading.Thread(target=receive_messages, args=(s,), daemon=True).start() + + while True: + draw_chat_window(chat_messages, chatkeuze) + bericht = input(wit + "> " + reset) + + if bericht.lower() == "/quit": + exit() + + elif bericht.lower() == "/break": + break + + elif bericht.lower() == "/users": + s.sendall(json.dumps({ + "action": "get_users", + "chat": chatkeuze + }).encode("utf-8")) + + elif bericht.lower().startswith("/add "): + target_user = bericht.split(" ", 1)[1] + s.sendall(json.dumps({ + "action": "add_user", + "chat": chatkeuze, + "user": target_user, + "by": current_user + }).encode("utf-8")) + + else: + with lock: + chat_messages.append({ + "user": current_user, + "message": bericht + }) + + draw_chat_window(chat_messages, chatkeuze) + + s.sendall(json.dumps({ + "action": "message", + "chat_name": chatkeuze, + "message": bericht + }).encode("utf-8")) + +while True: + print_white(" --- Available chats: --- ") + + for i, chat in enumerate(chat_names, start=1): + print_white(f"{i}. {chat}") + + print_white(f"{len(chat_names)+1}. New chat") + + keuze = input(wit + " > " + reset) + + if keuze.isdigit() and int(keuze) == len(chat_names)+1: + nieuwe_chat = input("Name of new chat: ") + s.sendall(json.dumps({ + "action": "new_chat", + "chat_name": nieuwe_chat + }).encode("utf-8")) + + chat_data = recv_json(s) + chat_names = list(chat_data.keys()) + + elif keuze.isdigit() and 1 <= int(keuze) <= len(chat_names): + chatkeuze = chat_names[int(keuze)-1] + chat_session(chatkeuze) \ No newline at end of file