def client(destination_hexhash, configpath): # We need a binary representation of the destination # hash that was entered on the command line try: if len(destination_hexhash) != 20: raise ValueError( "Destination length is invalid, must be 20 hexadecimal characters (10 bytes)" ) destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") exit() # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # Check if we know a path to the destination if not RNS.Transport.has_path(destination_hash): RNS.log( "Destination is not yet known. Requesting path and waiting for announce to arrive..." ) RNS.Transport.request_path(destination_hash) while not RNS.Transport.has_path(destination_hash): time.sleep(0.1) # Recall the server identity server_identity = RNS.Identity.recall(destination_hash) # Inform the user that we'll begin connecting RNS.log("Establishing link with server...") # When the server identity is known, we set # up a destination server_destination = RNS.Destination(server_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "filetransfer", "server") # We also want to automatically prove incoming packets server_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) # And create a link link = RNS.Link(server_destination) # We expect any normal data packets on the link # to contain a list of served files, so we set # a callback accordingly link.set_packet_callback(filelist_received) # We'll also set up functions to inform the # user when the link is established or closed link.set_link_established_callback(link_established) link.set_link_closed_callback(link_closed) # And set the link to automatically begin # downloading advertised resources link.set_resource_strategy(RNS.Link.ACCEPT_ALL) link.set_resource_started_callback(download_began) link.set_resource_concluded_callback(download_concluded) menu()
def client(destination_hexhash, configpath): # We need a binary representation of the destination # hash that was entered on the command line try: if len(destination_hexhash) != 20: raise ValueError("Destination length is invalid, must be 20 hexadecimal characters (10 bytes)") destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") exit() # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) # Check if we know a path to the destination if not RNS.Transport.has_path(destination_hash): RNS.log("Destination is not yet known. Requesting path and waiting for announce to arrive...") RNS.Transport.request_path(destination_hash) while not RNS.Transport.has_path(destination_hash): time.sleep(0.1) # Recall the server identity server_identity = RNS.Identity.recall(destination_hash) # Inform the user that we'll begin connecting RNS.log("Establishing link with server...") # When the server identity is known, we set # up a destination server_destination = RNS.Destination( server_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "linkexample" ) # And create a link link = RNS.Link(server_destination) # We set a callback that will get executed # every time a packet is received over the # link link.set_packet_callback(client_packet_received) # We'll also set up functions to inform the # user when the link is established or closed link.set_link_established_callback(link_established) link.set_link_closed_callback(link_closed) # Everything is set up, so let's enter a loop # for the user to interact with the example client_loop()
def process_outbound(self, sender=None): if self.processing_outbound: return for lxmessage in self.pending_outbound: if lxmessage.state == LXMessage.DELIVERED: RNS.log( "Delivery has occurred for " + str(lxmessage) + ", removing from outbound queue", RNS.LOG_DEBUG) self.pending_outbound.remove(lxmessage) else: RNS.log( "Starting outbound processing for " + str(lxmessage) + " to " + RNS.prettyhexrep(lxmessage.get_destination().hash), RNS.LOG_DEBUG) # Outbound handling for opportunistic messages if lxmessage.method == LXMessage.OPPORTUNISTIC: if lxmessage.delivery_attempts <= LXMRouter.MAX_DELIVERY_ATTEMPTS: if not hasattr( lxmessage, "next_delivery_attempt" ) or time.time() > lxmessage.next_delivery_attempt: lxmessage.delivery_attempts += 1 lxmessage.next_delivery_attempt = time.time( ) + LXMRouter.DELIVERY_RETRY_WAIT RNS.log( "Opportunistic delivery attempt " + str(lxmessage.delivery_attempts) + " for " + str(lxmessage) + " to " + RNS.prettyhexrep( lxmessage.get_destination().hash), RNS.LOG_DEBUG) lxmessage.send() else: RNS.log( "Max delivery attempts reached for oppertunistic " + str(lxmessage) + " to " + RNS.prettyhexrep(lxmessage.get_destination().hash), RNS.LOG_DEBUG) self.fail_message(lxmessage) # Outbound handling for messages transferred # over a direct link to the final recipient elif lxmessage.method == LXMessage.DIRECT: if lxmessage.delivery_attempts <= LXMRouter.MAX_DELIVERY_ATTEMPTS: delivery_destination_hash = lxmessage.get_destination( ).hash if delivery_destination_hash in self.direct_links: # A link already exists, so we'll try to use it # to deliver the message direct_link = self.direct_links[ delivery_destination_hash] if direct_link.status == RNS.Link.ACTIVE: if lxmessage.state != LXMessage.SENDING: RNS.log( "Starting transfer of " + str(lxmessage) + " to " + RNS.prettyhexrep( lxmessage.get_destination().hash), RNS.LOG_DEBUG) lxmessage.set_delivery_destination( direct_link) lxmessage.send() else: RNS.log( "The transfer of " + str(lxmessage) + " is in progress (" + str(round(lxmessage.progress * 100, 1)) + "%)", RNS.LOG_DEBUG) elif direct_link.status == RNS.Link.CLOSED: RNS.log( "The link to " + RNS.prettyhexrep( lxmessage.get_destination().hash) + " was closed", RNS.LOG_DEBUG) lxmessage.set_delivery_destination(None) self.direct_links.pop( delivery_destination_hash) lxmessage.next_delivery_attempt = time.time( ) + LXMRouter.DELIVERY_RETRY_WAIT else: # Simply wait for the link to become # active or close RNS.log( "The link to " + RNS.prettyhexrep( lxmessage.get_destination().hash) + " is pending, waiting for link to become active", RNS.LOG_DEBUG) else: # No link exists, so we'll try to establish one, but # only if we've never tried before, or the retry wait # period has elapsed. if not hasattr( lxmessage, "next_delivery_attempt" ) or time.time() > lxmessage.next_delivery_attempt: lxmessage.delivery_attempts += 1 lxmessage.next_delivery_attempt = time.time( ) + LXMRouter.DELIVERY_RETRY_WAIT if lxmessage.delivery_attempts < LXMRouter.MAX_DELIVERY_ATTEMPTS: if RNS.Transport.has_path( lxmessage.get_destination().hash): RNS.log( "Establishing link to " + RNS.prettyhexrep( lxmessage.get_destination( ).hash) + " for delivery attempt " + str(lxmessage.delivery_attempts) + " to " + RNS.prettyhexrep( lxmessage.get_destination( ).hash), RNS.LOG_DEBUG) delivery_link = RNS.Link( lxmessage.get_destination()) delivery_link.set_link_established_callback( self.process_outbound) self.direct_links[ delivery_destination_hash] = delivery_link else: RNS.log( "No path known for delivery attempt " + str(lxmessage.delivery_attempts) + " to " + RNS.prettyhexrep( lxmessage.get_destination(). hash) + ". Requesting path...", RNS.LOG_DEBUG) RNS.Transport.request_path( lxmessage.get_destination().hash) else: RNS.log( "Max delivery attempts reached for direct " + str(lxmessage) + " to " + RNS.prettyhexrep(lxmessage.get_destination().hash), RNS.LOG_DEBUG) self.fail_message(lxmessage) # Outbound handling for messages transported via # propagation to a LXMF router network. elif lxmessage.method == LXMessage.PROPAGATED: RNS.log( "Attempting propagated delivery for " + str(lxmessage) + " to " + RNS.prettyhexrep(lxmessage.get_destination().hash), RNS.LOG_DEBUG) raise NotImplementedError( "LXMF propagation is not implemented yet")
def __load(self): # If an established link exists, but it doesn't match the target # destination, we close and clear it. if self.link != None and self.link.destination.hash != self.destination_hash: self.link.teardown() self.link = None # If no link to the destination exists, we create one. if self.link == None: if not RNS.Transport.has_path(self.destination_hash): self.status = Browser.NO_PATH self.update_display() RNS.Transport.request_path(self.destination_hash) self.status = Browser.PATH_REQUESTED self.update_display() pr_time = time.time() while not RNS.Transport.has_path(self.destination_hash): now = time.time() if now > pr_time + self.timeout: self.request_timeout() return time.sleep(0.25) self.status = Browser.ESTABLISHING_LINK self.update_display() identity = RNS.Identity.recall(self.destination_hash) destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, self.app_name, self.aspects) self.link = RNS.Link(destination, established_callback=self.link_established, closed_callback=self.link_closed) while self.status == Browser.ESTABLISHING_LINK: time.sleep(0.1) if self.status != Browser.LINK_ESTABLISHED: return self.update_display() # Send the request self.status = Browser.REQUESTING self.response_progress = 0 self.response_size = None self.response_transfer_size = None self.saved_file_name = None self.update_display() receipt = self.link.request(self.path, data=None, response_callback=self.response_received, failed_callback=self.request_failed, progress_callback=self.response_progressed) if receipt: self.last_request_receipt = receipt self.last_request_id = receipt.request_id self.status = Browser.REQUEST_SENT self.update_display() else: self.link.teardown()