From e356f62f97da7a7dce65f6db3e1b33c99c53adba Mon Sep 17 00:00:00 2001 From: desty2k Date: Tue, 17 May 2022 08:25:58 +0200 Subject: [PATCH] UPD: add write methods, rename Device to Client --- QtPyNetwork2/balancers/AbstractBalancer.py | 20 +++- QtPyNetwork2/balancers/NoBalancer.py | 68 +++++++++-- QtPyNetwork2/server/AbstractServer.py | 128 ++++++++++++--------- examples2/client.py | 6 +- examples2/no_balancer.py | 13 ++- 5 files changed, 163 insertions(+), 72 deletions(-) diff --git a/QtPyNetwork2/balancers/AbstractBalancer.py b/QtPyNetwork2/balancers/AbstractBalancer.py index db4c7a5..c0515e6 100644 --- a/QtPyNetwork2/balancers/AbstractBalancer.py +++ b/QtPyNetwork2/balancers/AbstractBalancer.py @@ -1,4 +1,5 @@ from qtpy.QtCore import QObject, Signal, Slot +from abc import ABC, abstractmethod import logging from struct import calcsize @@ -11,7 +12,7 @@ class AbstractBalancer(QObject): disconnected = Signal(int) connected = Signal(int, str, int) message = Signal(int, bytes) - error = Signal(int, Exception) + client_error = Signal(int, Exception) closed = Signal() def __init__(self): @@ -19,16 +20,29 @@ def __init__(self): self.logger = logging.getLogger(self.__class__.__name__) self.__socket_id = 0 + @abstractmethod @Slot(type, int) def balance(self, socket_type: type, socket_descriptor: int): pass + @abstractmethod @Slot(int, bytes) - def write(self, device_id: int, message: bytes): + def write(self, client_id: int, message: bytes): pass + @abstractmethod + @Slot(bytes) + def write_all(self, message: bytes): + pass + + @abstractmethod @Slot(int) - def close(self, device_id: int): + def disconnect(self, client_id: int): + pass + + @abstractmethod + @Slot() + def close(self): pass @Slot() diff --git a/QtPyNetwork2/balancers/NoBalancer.py b/QtPyNetwork2/balancers/NoBalancer.py index 7f49454..d20e978 100644 --- a/QtPyNetwork2/balancers/NoBalancer.py +++ b/QtPyNetwork2/balancers/NoBalancer.py @@ -1,9 +1,9 @@ from qtpy.QtCore import Slot, Signal -from qtpy.QtNetwork import QAbstractSocket, QUdpSocket +from qtpy.QtNetwork import QAbstractSocket -from struct import unpack +from struct import unpack, pack -from .AbstractBalancer import AbstractBalancer +from .AbstractBalancer import AbstractBalancer, HEADER, HEADER_SIZE class NoBalancer(AbstractBalancer): @@ -67,9 +67,6 @@ def __on_socket_ready_read(self): def __on_socket_disconnected(self): """Handle socket disconnection. - Args: - conn (QTcpSocket): Socket object. - Note: Emits disconnected signal. """ @@ -87,14 +84,65 @@ def __on_socket_disconnected(self): def __on_socket_error(self): """Handle socket errors. - Args: - conn (QTcpSocket): Socket object. - Note: Emits error signal. """ socket = self.sender() client_id = int(socket.objectName()) error = socket.errorString() - self.error.emit(client_id, Exception(error)) + self.client_error.emit(client_id, Exception(error)) + + @Slot(int, bytes) + def write(self, client_id: int, data: bytes): + """Write data to socket. + + Args: + client_id (int): Client ID. + data (bytes): Data to write. + """ + for socket in self.sockets: + if int(socket.objectName()) == client_id: + data = pack(HEADER, len(data)) + data + socket.write(data) + socket.flush() + print(f"Written {len(data)} bytes to {socket.objectName()}") + return + print(f"{client_id} - {data}") + print([socket.objectName() for socket in self.sockets]) + self.client_error.emit(client_id, Exception(f"Client {client_id} not found")) + + @Slot(bytes) + def write_all(self, message: bytes): + """Write data to all sockets. + + Args: + message (bytes): Data to write. + """ + for socket in self.sockets: + socket.write(message) + socket.flush() + + @Slot(int) + def disconnect(self, client_id: int): + """Disconnect socket. + + Args: + client_id (int): Client ID. + """ + for socket in self.sockets: + if int(socket.objectName()) == client_id: + socket.disconnectFromHost() + return + self.client_error.emit(client_id, Exception(f"Client {client_id} not found")) + + @Slot() + def close(self): + """Close all sockets.""" + for socket in self.sockets: + try: + socket.disconnectFromHost() + socket.close() + except RuntimeError: + pass + self.sockets.clear() diff --git a/QtPyNetwork2/server/AbstractServer.py b/QtPyNetwork2/server/AbstractServer.py index 076ed10..7c62af8 100644 --- a/QtPyNetwork2/server/AbstractServer.py +++ b/QtPyNetwork2/server/AbstractServer.py @@ -1,8 +1,8 @@ from qtpy.QtCore import Slot, Signal, QObject, QThread from qtpy.QtNetwork import QTcpServer, QHostAddress -from QtPyNetwork.models import Device -from QtPyNetwork.exceptions import NotConnectedError, ServerNotRunning +from QtPyNetwork2.models import Client +from QtPyNetwork2.exceptions import NotConnectedError, ServerNotRunning import logging @@ -13,48 +13,49 @@ class AbstractServer(QObject): started = Signal(str, int) closed = Signal() - connected = Signal(Device, str, int) - disconnected = Signal(Device) - message = Signal(Device, bytes) + connected = Signal(Client, str, int) + disconnected = Signal(Client) + message = Signal(Client, bytes) - client_error = Signal(Device, Exception) + client_error = Signal(Client, Exception) server_error = Signal(Exception) def __init__(self, balancer: AbstractBalancer): super(AbstractServer, self).__init__() - self.devices: list[Device] = [] + self.clients: list[Client] = [] self.server: QObject = None - self.device_model = Device + self.client_model = Client self.balancer = balancer - self.balancer.connected.connect(self.__on_balancer_device_connected) - self.balancer.message.connect(self.__on_balancer_device_message) - self.balancer.error.connect(self.__on_balancer_device_error) + self.balancer.connected.connect(self.__on_balancer_client_connected) + self.balancer.disconnected.connect(self.__on_balancer_client_disconnected) + self.balancer.message.connect(self.__on_balancer_client_message) + self.balancer.client_error.connect(self.__on_balancer_client_error) self.balancer.closed.connect(self.on_closed) @Slot(int, str, int) - def __on_balancer_device_connected(self, device_id: int, ip: str, port: int): - device = self.device_model(self, device_id, ip, port) - self.devices.append(device) - self.on_connected(device, ip, port) + def __on_balancer_client_connected(self, client_id: int, ip: str, port: int): + client = self.client_model(self, client_id, ip, port) + self.clients.append(client) + self.on_connected(client, ip, port) @Slot(int, bytes) - def __on_balancer_device_message(self, device_id: int, message: bytes): - """When server receives message from device.""" - self.on_message(self.get_device_by_id(device_id), message) + def __on_balancer_client_message(self, client_id: int, message: bytes): + """When server receives message from client.""" + self.on_message(self.get_client_by_id(client_id), message) @Slot(int) - def __on_balancer_device_disconnected(self, device_id: int): - """When device disconnects from server.""" - device = self.get_device_by_id(device_id) - device.set_connected(False) - if device in self.devices: - self.devices.remove(device) - self.on_disconnected(device) + def __on_balancer_client_disconnected(self, client_id: int): + """When client disconnects from server.""" + client = self.get_client_by_id(client_id) + client.set_connected(False) + if client in self.clients: + self.clients.remove(client) + self.on_disconnected(client) @Slot(int, Exception) - def __on_balancer_device_error(self, device_id: int, error: Exception): - self.on_device_error(self.get_device_by_id(device_id), error) + def __on_balancer_client_error(self, client_id: int, error: Exception): + self.on_client_error(self.get_client_by_id(client_id), error) @Slot(str, int) def start(self, ip: str, port: int): @@ -64,49 +65,49 @@ def start(self, ip: str, port: int): def on_started(self, ip: str, port: int): self.started.emit(ip, port) - @Slot(Device, str, int) - def on_connected(self, device: Device, ip: str, port: int): + @Slot(Client, str, int) + def on_connected(self, client: Client, ip: str, port: int): """Called when new client connects to server. Emits connected signal. Args: - device (Device): Device object. + client (Client): Client object. ip (str): Client ip address. port (int): Client port. """ - self.connected.emit(device, ip, port) + self.connected.emit(client, ip, port) - @Slot(Device, bytes) - def on_message(self, device: Device, message: bytes): + @Slot(Client, bytes) + def on_message(self, client: Client, message: bytes): """Called when server receives message from client. Emits message signal. Args: - device (Device): Message sender. + client (Client): Message sender. message (bytes): Message. """ - self.message.emit(device, message) + self.message.emit(client, message) - @Slot(Device) - def on_disconnected(self, device: Device): - """Called when device disconnects from server. + @Slot(Client) + def on_disconnected(self, client: Client): + """Called when client disconnects from server. Emits disconnected signal. Args: - device (Device): Disconnected device. + client (Client): Disconnected client. """ - self.disconnected.emit(device) + self.disconnected.emit(client) - @Slot(Device, Exception) - def on_device_error(self, device: Device, error: Exception): + @Slot(Client, Exception) + def on_client_error(self, client: Client, error: Exception): """Called when server error occurs. Emits error signal. Args: - device (Device): Device object. + client (Client): Client object. error (Exception): Exception object. """ - self.client_error.emit(device, error) + self.client_error.emit(client, error) @Slot(Exception) def on_server_error(self, error: Exception): @@ -122,11 +123,30 @@ def on_server_error(self, error: Exception): def on_closed(self): self.closed.emit() + @Slot(Client, bytes) + def write(self, client: Client, message: bytes): + """Sends message to client. + + Args: + client (Client): Client object. + message (bytes): Message. + """ + self.balancer.write(client.id(), message) + + @Slot(bytes) + def write_all(self, message: bytes): + """Sends message to all clients. + + Args: + message (bytes): Message. + """ + self.balancer.write_all(message) + @Slot(int) - def get_device_by_id(self, device_id: int): - for device in self.devices: - if device.id() == device_id: - return device + def get_client_by_id(self, client_id: int): + for client in self.clients: + if client.id() == client_id: + return client @Slot() def is_running(self) -> bool: @@ -247,12 +267,12 @@ def close(self): # @Slot(int, bytes) # def __on_handler_device_message(self, device_id: int, message: bytes): # """When server receives message from bot.""" -# self.on_message(self.get_device_by_id(device_id), message) +# self.on_message(self.get_client_by_id(device_id), message) # # @Slot(int) # def __on_handler_device_disconnected(self, device_id): # """When bot disconnects from server.""" -# device = self.get_device_by_id(device_id) +# device = self.get_client_by_id(device_id) # device.set_connected(False) # if device in self.__devices: # self.__devices.remove(device) @@ -260,7 +280,7 @@ def close(self): # # @Slot(int, str) # def __on_handler_device_error(self, device_id, error): -# self.on_error(self.get_device_by_id(device_id), error) +# self.on_error(self.get_client_by_id(device_id), error) # # @Slot(Device, str, int) # def on_connected(self, device: Device, ip: str, port: int): @@ -321,7 +341,7 @@ def close(self): # # @Slot(bytes) # def write_all(self, data: bytes): -# """Write data to all devices.""" +# """Write data to all clients.""" # if not self.__server or not self.__handler: # raise ServerNotRunning("Server is not running") # self.__handler.write_all.emit(data) @@ -377,7 +397,7 @@ def close(self): # return True # # @Slot(int) -# def get_device_by_id(self, device_id: int) -> Device: +# def get_client_by_id(self, device_id: int) -> Device: # """Returns device with associated ID. # # Args: @@ -389,7 +409,7 @@ def close(self): # raise Exception("CLIENT-{} not found".format(device_id)) # # def get_devices(self): -# """Returns list with devices.""" +# """Returns list with clients.""" # return self.__devices # # def set_handler_class(self, handler): diff --git a/examples2/client.py b/examples2/client.py index 6199739..6d41eb1 100644 --- a/examples2/client.py +++ b/examples2/client.py @@ -19,7 +19,7 @@ def setup(self): self.logger = logging.getLogger(self.__class__.__name__) self.cln = QThreadedClient() - # self.cln.message.connect(self.client_data_received) + self.cln.message.connect(self.on_message) self.cln.connected.connect(self.on_connected) self.cln.failed_to_connect.connect(self.close) self.cln.disconnected.connect(self.close) @@ -30,6 +30,10 @@ def on_connected(self, ip: str, port: int): self.logger.info(f"Connected to {ip}:{port}") self.cln.write(b"Kick me plz") + @Slot(bytes) + def on_message(self, data: bytes): + self.logger.info(f"Received: {data}") + @Slot() def close(self): self.cln.close() diff --git a/examples2/no_balancer.py b/examples2/no_balancer.py index 7ef25ee..3be3c2d 100644 --- a/examples2/no_balancer.py +++ b/examples2/no_balancer.py @@ -7,7 +7,7 @@ from QtPyNetwork2.server import TCPServer from QtPyNetwork2.balancers import NoBalancer -from QtPyNetwork2.models import Device +from QtPyNetwork2.models import Client IP = "127.0.0.1" PORT = 12500 @@ -19,17 +19,22 @@ def __init__(self): super(Main, self).__init__(None) self.logger = logging.getLogger(self.__class__.__name__) - self.balancer = NoBalancer() - self.server = TCPServer(self.balancer) - self.server.connected.connect(lambda client, ip, port: print(ip, port)) + self.server = TCPServer(NoBalancer()) + self.server.connected.connect(self.on_client_connected) self.server.disconnected.connect(lambda client: print(f"Client disconnected: {client.id()}")) self.server.message.connect(lambda client, data: print(f"Received data from client {client.id()}: {data}")) # self.server.disconnected.connect(self.on_disconnected) # self.server.message.connect(self.on_message) + @Slot() def start(self): self.server.start(IP, PORT) + @Slot(Client, str, int) + def on_client_connected(self, client, ip, port): + print(f"Hello new client! {client.id()} - {ip}:{port}") + client.write(b"Hello from server") + # @Slot(Device, bytes) # def on_message(self, device, message: bytes): # self.logger.info("Received {}: {}".format(device.id(), message))