import socket import os import shutil import hashlib import json import getpass from pathlib import Path import threading import readline 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])] if state < len(matches): return matches[state] return 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)] if state < len(matches): return matches[state] return None return None readline.set_completer_delims(" \t\n") readline.set_completer(completer) readline.parse_and_bind("tab: complete") def clear(): os.system("cls" if os.name == "nt" else "clear") def term_size(): size = shutil.get_terminal_size() return size.columns, size.lines def print_white(text=""): print(wit + text + reset) 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 + "Gebruikersnaam: " + reset) password = getpass.getpass(wit + "Wachtwoord: " + 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_white("1. inloggen") print_white("2. nieuw account") keuze = input(wit + " > " + reset) 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() data = s.recv(4096) chat_data = json.loads(data.decode("utf-8")) chat_names = list(chat_data.keys()) def draw_chat_window(messages, chatname): 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) def chat_session(chatkeuze): global chat_messages global chat_users s.sendall(json.dumps({"action": "openchat", "chat_name": chatkeuze}).encode("utf-8")) data = s.recv(4096) chat_data = json.loads(data.decode("utf-8")) 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 global chat_users while True: try: data = sock.recv(4096) if not data: break decoded = json.loads(data.decode("utf-8")) # /users response if isinstance(decoded, dict) and decoded.get("type") == "users_list": users = decoded.get("users", []) print("\nUsers:", ", ".join(users)) print(wit + "Typ je bericht: " + reset, end="", flush=True) continue # normale chat update 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) print(wit + "Typ je bericht: " + reset, end="", flush=True) except Exception: break threading.Thread(target=receive_messages, args=(s,), daemon=True).start() while True: draw_chat_window(chat_messages, chatkeuze) bericht = input(wit + "Typ je bericht: " + reset) if bericht.lower() == "/quit": exit() elif bericht.lower() == "/rm": s.sendall(json.dumps({ "action": "remove_message", "chat_name": chatkeuze, "by": current_user }).encode("utf-8")) 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("Beschikbare chats:") for i, chat in enumerate(chat_names, start=1): print_white(f"{i}. {chat}") print_white(f"{len(chat_names)+1}. Nieuwe chat aanmaken") keuze = input(wit + " > " + reset) if keuze.isdigit() and int(keuze) == len(chat_names)+1: nieuwe_chat = input("Naam van nieuwe chat: ") s.sendall(json.dumps({"action": "new_chat", "chat_name": nieuwe_chat}).encode("utf-8")) data = s.recv(4096) chat_data = json.loads(data.decode("utf-8")) 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)