class RelayInterface: """ Component that is responsible for every interaction with the Mesh Relay. It achieves this through the use of websockets. This component runs concurrently to the main program, similiar to Listener or Sender. """ def __init__(self, crypto, relay_address, uid): self.crypto = crypto self.relay_address = relay_address self.uid = uid def start(self, parser): """Start the relay sender and Listener""" self.parser = parser self.sender = RelaySender() self.launch_listener_thread() def send(self, uid, msg): """Send a message on the mesh relay""" return self.sender.send(uid, msg) def connect_to_relay(self): """This runs the connection protocol""" self.relay = asyncio.get_event_loop().run_until_complete(self.get_mesh_relay(self.relay_address, self.uid)) self.sender.relay_socket = self.relay # Send a subscription self.sender.send() def launch_listener_thread(self): """Daemonizes and launches the concurrent listener""" # self.serve_forever() listener_thread = threading.Thread(target=self.serve_forever) listener_thread.daemon = True listener_thread.start() def serve_forever(self): """Serves the Receiver loop until the program completes""" loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) self.connect_to_relay() asyncio.get_event_loop().run_until_complete(self.receive()) @asyncio.coroutine def get_mesh_relay(self, relay_address, uid): """Connect to the mesh relay and return the active connection""" result = yield from websockets.connect("ws://{0}?uid={1}".format(relay_address, uid)) return result @asyncio.coroutine def receive(self): """Run a receive loop forever""" while True: try: # Wait until we get data from the relay server recved = yield from self.relay.recv() relay_msg = json.loads(recved) self.handle_message(relay_msg) except websockets.exceptions.ConnectionClosed: """In the event of a relay closing the connection erroneously (rails issue?), reconnect to the relay immediately.""" self.connect_to_relay() continue def handle_message(self, relay_msg): """Check validity of payload, then decrypt if we can""" # Validate that the message is appropriate if "message" in relay_msg and "type" not in relay_msg and "message" in relay_msg["message"]: try: to_decrypt = json.dumps(relay_msg["message"]).encode() decrypted = self.crypto.decrypt(to_decrypt) self.parser.handle_message(decrypted) except Exception as msg: Display.warn("Warning: General decryption failure\n\n{0}".format(msg))
def start(self, parser): """Start the relay sender and Listener""" self.parser = parser self.sender = RelaySender() self.launch_listener_thread()