# Copyright (C) 2020 by eichhornchen, ÿnérant # SPDX-License-Identifier: GPL-3.0-or-later import socket from argparse import ArgumentParser from typing import Any, Tuple class Squinnondation: args: Any bind_address: str bind_port: int client_address: str client_port: int def parse_arguments(self) -> None: parser = ArgumentParser(description="MIRC client.") parser.add_argument('bind_address', type=str, default="localhost", help="Address of the client.") parser.add_argument('bind_port', type=int, default=2500, help="Port of the client. Must be between 1024 and 65535.") parser.add_argument('--client_address', type=str, default="localhost", help="Address of the first neighbour.") parser.add_argument('--client_port', type=int, default=2500, help="Port of the first neighbour. Must be between 1024 and 65535.") parser.add_argument('--bind-only', '-b', action='store_true', help="Don't connect to another client, only listen to connections.") self.args = parser.parse_args() if not (1024 <= self.args.bind_port <= 65535) and (1024 <= self.args.client_port <= 65535): raise ValueError("Ports must be between 1024 and 65535.") self.bind_address = self.args.bind_address self.bind_port = self.args.bind_port self.client_address = self.args.client_address self.client_port = self.args.client_port @staticmethod def main() -> None: # pragma: no cover instance = Squinnondation() instance.parse_arguments() squirrel = Squirrel(input("Enter your nickname: "), instance.bind_address, instance.bind_port) if not instance.args.bind_only: hazelnut = Hazelnut(address=instance.client_address, port=instance.client_port) squirrel.send_raw_data(hazelnut, b"Hello world!") while True: data, addr = squirrel.receive_raw_data() print("received message: %s" % data) # squirrel.send_raw_data(hazelnut, b"Hello squirrel!") class Hazelnut: """ A hazelnut is a connected client, with its socket. """ def __init__(self, nickname: str = "anonymous", address: str = "localhost", port: int = 2500): self.nickname = nickname self.address = address self.port = port class Squirrel(Hazelnut): """ The squirrel is the user of the program. It can speak with other clients, that are called hazelnuts. """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.bind((self.address, self.port)) print(f"Listening on {self.address}:{self.port}") def send_raw_data(self, client: Hazelnut, data: bytes) -> int: """ Send a raw packet to a client. """ return self.socket.sendto(data, (client.address, client.port)) def receive_raw_data(self) -> Tuple[bytes, Any]: """ Receive a packet from the socket. TODO: Translate the address into the correct hazelnut. """ return self.socket.recvfrom(1024)