async def _handle_subscribe(self) -> Subscription: Log.debug('[Server] New sub requested') # Subscribe ACK await protocol.send_packet(self._writer, protocol.Commands.SUBSCRIBE_ACK) # Subscribe 'topic' packet = await protocol.read_packet(self._reader) if not await protocol.async_cmd_ok(packet, protocol.Commands.SUBSCRIBE, self._writer): return None topic = packet.data.decode('utf-8') # Ensure topic is OK according to the format required. if not protocol.topic_ok(topic): Log.debug(f'[Server] Sub -> Topic "{topic}" is incorrect format.') return None # Subscribe OK await protocol.send_packet(self._writer, protocol.Commands.SUBSCRIBE_OK) sub = Subscription(topic, self._reader, self._writer) Log.info(f'[Server] New sub -> {sub}') return sub
async def _handle_publish(self) -> Publication: # Log.debug('Server: PUB') # Send: Publish ACK await protocol.send_packet(self._writer, protocol.Commands.PUBLISH_ACK) # Receive: Publish + Data ('topic' | 'message') packet = await protocol.read_packet(self._reader) if not await protocol.async_cmd_ok(packet, protocol.Commands.PUBLISH, self._writer): return data = packet.data.decode('utf-8') # Ensure publish is OK according to the format required. if not protocol.publish_ok(data): Log.debug(f'[Server] Pub -> Publish "{data}" is incorrect format.') await protocol.send_packet(self._writer, protocol.Commands.INCORRECT_FORMAT) return None # Publish OK await protocol.send_packet(self._writer, protocol.Commands.PUBLISH_OK) topic, message = protocol.get_topic_and_msg(data) publication = Publication(topic, message) fd = self._writer.get_extra_info('socket').fileno() Log.info(f'[Server] New Pub: "{fd}: {publication}"') return publication
async def subscribe(self, topic: str, data_received: callable = None) -> None: """ Throws ConnectionRefusedError. """ sub = AsyncSubscribe(self._ip, self._port, data_received) Log.info(f'[Client] Subscribing to "{topic}"') await sub.start(topic)
async def start(self) -> None: """ Starts the server. This method runs forever. """ server = await asyncio.start_server(self._request_handler, self._ip, self._port) ip, port = server.sockets[0].getsockname() Log.info(f'{NAME} Server started at {ip} on port {port}') async with server: await asyncio.gather(self._make_pings_task(), self._make_publications_task(), server.serve_forever())
async def publish(self, topic: str, message: str) -> bool: """ Returns if the publish is succesful or not. Throws ConnectionRefusedError. """ publish = AsyncPublish(self._ip, self._port) try: pub_ok = await publish.start(topic, message) except ConnectionRefusedError: Log.err(f'[Client ]Failed to connect to server {self._ip} ' f'on port {self._port}') return if pub_ok: Log.info(f'[Client] Published "{message}" to topic "{topic}"') else: Log.info(f'[Client] Failed to publish "{message}" to' f' topic "{topic}"') return pub_ok
def _save_config(config: dict) -> None: Log.info(f'Saving configuration file at {CONFIG_PATH}') with open(CONFIG_PATH, 'w') as f: json.dump(config, f)