Uses curses to have a proper terminal UI
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
			
		||||
# Copyright (C) 2020 by eichhornchen, ÿnérant
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
import curses
 | 
			
		||||
import socket
 | 
			
		||||
from argparse import ArgumentParser
 | 
			
		||||
from enum import Enum
 | 
			
		||||
@@ -8,6 +9,8 @@ from ipaddress import IPv6Address
 | 
			
		||||
from threading import Thread
 | 
			
		||||
from typing import Any, List, Optional, Tuple
 | 
			
		||||
 | 
			
		||||
from squinnondation.term_manager import TermManager
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Squinnondation:
 | 
			
		||||
    args: Any
 | 
			
		||||
@@ -43,28 +46,48 @@ class Squinnondation:
 | 
			
		||||
        instance = Squinnondation()
 | 
			
		||||
        instance.parse_arguments()
 | 
			
		||||
 | 
			
		||||
        squirrel = Squirrel(input("Enter your nickname: "), instance.bind_address, instance.bind_port)
 | 
			
		||||
        with TermManager() as term_manager:
 | 
			
		||||
            screen = term_manager.screen
 | 
			
		||||
            screen.addstr(0, 0, "Enter your nickname: ")
 | 
			
		||||
            nickname = screen.getstr().decode("UTF-8")
 | 
			
		||||
            squirrel = Squirrel(nickname, instance.bind_address, instance.bind_port)
 | 
			
		||||
 | 
			
		||||
        if not instance.args.bind_only:
 | 
			
		||||
            hazelnut = Hazelnut(address=instance.client_address, port=instance.client_port)
 | 
			
		||||
            squirrel.hazelnuts[(instance.client_address, instance.client_port)] = hazelnut
 | 
			
		||||
            if not instance.args.bind_only:
 | 
			
		||||
                hazelnut = Hazelnut(address=instance.client_address, port=instance.client_port)
 | 
			
		||||
                squirrel.hazelnuts[(instance.client_address, instance.client_port)] = hazelnut
 | 
			
		||||
 | 
			
		||||
        Worm(squirrel).start()
 | 
			
		||||
            squirrel.history = []
 | 
			
		||||
 | 
			
		||||
        while True:
 | 
			
		||||
            msg = f"<{squirrel.nickname}> {input(f'<{squirrel.nickname}> ')}"
 | 
			
		||||
            for hazelnut in list(squirrel.hazelnuts.values()):
 | 
			
		||||
                pkt = Packet()
 | 
			
		||||
                pkt.magic = 95
 | 
			
		||||
                pkt.version = 0
 | 
			
		||||
                tlv = DataTLV()
 | 
			
		||||
                tlv.data = msg.encode("UTF-8")
 | 
			
		||||
                tlv.sender_id = 42
 | 
			
		||||
                tlv.nonce = 18
 | 
			
		||||
                tlv.length = len(msg) + 1 + 1 + 8 + 4
 | 
			
		||||
                pkt.body = [tlv]
 | 
			
		||||
                pkt.body_length = tlv.length + 2
 | 
			
		||||
                squirrel.send_packet(hazelnut, pkt)
 | 
			
		||||
            def refresh() -> None:
 | 
			
		||||
                screen.clear()
 | 
			
		||||
                screen.refresh()
 | 
			
		||||
                for i, msg in enumerate(squirrel.history[max(0, len(squirrel.history) - curses.LINES + 2):]):
 | 
			
		||||
                    screen.addstr(i, 0, msg)
 | 
			
		||||
 | 
			
		||||
                screen.addstr(curses.LINES - 1, 0, f"<{squirrel.nickname}> ")
 | 
			
		||||
                screen.refresh()
 | 
			
		||||
            squirrel.refresh = refresh
 | 
			
		||||
 | 
			
		||||
            Worm(squirrel).start()
 | 
			
		||||
 | 
			
		||||
            while True:
 | 
			
		||||
                refresh()
 | 
			
		||||
                msg = screen.getstr().decode("UTF-8")
 | 
			
		||||
                msg = f"<{squirrel.nickname}> {msg}"
 | 
			
		||||
                squirrel.history.append(msg)
 | 
			
		||||
 | 
			
		||||
                for hazelnut in list(squirrel.hazelnuts.values()):
 | 
			
		||||
                    pkt = Packet()
 | 
			
		||||
                    pkt.magic = 95
 | 
			
		||||
                    pkt.version = 0
 | 
			
		||||
                    tlv = DataTLV()
 | 
			
		||||
                    tlv.data = msg.encode("UTF-8")
 | 
			
		||||
                    tlv.sender_id = 42
 | 
			
		||||
                    tlv.nonce = 18
 | 
			
		||||
                    tlv.length = len(tlv.data) + 1 + 1 + 8 + 4
 | 
			
		||||
                    pkt.body = [tlv]
 | 
			
		||||
                    pkt.body_length = tlv.length + 2
 | 
			
		||||
                    squirrel.send_packet(hazelnut, pkt)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TLV:
 | 
			
		||||
@@ -415,10 +438,12 @@ class Worm(Thread):
 | 
			
		||||
        self.squirrel = squirrel
 | 
			
		||||
 | 
			
		||||
    def run(self) -> None:
 | 
			
		||||
        self.squirrel.history = []
 | 
			
		||||
        while True:
 | 
			
		||||
            try:
 | 
			
		||||
                pkt, hazelnut = self.squirrel.receive_packet()
 | 
			
		||||
            except ValueError as error:
 | 
			
		||||
                print("An error occured while receiving a packet: ", error)
 | 
			
		||||
            else:
 | 
			
		||||
                print(pkt.body[0].data.decode('UTF-8'))
 | 
			
		||||
                self.squirrel.history.append(pkt.body[0].data.decode('UTF-8'))
 | 
			
		||||
                self.squirrel.refresh()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								squinnondation/term_manager.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								squinnondation/term_manager.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
import curses
 | 
			
		||||
from types import TracebackType
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TermManager:  # pragma: no cover
 | 
			
		||||
    """
 | 
			
		||||
    The TermManager object initializes the terminal, returns a screen object and
 | 
			
		||||
    de-initializes the terminal after use
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.screen = curses.initscr()
 | 
			
		||||
        # convert escapes sequences to curses abstraction
 | 
			
		||||
        self.screen.keypad(True)
 | 
			
		||||
        # stop printing typed keys to the terminal
 | 
			
		||||
        # curses.noecho()
 | 
			
		||||
        # send keys through without having to press <enter>
 | 
			
		||||
        # curses.cbreak()
 | 
			
		||||
        # make cursor invisible
 | 
			
		||||
        # curses.curs_set(False)
 | 
			
		||||
        # Catch mouse events
 | 
			
		||||
        curses.mousemask(True)
 | 
			
		||||
        # Enable colors
 | 
			
		||||
        curses.start_color()
 | 
			
		||||
 | 
			
		||||
    def __enter__(self):
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    def __exit__(self, exc_type: type, exc_value: Exception,
 | 
			
		||||
                 exc_traceback: TracebackType) -> None:
 | 
			
		||||
        # restore the terminal to its original state
 | 
			
		||||
        self.screen.keypad(False)
 | 
			
		||||
        # curses.echo()
 | 
			
		||||
        # curses.nocbreak()
 | 
			
		||||
        # curses.curs_set(True)
 | 
			
		||||
        curses.endwin()
 | 
			
		||||
		Reference in New Issue
	
	Block a user