Skip to content

Commit

Permalink
properly fix the config situation for the tui client
Browse files Browse the repository at this point in the history
  • Loading branch information
iiPythonx committed Nov 25, 2024
1 parent 69f7063 commit 77be2c8
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 165 deletions.
25 changes: 0 additions & 25 deletions nightwatch/__main__.py

This file was deleted.

136 changes: 1 addition & 135 deletions nightwatch/client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,138 +1,4 @@
# Copyright (c) 2024 iiPython

# Modules
import os
import re
import typing
import requests
from threading import Thread

import urwid
import websockets
from websockets.sync.client import connect

from nightwatch import __version__, HEX_COLOR_REGEX
from nightwatch.config import fetch_config

from .extra.ui import NightwatchUI
from .extra.select import menu
from .extra.wswrap import ORJSONWebSocket

# Initialization
config = fetch_config("config")

if os.name == "nt":
urwid.set_encoding("utf-8")

# Connection handler
def connect_loop(host: str, port: int, username: str) -> None:
protocol, url = "s" if port == 443 else "", f"{host}:{port}"

# Perform authentication
resp = requests.post(f"http{protocol}://{url}/api/join", json = {"username": username, "hex": config["client.color"]}).json()
if resp.get("code") != 200:
exit(f"\nCould not connect to {url}. Additional details:\n{resp}")

destination = f"ws{protocol}://{url}/api/ws?authorization={resp['authorization']}"
try:
with connect(destination) as ws:
ws = ORJSONWebSocket(ws)

# Handle fetching server information
response = ws.recv()

# Create UI
ui = NightwatchUI(ws)
loop = urwid.MainLoop(ui.frame, [
("yellow", "yellow", ""),
("gray", "dark gray", "", "", "#555753", ""),
("green", "dark green", "")
])
loop.screen.set_terminal_properties(2 ** 24) # Activate 24-bit color mode

# Individual components
loop.screen.register_palette_entry("time", "dark green", "", foreground_high = config["colors.time"] or "#00FF00")
loop.screen.register_palette_entry("sep", "dark gray", "", foreground_high = config["colors.sep"] or "#555753")

# Handle messages
def message_loop(ws: ORJSONWebSocket, ui: NightwatchUI) -> None:
try:
while ws.ws:
ui.on_message(ws.recv())

except websockets.exceptions.ConnectionClosed:
pass

Thread(target = message_loop, args = [ws, ui]).start()

# Start mainloop
ui.on_ready(loop, response["data"])
loop.run()

except websockets.exceptions.InvalidURI:
exit(f"\nCould not connect to {destination} due to an HTTP redirect.\nPlease ensure you entered the correct address.")

except OSError:
exit(f"\nCould not connect to {destination} due to an OSError.\nThis is more then likely because the server is not running.")

# Entrypoint
def start_client(
address: typing.Optional[str] = None,
username: typing.Optional[str] = None
):
username = username or config["client.username"]

# Start main UI
print(f"\033[H\033[2J✨ Nightwatch | v{__version__}\n")
if username is None:
print("Hello! It seems that this is your first time using Nightwatch.")
print("Before you can connect to a server, please set your desired username.\n")

username = input("Username: ")
config.set("client.username", username)
print("\033[4A\033[0J", end = "") # Reset back up to the Nightwatch label

# Handle color setup
color = config["client.color"] or ""
if not re.match(HEX_COLOR_REGEX, color):
while True:
print("For fun, you can select a color for your username.")
print("Please enter the HEX code (6 long) you would like to have as your color.")
color = (input("> #") or "ffffff").lstrip("#")

# Validate their color choice
if re.match(HEX_COLOR_REGEX, color):
break

print("\033[3A\033[0J", end = "")

print("\033[3A\033[0J", end = "")
config.set("client.color", color)

# Handle server address
if address is None:
servers = config["client.servers"]
if servers is None:
servers = ["nightwatch.iipython.dev"]
config.set("client.servers", servers)

print(f"Hello, {username}. Please select a Nightwatch server to connect to:")
address = menu.show(servers)
print()

print(f"Establishing connection to {address} ...")

# Parse said address
if ":" not in address:
host, port = address, 443

else:
host, port = address.split(":")

# Connect to server
try:
connect_loop(host, int(port), username)

except KeyboardInterrupt:
print("\033[5A\033[0J", end = "") # Reset back up to the Nightwatch label
print(f"Goodbye, {username}.")
config = fetch_config("client")
155 changes: 155 additions & 0 deletions nightwatch/client/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Copyright (c) 2024 iiPython

# Modules
import os
import re
import typing
import requests
from threading import Thread
from argparse import ArgumentParser

import urwid
import websockets
from websockets.sync.client import connect

from nightwatch import __version__, HEX_COLOR_REGEX

from . import config
from .extra.ui import NightwatchUI
from .extra.select import menu
from .extra.wswrap import ORJSONWebSocket

# Initialization
if os.name == "nt":
urwid.set_encoding("utf-8")

# Connection handler
def connect_loop(host: str, port: int, username: str) -> None:
protocol, url = "s" if port == 443 else "", f"{host}:{port}"

# Perform authentication
resp = requests.post(f"http{protocol}://{url}/api/join", json = {"username": username, "hex": config["client.color"]}).json()
if resp.get("code") != 200:
exit(f"\nCould not connect to {url}. Additional details:\n{resp}")

destination = f"ws{protocol}://{url}/api/ws?authorization={resp['authorization']}"
try:
with connect(destination) as ws:
ws = ORJSONWebSocket(ws)

