def __init__(self, logger, identifier, welcome_message, max_paste_time, *args): self.logger = logger self.identifier = identifier self.welcome_message = welcome_message self.max_paste_time = max_paste_time self.server = Server(logger, *args) self.server.connect_handler.bind(self.client_connected) self.server.disconnect_handler.bind(self.client_disconnected) self.server.data_handler.bind(self.identify_package) self.packager = DataPackager(logger) self.paste_requests = Queue() self.paste_request_processor_running = threading.Event() self.paste_request_received = threading.Event() self.paste_received = threading.Event() self.paste_permission_holder = None self.client_list = dict()
def __init__(self, logger, *args): self.logger = logger self.client = Client(logger, *args) self.client.data_handler.bind(self.identify_package) self.packager = DataPackager(logger)
class ChatServer(object): def __init__(self, logger, identifier, welcome_message, max_paste_time, *args): self.logger = logger self.identifier = identifier self.welcome_message = welcome_message self.max_paste_time = max_paste_time self.server = Server(logger, *args) self.server.connect_handler.bind(self.client_connected) self.server.disconnect_handler.bind(self.client_disconnected) self.server.data_handler.bind(self.identify_package) self.packager = DataPackager(logger) self.paste_requests = Queue() self.paste_request_processor_running = threading.Event() self.paste_request_received = threading.Event() self.paste_received = threading.Event() self.paste_permission_holder = None self.client_list = dict() @property def running(self): return self.server.server_running.is_set() def _get_client_address(self, client): return self.server.all_clients[client] def _get_client_nickname(self, client): return self.client_list[client] def _get_client_list(self): return filter(lambda x: x != self.identifier, self.client_list.values()) def _broadcast_package(self, package, sender): nickname = self._get_client_nickname(sender) outgoing_package = self.packager.add_sender_to_package(package, nickname) for client in self.server.all_clients: if client not in [self.server(), sender]: try: self.server.send_to(client, outgoing_package) except ConnectionBroken: self.client_disconnected(client) self.logger.error('Broadcasting to {0} failed.'.format(nickname)) def _broadcast_client_list(self): client_list_package = self.packager.make_client_list_package(self._get_client_list()) self._broadcast_package(client_list_package, self.server()) self.logger.debug('Client list broadcasted: {0}'.format(str(client_list_package))) def _receive_identification(self, new_client): try: self.logger.info('Identification started.') id_package = self.server.receive_from(new_client) self.logger.debug('Identification package received: {0}'.format(str(id_package))) return self.packager.identify_client(id_package) except ConnectionBroken: raise ClientIdentificationFailed def client_connected(self, new_client): try: nickname = self._receive_identification(new_client) self.client_list[new_client] = nickname except ClientIdentificationFailed: self.logger.info('Client identification failed.') self.server.disconnect_client(new_client) return welcome_package = self.packager.make_message_package(self.welcome_message) welcome_package = self.packager.add_sender_to_package(welcome_package, self.identifier) try: self.server.send_to(new_client, welcome_package) self.logger.debug('Welcome message sent: {0}'.format(str(welcome_package))) except ConnectionBroken: self.logger.info('Welcome message sending failed, connection broken.') self.server.disconnect_client(new_client) self.client_list.pop(new_client, None) return self._broadcast_client_list() address = self._get_client_address(new_client) message = '{0} joined from {1}:{2}'.format(nickname, address[0], address[1]) inform_package = self.packager.make_message_package(message) self._broadcast_package(inform_package, self.server()) self.logger.debug(message) def client_disconnected(self, disconnected_client): nickname = self._get_client_nickname(disconnected_client) self.server.disconnect_client(disconnected_client) self.client_list.pop(disconnected_client, None) self._broadcast_client_list() message = '{0} left.'.format(nickname) inform_package = self.packager.make_message_package(message) self._broadcast_package(inform_package, self.server()) self.logger.debug(message) def _broadcast_paste_permission(self, nickname): paste_permission_package = self.packager.make_paste_notification_package(nickname) self._broadcast_package(paste_permission_package, self.server()) self.logger.debug('Paste permission broadcasted: {0}'.format(str(paste_permission_package))) def _paste_request_processor(self): self.logger.info('Paste request processor started.') while self.running: try: requester_client = self.paste_requests.get(False) package = self.packager.make_paste_granted_package() package = self.packager.add_sender_to_package(package, self.identifier) nickname = self._get_client_nickname(requester_client) try: self.paste_received.clear() self.paste_permission_holder = requester_client self.server.send_to(requester_client, package) self.logger.debug('Paste request granted to: {0} for {1}s'.format(nickname, self.max_paste_time)) self._broadcast_paste_permission(nickname) self.paste_received.wait(self.max_paste_time) except ConnectionBroken: self.logger.debug('Paste request permission sending failed to: {0}'.format(nickname)) except QueueEmpty: self.paste_permission_holder = None self.paste_request_received.clear() self.paste_request_received.wait() self.paste_request_processor_running.set() def identify_package(self, sender_client, package): try: package_type, _package_data = self.packager.process_package(package, False) except PackageVerificationFailed: self.logger.error('Package verification failed: {0}'.format(str(package))) return if package_type == PKG_PASTE_REQUEST: self.paste_requests.put(sender_client) self.paste_request_received.set() return elif package_type == PKG_PASTE: if sender_client != self.paste_permission_holder: self.logger.info('This paste has timed out, and will be ignored.') return self.paste_received.set() self._broadcast_package(package, sender_client) def host(self, port): server_address = self.server.host(port) self.client_list[self.server()] = self.identifier paste_request_thread = threading.Thread(target=self._paste_request_processor) paste_request_thread.start() return server_address def close_server(self): self.paste_request_processor_running.clear() self.server.close_server() self.paste_request_received.set() self.paste_request_processor_running.wait()
class ChatClient(object): message_handler = EventHandler() paste_handler = EventHandler() client_list_handler = EventHandler() paste_granted_handler = EventHandler() paste_notification_handler = EventHandler() def __init__(self, logger, *args): self.logger = logger self.client = Client(logger, *args) self.client.data_handler.bind(self.identify_package) self.packager = DataPackager(logger) @property def connected(self): return self.client.connected.is_set() def connect(self, address, nickname): self.client.connect(address) try: id_package = self.packager.make_id_package(nickname) self.client.send(id_package) self.logger.debug("Sent identification: {0}".format(str(id_package))) except ConnectionBroken: self.client.disconnect() self.logger.info("Server rejected client identification.") raise def disconnect(self): self.client.disconnect() def identify_package(self, package): package_handlers = { PKG_MESSAGE: self.message_handler, PKG_PASTE: self.paste_handler, PKG_CLIENT_LIST: self.client_list_handler, PKG_PASTE_GRANTED: self.paste_granted_handler, PKG_PASTE_NOTIFICATION: self.paste_notification_handler, } try: package_type, package_sender, package_data = self.packager.process_package(package) self.logger.debug( "Package processed as: {0} from {1} - {2}".format(package_type, package_sender, str(package_data)) ) handler = package_handlers[package_type] handler(package_sender, package_data) self.logger.info("Package handled successfully.") except PackageVerificationFailed: self.logger.error("Package verification failed: {0}".format(str(package))) def send_package(self, package): if not self.connected: raise ConnectionBroken self.client.send(package) self.logger.debug("Package sent to {0} with: {1}".format(self.client().getpeername(), str(package))) def send_message(self, message): package = self.packager.make_message_package(message) self.send_package(package) def send_paste(self, paste_data): package = self.packager.make_paste_package(paste_data) self.send_package(package) def send_paste_request(self): package = self.packager.make_paste_request_package() self.send_package(package)