# Handle fetching server information
response = ws.recv()

# Create UI
ui = NightwatchUI(ws)
loop = urwid.MainLoop(ui.frame, [
("yellow", "yellow", ""),
("gray", "dark gray", "", "", "#555753", ""),
("green", "dark green", "")
])
loop.screen.set_terminal_properties(2 ** 24) # Activate 24-bit color mode

# Individual components
loop.screen.register_palette_entry("time", "dark green", "", foreground_high = config["colors.time"] or "#00FF00")
loop.screen.register_palette_entry("sep", "dark gray", "", foreground_high = config["colors.sep"] or "#555753")

# Handle messages
def message_loop(ws: ORJSONWebSocket, ui: NightwatchUI) -> None:
try:
while ws.ws:
ui.on_message(ws.recv())

except websockets.exceptions.ConnectionClosed:
pass

Thread(target = message_loop, args = [ws, ui]).start()

# Start mainloop
ui.on_ready(loop, response["data"])
loop.run()

except websockets.exceptions.InvalidURI:
exit(f"\nCould not connect to {destination} due to an HTTP redirect.\nPlease ensure you entered the correct address.")

except OSError:
exit(f"\nCould not connect to {destination} due to an OSError.\nThis is more then likely because the server is not running.")

# Entrypoint
def start_client(
address: typing.Optional[str] = None,
username: typing.Optional[str] = None
):
username = username or config["client.username"]

# Start main UI
print(f"\033[H\033[2J✨ Nightwatch | v{__version__}\n")
if username is None:
print("Hello! It seems that this is your first time using Nightwatch.")
print("Before you can connect to a server, please set your desired username.\n")

username = input("Username: ")
config.set("client.username", username)
print("\033[4A\033[0J", end = "") # Reset back up to the Nightwatch label

# Handle color setup
color = config["client.color"] or ""
if not re.match(HEX_COLOR_REGEX, color):
while True:
print("For fun, you can select a color for your username.")
print("Please enter the HEX code (6 long) you would like to have as your color.")
color = (input("> #") or "ffffff").lstrip("#")

# Validate their color choice
if re.match(HEX_COLOR_REGEX, color):
break

print("\033[3A\033[0J", end = "")

print("\033[3A\033[0J", end = "")
config.set("client.color", color)

# Handle server address
if address is None:
servers = config["client.servers"]
if servers is None:
servers = ["nightwatch.iipython.dev"]
config.set("client.servers", servers)

print(f"Hello, {username}. Please select a Nightwatch server to connect to:")
address = menu.show(servers)
print()

print(f"Establishing connection to {address} ...")

# Parse said address
if ":" not in address:
host, port = address, 443

else:
host, port = address.split(":")

# Connect to server
try:
connect_loop(host, int(port), username)

except KeyboardInterrupt:
print("\033[5A\033[0J", end = "") # Reset back up to the Nightwatch label
print(f"Goodbye, {username}.")

# Initialization
def main() -> None:
ap = ArgumentParser(
prog = "nightwatch",
description = "The chatting application to end all chatting applications.\nhttps://github.com/iiPythonx/nightwatch",
epilog = "Copyright (c) 2024 iiPython"
)
ap.add_argument("-a", "--address", help = "the nightwatch server to connect to")
ap.add_argument("-u", "--username", help = "the username to use")
ap.add_argument("-r", "--reset", action = "store_true", help = "reset the configuration file")

# Launch client
args = ap.parse_args()
if args.reset:
fetch_config("config").reset()

start_client(args.address, args.username)
4 changes: 2 additions & 2 deletions nightwatch/client/extra/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Callable

from nightwatch import __version__
from nightwatch.config import fetch_config
from nightwatch.client import config

# Main class
class BaseCommand():
Expand Down Expand Up @@ -47,7 +47,7 @@ def on_execute(self, args: list[str]) -> None:
elif len(args) < 2:
return self.print(f"Missing the value to assign to '{args[0]}'.")

fetch_config("config").set(args[0], args[1])
config.set(args[0], args[1])
self.print(f"{args[0]} has been set to \"{args[1]}\".")

class HelpCommand(BaseCommand):
Expand Down
4 changes: 2 additions & 2 deletions nightwatch/client/extra/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .wswrap import ORJSONWebSocket
from ..vendor.scroll import Scrollable, ScrollBar

from nightwatch.config import fetch_config
from nightwatch.client import config

# Input edit class
class InputEdit(urwid.Edit):
Expand Down Expand Up @@ -71,7 +71,7 @@ def construct_message(self, author: str, content: str, user_color: str = "gray")
visible_author = author if author != self.last_author else " " * self.length(author)
now, time_string = datetime.now(), ""
if (author != self.last_author) or ((now - self.last_time).total_seconds() > 300):
time_string = now.strftime("%I:%M %p" if fetch_config("config")["client.time_format"] != "24h" else "%H:%M") + " " # Right padding for the scrollbar
time_string = now.strftime("%I:%M %p" if config["client.time_format"] != "24h" else "%H:%M") + " " # Right padding for the scrollbar

self.pile.contents.append((urwid.Columns([
(self.length(visible_author), urwid.Text((user_color, visible_author))),
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ Homepage = "https://github.com/iiPythonx/nightwatch"
Issues = "https://github.com/iiPythonx/nightwatch/issues"

[project.scripts]
nightwatch = "nightwatch.__main__:main"
nightwatch = "nightwatch.client.__main__:main"

0 comments on commit 77be2c8

Please sign in to comment.