From 8e207d806abfa231b4993ae2ea63cc9ec1bdfd0e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Oct 2024 10:44:18 +0200 Subject: [PATCH 1/2] modernize --- Examples/Announce.py | 14 +- Examples/Broadcast.py | 6 +- Examples/Buffer.py | 16 +- Examples/Channel.py | 23 +- Examples/Echo.py | 45 ++-- Examples/Filetransfer.py | 38 ++-- Examples/Identify.py | 25 +-- Examples/Link.py | 20 +- Examples/Minimal.py | 6 +- Examples/Ratchets.py | 45 ++-- Examples/Request.py | 18 +- Examples/Speedtest.py | 28 ++- RNS/Buffer.py | 8 +- RNS/Channel.py | 28 +-- RNS/Cryptography/Fernet.py | 4 +- RNS/Cryptography/HMAC.py | 8 +- RNS/Cryptography/PKCS7.py | 2 +- RNS/Cryptography/Provider.py | 2 +- RNS/Cryptography/SHA256.py | 6 +- RNS/Cryptography/SHA512.py | 6 +- RNS/Cryptography/__init__.py | 2 +- RNS/Cryptography/aes/aes.py | 6 +- RNS/Cryptography/pure25519/basic.py | 4 +- RNS/Cryptography/pure25519/ed25519_oop.py | 6 +- RNS/Cryptography/pure25519/eddsa.py | 6 +- RNS/Destination.py | 30 +-- RNS/Identity.py | 66 +++--- RNS/Interfaces/AX25KISSInterface.py | 42 ++-- RNS/Interfaces/Android/KISSInterface.py | 46 ++-- RNS/Interfaces/Android/RNodeInterface.py | 186 +++++++-------- RNS/Interfaces/Android/SerialInterface.py | 30 +-- RNS/Interfaces/Android/__init__.py | 2 +- RNS/Interfaces/AutoInterface.py | 72 +++--- RNS/Interfaces/I2PInterface.py | 126 +++++------ RNS/Interfaces/Interface.py | 8 +- RNS/Interfaces/KISSInterface.py | 38 ++-- RNS/Interfaces/LocalInterface.py | 28 +-- RNS/Interfaces/PipeInterface.py | 24 +- RNS/Interfaces/RNodeInterface.py | 128 +++++------ RNS/Interfaces/RNodeMultiInterface.py | 138 ++++++------ RNS/Interfaces/SerialInterface.py | 22 +- RNS/Interfaces/TCPInterface.py | 48 ++-- RNS/Interfaces/UDPInterface.py | 4 +- RNS/Interfaces/__init__.py | 2 +- RNS/Link.py | 74 +++--- RNS/Packet.py | 20 +- RNS/Resource.py | 50 ++--- RNS/Reticulum.py | 70 +++--- RNS/Transport.py | 262 +++++++++++----------- RNS/Utilities/__init__.py | 2 +- RNS/Utilities/rncp.py | 134 +++++------ RNS/Utilities/rnid.py | 132 +++++------ RNS/Utilities/rnir.py | 2 +- RNS/Utilities/rnodeconf.py | 58 ++--- RNS/Utilities/rnpath.py | 58 ++--- RNS/Utilities/rnprobe.py | 38 ++-- RNS/Utilities/rnsd.py | 6 +- RNS/Utilities/rnstatus.py | 18 +- RNS/Utilities/rnx.py | 86 +++---- RNS/__init__.py | 20 +- RNS/vendor/__init__.py | 2 +- RNS/vendor/configobj.py | 120 +++++----- RNS/vendor/i2plib/aiosam.py | 12 +- RNS/vendor/i2plib/sam.py | 28 +-- RNS/vendor/i2plib/tunnel.py | 9 +- RNS/vendor/i2plib/utils.py | 2 +- RNS/vendor/ifaddr/__init__.py | 2 +- RNS/vendor/ifaddr/_posix.py | 2 +- RNS/vendor/ifaddr/_shared.py | 12 +- RNS/vendor/ifaddr/niwrapper.py | 2 +- RNS/vendor/six.py | 55 +++-- RNS/vendor/umsgpack.py | 70 +++--- docs/source/conf.py | 4 +- setup.py | 6 +- tests/channel.py | 6 +- tests/hashes.py | 24 +- tests/identity.py | 30 +-- tests/link.py | 80 +++---- 78 files changed, 1418 insertions(+), 1490 deletions(-) diff --git a/Examples/Announce.py b/Examples/Announce.py index 69c94cb..5b0a3af 100644 --- a/Examples/Announce.py +++ b/Examples/Announce.py @@ -93,9 +93,7 @@ def announceLoop(destination_1, destination_2): # Send the announce including the app data destination_1.announce(app_data=fruit.encode("utf-8")) RNS.log( - "Sent announce from "+ - RNS.prettyhexrep(destination_1.hash)+ - " ("+destination_1.name+")" + f"Sent announce from {RNS.prettyhexrep(destination_1.hash)} ({destination_1.name})" ) # Randomly select a noble gas @@ -104,9 +102,7 @@ def announceLoop(destination_1, destination_2): # Send the announce including the app data destination_2.announce(app_data=noble_gas.encode("utf-8")) RNS.log( - "Sent announce from "+ - RNS.prettyhexrep(destination_2.hash)+ - " ("+destination_2.name+")" + f"Sent announce from {RNS.prettyhexrep(destination_2.hash)} ({destination_2.name})" ) # We will need to define an announce handler class that @@ -126,14 +122,12 @@ class ExampleAnnounceHandler: # and cannot use wildcards. def received_announce(self, destination_hash, announced_identity, app_data): RNS.log( - "Received an announce from "+ - RNS.prettyhexrep(destination_hash) + f"Received an announce from {RNS.prettyhexrep(destination_hash)}" ) if app_data: RNS.log( - "The announce contained the following app data: "+ - app_data.decode("utf-8") + f"The announce contained the following app data: {app_data.decode('utf-8')}" ) ########################################################## diff --git a/Examples/Broadcast.py b/Examples/Broadcast.py index 76acc70..423d759 100644 --- a/Examples/Broadcast.py +++ b/Examples/Broadcast.py @@ -48,15 +48,13 @@ def program_setup(configpath, channel=None): def packet_callback(data, packet): # Simply print out the received data print("") - print("Received data: "+data.decode("utf-8")+"\r\n> ", end="") + print(f"Received data: {data.decode('utf-8')}\r\n> ", end="") sys.stdout.flush() def broadcastLoop(destination): # Let the user know that everything is ready RNS.log( - "Broadcast example "+ - RNS.prettyhexrep(destination.hash)+ - " running, enter text and hit enter to broadcast (Ctrl-C to quit)" + f"Broadcast example {RNS.prettyhexrep(destination.hash)} running, enter text and hit enter to broadcast (Ctrl-C to quit)" ) # We enter a loop that runs until the users exits. diff --git a/Examples/Buffer.py b/Examples/Buffer.py index 6805184..7d26ce1 100644 --- a/Examples/Buffer.py +++ b/Examples/Buffer.py @@ -61,9 +61,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Link buffer example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Link buffer example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -75,7 +73,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -120,9 +118,9 @@ def server_buffer_ready(ready_bytes: int): data = latest_buffer.read(ready_bytes) data = data.decode("utf-8") - RNS.log("Received data over the buffer: " + data) + RNS.log(f"Received data over the buffer: {data}") - reply_message = "I received \""+data+"\" over the buffer" + reply_message = f"I received \"{data}\" over the buffer" reply_message = reply_message.encode("utf-8") latest_buffer.write(reply_message) latest_buffer.flush() @@ -151,7 +149,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -223,7 +221,7 @@ def client_loop(): except Exception as e: - RNS.log("Error while sending data over the link buffer: "+str(e)) + RNS.log(f"Error while sending data over the link buffer: {e}") should_quit = True server_link.teardown() @@ -262,7 +260,7 @@ def link_closed(link): def client_buffer_ready(ready_bytes: int): global buffer data = buffer.read(ready_bytes) - RNS.log("Received data over the link buffer: " + data.decode("utf-8")) + RNS.log(f"Received data over the link buffer: {data.decode('utf-8')}") print("> ", end=" ") sys.stdout.flush() diff --git a/Examples/Channel.py b/Examples/Channel.py index c4ce315..b1c6b39 100644 --- a/Examples/Channel.py +++ b/Examples/Channel.py @@ -124,9 +124,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Link example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Link example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -138,7 +136,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -176,9 +174,9 @@ def server_message_received(message): # # if isinstance(message, StringMessage): - RNS.log("Received data on the link: " + message.data + " (message created at " + str(message.timestamp) + ")") + RNS.log(f"Received data on the link: {message.data} (message created at {message.timestamp})") - reply_message = StringMessage("I received \""+message.data+"\" over the link") + reply_message = StringMessage(f"I received \"{message.data}\" over the link") latest_client_link.get_channel().send(reply_message) # Incoming messages are sent to each message @@ -206,7 +204,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -280,17 +278,14 @@ def client_loop(): channel.send(message) else: RNS.log( - "Cannot send this packet, the data size of "+ - str(packed_size)+" bytes exceeds the link packet MDU of "+ - str(channel.MDU)+" bytes", + f"Cannot send this packet, the data size of {packed_size} bytes exceeds the link packet MDU of {channel.MDU} bytes", RNS.LOG_ERROR ) else: - RNS.log("Channel is not ready to send, please wait for " + - "pending messages to complete.", RNS.LOG_ERROR) + RNS.log(f"Channel is not ready to send, please wait for pending messages to complete.", RNS.LOG_ERROR) except Exception as e: - RNS.log("Error while sending data over the link: "+str(e)) + RNS.log(f"Error while sending data over the link: {e}") should_quit = True server_link.teardown() @@ -329,7 +324,7 @@ def link_closed(link): # simply print out the data. def client_message_received(message): if isinstance(message, StringMessage): - RNS.log("Received data on the link: " + message.data + " (message created at " + str(message.timestamp) + ")") + RNS.log(f"Received data on the link: {message.data} (message created at {message.timestamp})") print("> ", end=" ") sys.stdout.flush() diff --git a/Examples/Echo.py b/Examples/Echo.py index e5b3930..ed377b2 100644 --- a/Examples/Echo.py +++ b/Examples/Echo.py @@ -64,9 +64,7 @@ def server(configpath): def announceLoop(destination): # Let the user know that everything is ready RNS.log( - "Echo server "+ - RNS.prettyhexrep(destination.hash)+ - " running, hit enter to manually send an announce (Ctrl-C to quit)" + f"Echo server {RNS.prettyhexrep(destination.hash)} running, hit enter to manually send an announce (Ctrl-C to quit)" ) # We enter a loop that runs until the users exits. @@ -76,7 +74,7 @@ def announceLoop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") def server_callback(message, packet): @@ -93,19 +91,19 @@ def server_callback(message, packet): reception_snr = reticulum.get_packet_snr(packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dBm]" + reception_stats += f" [SNR {reception_snr} dBm]" else: if packet.rssi != None: - reception_stats += " [RSSI "+str(packet.rssi)+" dBm]" + reception_stats += f" [RSSI {packet.rssi} dBm]" if packet.snr != None: - reception_stats += " [SNR "+str(packet.snr)+" dB]" + reception_stats += f" [SNR {packet.snr} dB]" - RNS.log("Received packet from echo client, proof sent"+reception_stats) + RNS.log(f"Received packet from echo client, proof sent{reception_stats}") ########################################################## @@ -123,13 +121,13 @@ def client(destination_hexhash, configpath, timeout=None): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: RNS.log("Invalid destination entered. Check your input!") - RNS.log(str(e)+"\n") + RNS.log(f"{e}\n") exit() # We must first initialise Reticulum @@ -142,9 +140,7 @@ def client(destination_hexhash, configpath, timeout=None): # Tell the user that the client is ready! RNS.log( - "Echo client ready, hit enter to send echo request to "+ - destination_hexhash+ - " (Ctrl-C to quit)" + f"Echo client ready, hit enter to send echo request to {destination_hexhash} (Ctrl-C to quit)" ) # We enter a loop that runs until the user exits. @@ -205,7 +201,7 @@ def client(destination_hexhash, configpath, timeout=None): packet_receipt.set_delivery_callback(packet_delivered) # Tell the user that the echo request was sent - RNS.log("Sent echo request to "+RNS.prettyhexrep(request_destination.hash)) + RNS.log(f"Sent echo request to {RNS.prettyhexrep(request_destination.hash)}") else: # If we do not know this destination, tell the # user to wait for an announce to arrive. @@ -222,10 +218,10 @@ def packet_delivered(receipt): rtt = receipt.get_rtt() if (rtt >= 1): rtt = round(rtt, 3) - rttstring = str(rtt)+" seconds" + rttstring = f"{rtt} seconds" else: rtt = round(rtt*1000, 3) - rttstring = str(rtt)+" milliseconds" + rttstring = f"{rtt} milliseconds" reception_stats = "" if reticulum.is_connected_to_shared_instance: @@ -233,30 +229,27 @@ def packet_delivered(receipt): reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dB]" + reception_stats += f" [SNR {reception_snr} dB]" else: if receipt.proof_packet != None: if receipt.proof_packet.rssi != None: - reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]" + reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" if receipt.proof_packet.snr != None: - reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dB]" + reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" RNS.log( - "Valid reply received from "+ - RNS.prettyhexrep(receipt.destination.hash)+ - ", round-trip time is "+rttstring+ - reception_stats + f"Valid reply received from {RNS.prettyhexrep(receipt.destination.hash)}, round-trip time is {rttstring}{reception_stats}" ) # This function is called if a packet times out. def packet_timed_out(receipt): if receipt.status == RNS.PacketReceipt.FAILED: - RNS.log("Packet "+RNS.prettyhexrep(receipt.hash)+" timed out") + RNS.log(f"Packet {RNS.prettyhexrep(receipt.hash)} timed out") ########################################################## diff --git a/Examples/Filetransfer.py b/Examples/Filetransfer.py index 98c4c7a..79081d1 100644 --- a/Examples/Filetransfer.py +++ b/Examples/Filetransfer.py @@ -73,7 +73,7 @@ def server(configpath, path): def announceLoop(destination): # Let the user know that everything is ready - RNS.log("File server "+RNS.prettyhexrep(destination.hash)+" running") + RNS.log(f"File server {RNS.prettyhexrep(destination.hash)} running") RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") # We enter a loop that runs until the users exits. @@ -83,7 +83,7 @@ def announceLoop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # Here's a convenience function for listing all files # in our served directory @@ -145,7 +145,7 @@ def client_request(message, packet): try: # If we have the requested file, we'll # read it and pack it as a resource - RNS.log("Client requested \""+filename+"\"") + RNS.log(f"Client requested \"{filename}\"") file = open(os.path.join(serve_path, filename), "rb") file_resource = RNS.Resource( @@ -158,7 +158,7 @@ def client_request(message, packet): except Exception as e: # If somethign went wrong, we close # the link - RNS.log("Error while reading file \""+filename+"\"", RNS.LOG_ERROR) + RNS.log(f"Error while reading file \"{filename}\"", RNS.LOG_ERROR) packet.link.teardown() raise e else: @@ -175,9 +175,9 @@ def resource_sending_concluded(resource): name = "resource" if resource.status == RNS.Resource.COMPLETE: - RNS.log("Done sending \""+name+"\" to client") + RNS.log(f"Done sending \"{name}\" to client") elif resource.status == RNS.Resource.FAILED: - RNS.log("Sending \""+name+"\" to client failed") + RNS.log(f"Sending \"{name}\" to client failed") def list_delivered(receipt): RNS.log("The file list was received by the client") @@ -218,7 +218,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -293,7 +293,7 @@ def download(filename): request_packet.send() print("") - print(("Requested \""+filename+"\" from server, waiting for download to begin...")) + print(f"Requested \"{filename}\" from server, waiting for download to begin...") menu_mode = "download_started" # This function runs a simple menu for the user @@ -363,7 +363,7 @@ def print_menu(): while menu_mode == "downloading": global current_download percent = round(current_download.get_progress() * 100.0, 1) - print(("\rProgress: "+str(percent)+" % "), end=' ') + print(f'\rProgress: {percent} % ', end=' ') sys.stdout.flush() time.sleep(0.1) @@ -383,15 +383,15 @@ def print_menu(): # Print statistics hours, rem = divmod(download_time, 3600) minutes, seconds = divmod(rem, 60) - timestring = "{:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds) + timestring = f"{int(hours):0>2}:{int(minutes):0>2}:{seconds:05.2f}" print("") print("") print("--- Statistics -----") - print("\tTime taken : "+timestring) - print("\tFile size : "+size_str(file_size)) - print("\tData transferred : "+size_str(transfer_size)) - print("\tEffective rate : "+size_str(file_size/download_time, suffix='b')+"/s") - print("\tTransfer rate : "+size_str(transfer_size/download_time, suffix='b')+"/s") + print(f"\tTime taken : {timestring}") + print(f"\tFile size : {size_str(file_size)}") + print(f"\tData transferred : {size_str(transfer_size)}") + print(f"\tEffective rate : {size_str(file_size / download_time, suffix='b')}/s") + print(f"\tTransfer rate : {size_str(transfer_size / download_time, suffix='b')}/s") print("") print("The download completed! Press enter to return to the menu.") print("") @@ -412,7 +412,7 @@ def print_filelist(): global server_files print("Files on server:") for index,file in enumerate(server_files): - print("\t("+str(index)+")\t"+file) + print(f"\t({index})\t{file}") def filelist_received(filelist_data, packet): global server_files, menu_mode @@ -509,7 +509,7 @@ def download_concluded(resource): counter = 0 while os.path.isfile(saved_filename): counter += 1 - saved_filename = current_filename+"."+str(counter) + saved_filename = f"{current_filename}.{counter}" try: file = open(saved_filename, "wb") @@ -534,9 +534,9 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1024.0: - return "%3.2f %s%s" % (num, unit, suffix) + return f"{num:3.2f} {unit}{suffix}" num /= 1024.0 - return "%.2f %s%s" % (num, last_unit, suffix) + return f"{num:.2f} {last_unit}{suffix}" # A convenience function for clearing the screen def clear_screen(): diff --git a/Examples/Identify.py b/Examples/Identify.py index 45ba18e..6bfa49d 100644 --- a/Examples/Identify.py +++ b/Examples/Identify.py @@ -53,9 +53,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Link identification example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Link identification example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -67,7 +65,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -85,7 +83,7 @@ def client_disconnected(link): RNS.log("Client disconnected") def remote_identified(link, identity): - RNS.log("Remote identified as: "+str(identity)) + RNS.log(f"Remote identified as: {identity}") def server_packet_received(message, packet): global latest_client_link @@ -100,9 +98,9 @@ def server_packet_received(message, packet): # that connected. text = message.decode("utf-8") - RNS.log("Received data from "+remote_peer+": "+text) + RNS.log(f"Received data from {remote_peer}: {text}") - reply_text = "I received \""+text+"\" over the link from "+remote_peer + reply_text = f"I received \"{text}\" over the link from {remote_peer}" reply_data = reply_text.encode("utf-8") RNS.Packet(latest_client_link, reply_data).send() @@ -127,7 +125,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -141,8 +139,7 @@ def client(destination_hexhash, configpath): # Create a new client identity client_identity = RNS.Identity() RNS.log( - "Client created new identity "+ - str(client_identity) + f"Client created new identity {client_identity}" ) # Check if we know a path to the destination @@ -210,14 +207,12 @@ def client_loop(): RNS.Packet(server_link, data).send() else: RNS.log( - "Cannot send this packet, the data size of "+ - str(len(data))+" bytes exceeds the link packet MDU of "+ - str(RNS.Link.MDU)+" bytes", + f"Cannot send this packet, the data size of {len(data)} bytes exceeds the link packet MDU of {RNS.Link.MDU} bytes", RNS.LOG_ERROR ) except Exception as e: - RNS.log("Error while sending data over the link: "+str(e)) + RNS.log(f"Error while sending data over the link: {e}") should_quit = True server_link.teardown() @@ -253,7 +248,7 @@ def link_closed(link): # simply print out the data. def client_packet_received(message, packet): text = message.decode("utf-8") - RNS.log("Received data on the link: "+text) + RNS.log(f"Received data on the link: {text}") print("> ", end=" ") sys.stdout.flush() diff --git a/Examples/Link.py b/Examples/Link.py index 6b3210c..6df8f3e 100644 --- a/Examples/Link.py +++ b/Examples/Link.py @@ -53,9 +53,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Link example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Link example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -67,7 +65,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -90,9 +88,9 @@ def server_packet_received(message, packet): # it will all be directed to the last client # that connected. text = message.decode("utf-8") - RNS.log("Received data on the link: "+text) + RNS.log(f"Received data on the link: {text}") - reply_text = "I received \""+text+"\" over the link" + reply_text = f"I received \"{text}\" over the link" reply_data = reply_text.encode("utf-8") RNS.Packet(latest_client_link, reply_data).send() @@ -113,7 +111,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -189,14 +187,12 @@ def client_loop(): RNS.Packet(server_link, data).send() else: RNS.log( - "Cannot send this packet, the data size of "+ - str(len(data))+" bytes exceeds the link packet MDU of "+ - str(RNS.Link.MDU)+" bytes", + f"Cannot send this packet, the data size of {len(data)} bytes exceeds the link packet MDU of {RNS.Link.MDU} bytes", RNS.LOG_ERROR ) except Exception as e: - RNS.log("Error while sending data over the link: "+str(e)) + RNS.log(f"Error while sending data over the link: {e}") should_quit = True server_link.teardown() @@ -230,7 +226,7 @@ def link_closed(link): # simply print out the data. def client_packet_received(message, packet): text = message.decode("utf-8") - RNS.log("Received data on the link: "+text) + RNS.log(f"Received data on the link: {text}") print("> ", end=" ") sys.stdout.flush() diff --git a/Examples/Minimal.py b/Examples/Minimal.py index 76f78c6..6f33893 100644 --- a/Examples/Minimal.py +++ b/Examples/Minimal.py @@ -51,9 +51,7 @@ def program_setup(configpath): def announceLoop(destination): # Let the user know that everything is ready RNS.log( - "Minimal example "+ - RNS.prettyhexrep(destination.hash)+ - " running, hit enter to manually send an announce (Ctrl-C to quit)" + f"Minimal example {RNS.prettyhexrep(destination.hash)} running, hit enter to manually send an announce (Ctrl-C to quit)" ) # We enter a loop that runs until the users exits. @@ -63,7 +61,7 @@ def announceLoop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") ########################################################## diff --git a/Examples/Ratchets.py b/Examples/Ratchets.py index 9c71c90..b690de4 100644 --- a/Examples/Ratchets.py +++ b/Examples/Ratchets.py @@ -75,9 +75,7 @@ def server(configpath): def announceLoop(destination): # Let the user know that everything is ready RNS.log( - "Ratcheted echo server "+ - RNS.prettyhexrep(destination.hash)+ - " running, hit enter to manually send an announce (Ctrl-C to quit)" + f"Ratcheted echo server {RNS.prettyhexrep(destination.hash)} running, hit enter to manually send an announce (Ctrl-C to quit)" ) # We enter a loop that runs until the users exits. @@ -87,7 +85,7 @@ def announceLoop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") def server_callback(message, packet): @@ -104,19 +102,19 @@ def server_callback(message, packet): reception_snr = reticulum.get_packet_snr(packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dBm]" + reception_stats += f" [SNR {reception_snr} dBm]" else: if packet.rssi != None: - reception_stats += " [RSSI "+str(packet.rssi)+" dBm]" + reception_stats += f" [RSSI {packet.rssi} dBm]" if packet.snr != None: - reception_stats += " [SNR "+str(packet.snr)+" dB]" + reception_stats += f" [SNR {packet.snr} dB]" - RNS.log("Received packet from echo client, proof sent"+reception_stats) + RNS.log(f"Received packet from echo client, proof sent{reception_stats}") ########################################################## @@ -134,13 +132,13 @@ def client(destination_hexhash, configpath, timeout=None): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: RNS.log("Invalid destination entered. Check your input!") - RNS.log(str(e)+"\n") + RNS.log(f"{e}\n") exit() # We must first initialise Reticulum @@ -153,9 +151,7 @@ def client(destination_hexhash, configpath, timeout=None): # Tell the user that the client is ready! RNS.log( - "Echo client ready, hit enter to send echo request to "+ - destination_hexhash+ - " (Ctrl-C to quit)" + f"Echo client ready, hit enter to send echo request to {destination_hexhash} (Ctrl-C to quit)" ) # We enter a loop that runs until the user exits. @@ -217,7 +213,7 @@ def client(destination_hexhash, configpath, timeout=None): packet_receipt.set_delivery_callback(packet_delivered) # Tell the user that the echo request was sent - RNS.log("Sent echo request to "+RNS.prettyhexrep(request_destination.hash)) + RNS.log(f"Sent echo request to {RNS.prettyhexrep(request_destination.hash)}") else: # If we do not know this destination, tell the # user to wait for an announce to arrive. @@ -234,10 +230,10 @@ def packet_delivered(receipt): rtt = receipt.get_rtt() if (rtt >= 1): rtt = round(rtt, 3) - rttstring = str(rtt)+" seconds" + rttstring = f"{rtt} seconds" else: rtt = round(rtt*1000, 3) - rttstring = str(rtt)+" milliseconds" + rttstring = f"{rtt} milliseconds" reception_stats = "" if reticulum.is_connected_to_shared_instance: @@ -245,30 +241,27 @@ def packet_delivered(receipt): reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dB]" + reception_stats += f" [SNR {reception_snr} dB]" else: if receipt.proof_packet != None: if receipt.proof_packet.rssi != None: - reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]" + reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" if receipt.proof_packet.snr != None: - reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dB]" + reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" RNS.log( - "Valid reply received from "+ - RNS.prettyhexrep(receipt.destination.hash)+ - ", round-trip time is "+rttstring+ - reception_stats + f"Valid reply received from {RNS.prettyhexrep(receipt.destination.hash)}, round-trip time is {rttstring}{reception_stats}" ) # This function is called if a packet times out. def packet_timed_out(receipt): if receipt.status == RNS.PacketReceipt.FAILED: - RNS.log("Packet "+RNS.prettyhexrep(receipt.hash)+" timed out") + RNS.log(f"Packet {RNS.prettyhexrep(receipt.hash)} timed out") ########################################################## diff --git a/Examples/Request.py b/Examples/Request.py index ca8a993..774fe2e 100644 --- a/Examples/Request.py +++ b/Examples/Request.py @@ -24,7 +24,7 @@ APP_NAME = "example_utilities" latest_client_link = None def random_text_generator(path, data, request_id, link_id, remote_identity, requested_at): - RNS.log("Generating response to request "+RNS.prettyhexrep(request_id)+" on link "+RNS.prettyhexrep(link_id)) + RNS.log(f"Generating response to request {RNS.prettyhexrep(request_id)} on link {RNS.prettyhexrep(link_id)}") texts = ["They looked up", "On each full moon", "Becky was upset", "I’ll stay away from it", "The pet shop stocks everything"] return texts[random.randint(0, len(texts)-1)] @@ -67,9 +67,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Request example "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Request example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -81,7 +79,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -113,7 +111,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -187,7 +185,7 @@ def client_loop(): except Exception as e: - RNS.log("Error while sending request over the link: "+str(e)) + RNS.log(f"Error while sending request over the link: {e}") should_quit = True server_link.teardown() @@ -195,13 +193,13 @@ def got_response(request_receipt): request_id = request_receipt.request_id response = request_receipt.response - RNS.log("Got response for request "+RNS.prettyhexrep(request_id)+": "+str(response)) + RNS.log(f"Got response for request {RNS.prettyhexrep(request_id)}: {response}") def request_received(request_receipt): - RNS.log("The request "+RNS.prettyhexrep(request_receipt.request_id)+" was received by the remote peer.") + RNS.log(f"The request {RNS.prettyhexrep(request_receipt.request_id)} was received by the remote peer.") def request_failed(request_receipt): - RNS.log("The request "+RNS.prettyhexrep(request_receipt.request_id)+" failed.") + RNS.log(f"The request {RNS.prettyhexrep(request_receipt.request_id)} failed.") # This function is called when a link diff --git a/Examples/Speedtest.py b/Examples/Speedtest.py index b66a556..4e564f0 100644 --- a/Examples/Speedtest.py +++ b/Examples/Speedtest.py @@ -62,9 +62,7 @@ def server(configpath): def server_loop(destination): # Let the user know that everything is ready RNS.log( - "Speedtest "+ - RNS.prettyhexrep(destination.hash)+ - " running, waiting for a connection." + f"Speedtest {RNS.prettyhexrep(destination.hash)} running, waiting for a connection." ) RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") @@ -76,7 +74,7 @@ def server_loop(destination): while True: entered = input() destination.announce() - RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}") # When a client establishes a link to our server # destination, this function will be called with @@ -108,9 +106,9 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1024.0: - return "%3.2f %s%s" % (num, unit, suffix) + return f"{num:3.2f} {unit}{suffix}" num /= 1024.0 - return "%.2f %s%s" % (num, last_unit, suffix) + return f"{num:.2f} {last_unit}{suffix}" def server_packet_received(message, packet): @@ -134,14 +132,14 @@ def server_packet_received(message, packet): download_time = last_packet_at-first_packet_at hours, rem = divmod(download_time, 3600) minutes, seconds = divmod(rem, 60) - timestring = "{:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds) + timestring = f"{int(hours):0>2}:{int(minutes):0>2}:{seconds:05.2f}" print("") print("") print("--- Statistics -----") - print("\tTime taken : "+timestring) - print("\tData transferred : "+size_str(rcv_d)) - print("\tTransfer rate : "+size_str(rcv_d/download_time, suffix='b')+"/s") + print(f"\tTime taken : {timestring}") + print(f"\tData transferred : {size_str(rcv_d)}") + print(f"\tTransfer rate : {size_str(rcv_d / download_time, suffix='b')}/s") print("") sys.stdout.flush() @@ -169,7 +167,7 @@ def client(destination_hexhash, configpath): dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: raise ValueError( - "Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2) + f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) destination_hash = bytes.fromhex(destination_hexhash) @@ -260,13 +258,13 @@ def link_established(link): download_time = ended-started hours, rem = divmod(download_time, 3600) minutes, seconds = divmod(rem, 60) - timestring = "{:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds) + timestring = f"{int(hours):0>2}:{int(minutes):0>2}:{seconds:05.2f}" print("") print("") print("--- Statistics -----") - print("\tTime taken : "+timestring) - print("\tData transferred : "+size_str(data_sent)) - print("\tTransfer rate : "+size_str(data_sent/download_time, suffix='b')+"/s") + print(f"\tTime taken : {timestring}") + print(f"\tData transferred : {size_str(data_sent)}") + print(f"\tTransfer rate : {size_str(data_sent / download_time, suffix='b')}/s") print("") sys.stdout.flush() diff --git a/RNS/Buffer.py b/RNS/Buffer.py index c9a89a9..f260c16 100644 --- a/RNS/Buffer.py +++ b/RNS/Buffer.py @@ -65,7 +65,7 @@ class StreamDataMessage(MessageBase): raise ValueError("stream_id must be 0-16383") self.stream_id = stream_id self.compressed = compressed - self.data = data or bytes() + self.data = data or b'' self.eof = eof def pack(self) -> bytes: @@ -73,7 +73,7 @@ class StreamDataMessage(MessageBase): raise ValueError("stream_id") header_val = (0x3fff & self.stream_id) | (0x8000 if self.eof else 0x0000) | (0x4000 if self.compressed > 0 else 0x0000) - return bytes(struct.pack(">H", header_val) + (self.data if self.data else bytes())) + return bytes(struct.pack(">H", header_val) + (self.data if self.data else b'')) def unpack(self, raw): self.stream_id = struct.unpack(">H", raw[:2])[0] @@ -148,7 +148,7 @@ class RawChannelReader(RawIOBase, AbstractContextManager): try: threading.Thread(target=listener, name="Message Callback", args=[len(self._buffer)], daemon=True).start() except Exception as ex: - RNS.log("Error calling RawChannelReader(" + str(self._stream_id) + ") callback: " + str(ex), RNS.LOG_ERROR) + RNS.log(f"Error calling RawChannelReader({self._stream_id}) callback: {ex}", RNS.LOG_ERROR) return True return False @@ -264,7 +264,7 @@ class RawChannelWriter(RawIOBase, AbstractContextManager): time.sleep(0.05) self._eof = True - self.write(bytes()) + self.write(b'') def __enter__(self): return self diff --git a/RNS/Channel.py b/RNS/Channel.py index 47c11f6..5634471 100644 --- a/RNS/Channel.py +++ b/RNS/Channel.py @@ -168,7 +168,7 @@ class Envelope: Internal wrapper used to transport messages over a channel and track its state within the channel framework. """ - def unpack(self, message_factories: dict[int, Type]) -> MessageBase: + def unpack(self, message_factories: dict[int, type]) -> MessageBase: msgtype, self.sequence, length = struct.unpack(">HHH", self.raw[:6]) raw = self.raw[6:] ctor = message_factories.get(msgtype, None) @@ -282,7 +282,7 @@ class Channel(contextlib.AbstractContextManager): self._message_callbacks: [MessageCallbackType] = [] self._next_sequence = 0 self._next_rx_sequence = 0 - self._message_factories: dict[int, Type[MessageBase]] = {} + self._message_factories: dict[int, type[MessageBase]] = {} self._max_tries = 5 self.fast_rate_rounds = 0 self.medium_rate_rounds = 0 @@ -301,12 +301,12 @@ class Channel(contextlib.AbstractContextManager): def __enter__(self) -> Channel: return self - def __exit__(self, __exc_type: Type[BaseException] | None, __exc_value: BaseException | None, + def __exit__(self, __exc_type: type[BaseException] | None, __exc_value: BaseException | None, __traceback: TracebackType | None) -> bool | None: self._shutdown() return False - def register_message_type(self, message_class: Type[MessageBase]): + def register_message_type(self, message_class: type[MessageBase]): """ Register a message class for reception over a ``Channel``. @@ -316,7 +316,7 @@ class Channel(contextlib.AbstractContextManager): """ self._register_message_type(message_class, is_system_type=False) - def _register_message_type(self, message_class: Type[MessageBase], *, is_system_type: bool = False): + def _register_message_type(self, message_class: type[MessageBase], *, is_system_type: bool = False): with self._lock: if not issubclass(message_class, MessageBase): raise ChannelException(CEType.ME_INVALID_MSG_TYPE, @@ -384,7 +384,7 @@ class Channel(contextlib.AbstractContextManager): for existing in ring: if envelope.sequence == existing.sequence: - RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence "+str(envelope.sequence), RNS.LOG_EXTREME) + RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence {envelope.sequence}", RNS.LOG_EXTREME) return False if envelope.sequence < existing.sequence and not (self._next_rx_sequence - envelope.sequence) > (Channel.SEQ_MAX//2): @@ -408,7 +408,7 @@ class Channel(contextlib.AbstractContextManager): if cb(message): return except Exception as e: - RNS.log("Channel "+str(self)+" experienced an error while running a message callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Channel {self} experienced an error while running a message callback. The contained exception was: {e}", RNS.LOG_ERROR) def _receive(self, raw: bytes): try: @@ -420,16 +420,16 @@ class Channel(contextlib.AbstractContextManager): window_overflow = (self._next_rx_sequence+Channel.WINDOW_MAX) % Channel.SEQ_MODULUS if window_overflow < self._next_rx_sequence: if envelope.sequence > window_overflow: - RNS.log("Invalid packet sequence ("+str(envelope.sequence)+") received on channel "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Invalid packet sequence ({envelope.sequence}) received on channel {self}", RNS.LOG_EXTREME) return else: - RNS.log("Invalid packet sequence ("+str(envelope.sequence)+") received on channel "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Invalid packet sequence ({envelope.sequence}) received on channel {self}", RNS.LOG_EXTREME) return is_new = self._emplace_envelope(envelope, self._rx_ring) if not is_new: - RNS.log("Duplicate message received on channel "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Duplicate message received on channel {self}", RNS.LOG_EXTREME) return else: with self._lock: @@ -454,7 +454,7 @@ class Channel(contextlib.AbstractContextManager): self._run_callbacks(m) except Exception as e: - RNS.log("An error ocurred while receiving data on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while receiving data on {self}. The contained exception was: {e}", RNS.LOG_ERROR) def is_ready_to_send(self) -> bool: """ @@ -520,9 +520,9 @@ class Channel(contextlib.AbstractContextManager): else: - RNS.log("Envelope not found in TX ring for "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Envelope not found in TX ring for {self}", RNS.LOG_EXTREME) if not envelope: - RNS.log("Spurious message received on "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Spurious message received on {self}", RNS.LOG_EXTREME) def _packet_delivered(self, packet: TPacket): self._packet_tx_op(packet, lambda env: True) @@ -541,7 +541,7 @@ class Channel(contextlib.AbstractContextManager): def _packet_timeout(self, packet: TPacket): def retry_envelope(envelope: Envelope) -> bool: if envelope.tries >= self._max_tries: - RNS.log("Retry count exceeded on "+str(self)+", tearing down Link.", RNS.LOG_ERROR) + RNS.log(f"Retry count exceeded on {self}, tearing down Link.", RNS.LOG_ERROR) self._shutdown() # start on separate thread? self._outlet.timed_out() return True diff --git a/RNS/Cryptography/Fernet.py b/RNS/Cryptography/Fernet.py index 245d86c..0ce843c 100644 --- a/RNS/Cryptography/Fernet.py +++ b/RNS/Cryptography/Fernet.py @@ -48,7 +48,7 @@ class Fernet(): raise ValueError("Token key cannot be None") if len(key) != 32: - raise ValueError("Token key must be 32 bytes, not "+str(len(key))) + raise ValueError(f"Token key must be 32 bytes, not {len(key)}") self._signing_key = key[:16] self._encryption_key = key[16:] @@ -56,7 +56,7 @@ class Fernet(): def verify_hmac(self, token): if len(token) <= 32: - raise ValueError("Cannot verify HMAC on token of only "+str(len(token))+" bytes") + raise ValueError(f"Cannot verify HMAC on token of only {len(token)} bytes") else: received_hmac = token[-32:] expected_hmac = HMAC.new(self._signing_key, token[:-32]).digest() diff --git a/RNS/Cryptography/HMAC.py b/RNS/Cryptography/HMAC.py index 848a231..2f7460b 100644 --- a/RNS/Cryptography/HMAC.py +++ b/RNS/Cryptography/HMAC.py @@ -37,7 +37,7 @@ class HMAC: """ if not isinstance(key, (bytes, bytearray)): - raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) + raise TypeError(f"key: expected bytes or bytearray, but got {type(key).__name__!r}") if not digestmod: raise TypeError("Missing required parameter 'digestmod'.") @@ -60,13 +60,11 @@ class HMAC: if hasattr(self._inner, 'block_size'): blocksize = self._inner.block_size if blocksize < 16: - _warnings.warn('block_size of %d seems too small; using our ' - 'default of %d.' % (blocksize, self.blocksize), + _warnings.warn(f'block_size of {int(blocksize)} seems too small; using our default of {int(self.blocksize)}.', RuntimeWarning, 2) blocksize = self.blocksize else: - _warnings.warn('No block_size attribute on given digest object; ' - 'Assuming %d.' % (self.blocksize), + _warnings.warn(f'No block_size attribute on given digest object; Assuming {int(self.blocksize)}.', RuntimeWarning, 2) blocksize = self.blocksize diff --git a/RNS/Cryptography/PKCS7.py b/RNS/Cryptography/PKCS7.py index aa3bef0..d508bab 100644 --- a/RNS/Cryptography/PKCS7.py +++ b/RNS/Cryptography/PKCS7.py @@ -35,6 +35,6 @@ class PKCS7: l = len(data) n = data[-1] if n > bs: - raise ValueError("Cannot unpad, invalid padding length of "+str(n)+" bytes") + raise ValueError(f"Cannot unpad, invalid padding length of {n} bytes") else: return data[:l-n] \ No newline at end of file diff --git a/RNS/Cryptography/Provider.py b/RNS/Cryptography/Provider.py index 80a3f9e..016dc37 100644 --- a/RNS/Cryptography/Provider.py +++ b/RNS/Cryptography/Provider.py @@ -35,4 +35,4 @@ def backend(): elif PROVIDER == PROVIDER_INTERNAL: return "internal" elif PROVIDER == PROVIDER_PYCA: - return "openssl, PyCA "+str(pyca_v) \ No newline at end of file + return f"openssl, PyCA {pyca_v}" \ No newline at end of file diff --git a/RNS/Cryptography/SHA256.py b/RNS/Cryptography/SHA256.py index 5fc8395..03f22a4 100644 --- a/RNS/Cryptography/SHA256.py +++ b/RNS/Cryptography/SHA256.py @@ -28,7 +28,7 @@ import sys def new(m=None): return sha256(m) -class sha256(object): +class sha256: _k = (0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, @@ -59,7 +59,7 @@ class sha256(object): if m is not None: if type(m) is not bytes: - raise TypeError('%s() argument 1 must be bytes, not %s' % (self.__class__.__name__, type(m).__name__)) + raise TypeError(f'{self.__class__.__name__}() argument 1 must be bytes, not {type(m).__name__}') self.update(m) def _rotr(self, x, y): @@ -100,7 +100,7 @@ class sha256(object): return if type(m) is not bytes: - raise TypeError('%s() argument 1 must be bytes, not %s' % (sys._getframe().f_code.co_name, type(m).__name__)) + raise TypeError(f'{sys._getframe().f_code.co_name}() argument 1 must be bytes, not {type(m).__name__}') self._buffer += m self._counter += len(m) diff --git a/RNS/Cryptography/SHA512.py b/RNS/Cryptography/SHA512.py index 4e5c3f6..7dbcb76 100644 --- a/RNS/Cryptography/SHA512.py +++ b/RNS/Cryptography/SHA512.py @@ -25,7 +25,7 @@ import copy, struct, sys def new(m=None): return sha512(m) -class sha512(object): +class sha512: _k = (0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, @@ -60,7 +60,7 @@ class sha512(object): if m is not None: if type(m) is not bytes: - raise TypeError('%s() argument 1 must be bytes, not %s' % (self.__class__.__name__, type(m).__name__)) + raise TypeError(f'{self.__class__.__name__}() argument 1 must be bytes, not {type(m).__name__}') self.update(m) def _rotr(self, x, y): @@ -100,7 +100,7 @@ class sha512(object): if not m: return if type(m) is not bytes: - raise TypeError('%s() argument 1 must be bytes, not %s' % (sys._getframe().f_code.co_name, type(m).__name__)) + raise TypeError(f'{sys._getframe().f_code.co_name}() argument 1 must be bytes, not {type(m).__name__}') self._buffer += m self._counter += len(m) diff --git a/RNS/Cryptography/__init__.py b/RNS/Cryptography/__init__.py index 78c04df..9c3289e 100644 --- a/RNS/Cryptography/__init__.py +++ b/RNS/Cryptography/__init__.py @@ -20,5 +20,5 @@ elif cp.PROVIDER == cp.PROVIDER_PYCA: from RNS.Cryptography.Proxies import Ed25519PrivateKeyProxy as Ed25519PrivateKey from RNS.Cryptography.Proxies import Ed25519PublicKeyProxy as Ed25519PublicKey -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] diff --git a/RNS/Cryptography/aes/aes.py b/RNS/Cryptography/aes/aes.py index eabb20b..4b8e45e 100644 --- a/RNS/Cryptography/aes/aes.py +++ b/RNS/Cryptography/aes/aes.py @@ -230,7 +230,7 @@ def test(): print(f"Ciphertext Hex: {ciphertext_block.hex()}") print(f"Plaintext: {plaintext_block.decode()}") assert plaintext_block == single_block_text - print(bcolors.OK + "Single Block Test Passed Successfully" + bcolors.RESET) + print(f"{bcolors.OK}Single Block Test Passed Successfully{bcolors.RESET}") print() # test a less than a block length phrase @@ -246,7 +246,7 @@ def test(): print(f"Ciphertext Hex: {ciphertext_short.hex()}") print(f"Plaintext: {plaintext_short.decode()}") assert short_text == plaintext_short - print(bcolors.OK + "Short Text Test Passed Successfully" + bcolors.RESET) + print(f"{bcolors.OK}Short Text Test Passed Successfully{bcolors.RESET}") print() # test an arbitrary length phrase @@ -262,7 +262,7 @@ def test(): print(f"Ciphertext Hex: {ciphertext.hex()}") print(f"Plaintext: {plaintext.decode()}") assert text == plaintext - print(bcolors.OK + "Arbitrary Length Text Test Passed Successfully" + bcolors.RESET) + print(f"{bcolors.OK}Arbitrary Length Text Test Passed Successfully{bcolors.RESET}") print() diff --git a/RNS/Cryptography/pure25519/basic.py b/RNS/Cryptography/pure25519/basic.py index e18c759..2450851 100644 --- a/RNS/Cryptography/pure25519/basic.py +++ b/RNS/Cryptography/pure25519/basic.py @@ -141,7 +141,7 @@ def encodepoint(P): assert 0 <= y < (1<<255) # always < 0x7fff..ff if x & 1: y += 1<<255 - return binascii.unhexlify("%064x" % y)[::-1] + return binascii.unhexlify(f"{y:064x}")[::-1] def isoncurve(P): x = P[0] @@ -192,7 +192,7 @@ def password_to_scalar(pw): def scalar_to_bytes(y): y = y % L assert 0 <= y < 2**256 - return binascii.unhexlify("%064x" % y)[::-1] + return binascii.unhexlify(f"{y:064x}")[::-1] # Elements, of various orders diff --git a/RNS/Cryptography/pure25519/ed25519_oop.py b/RNS/Cryptography/pure25519/ed25519_oop.py index 0edfa5a..fa5e6a4 100644 --- a/RNS/Cryptography/pure25519/ed25519_oop.py +++ b/RNS/Cryptography/pure25519/ed25519_oop.py @@ -39,7 +39,7 @@ class BadPrefixError(Exception): def remove_prefix(s_bytes, prefix): assert(type(s_bytes) == type(prefix)) if s_bytes[:len(prefix)] != prefix: - raise BadPrefixError("did not see expected '%s' prefix" % (prefix,)) + raise BadPrefixError(f"did not see expected '{prefix}' prefix") return s_bytes[len(prefix):] def to_ascii(s_bytes, prefix="", encoding="base64"): @@ -93,7 +93,7 @@ def from_ascii(s_ascii, prefix="", encoding="base64"): raise NotImplementedError return s_bytes -class SigningKey(object): +class SigningKey: # this can only be used to reconstruct a key created by create_keypair(). def __init__(self, sk_s, prefix="", encoding=None): assert isinstance(sk_s, bytes) @@ -150,7 +150,7 @@ class SigningKey(object): return to_ascii(sig_out, prefix, encoding) return prefix+sig_out -class VerifyingKey(object): +class VerifyingKey: def __init__(self, vk_s, prefix="", encoding=None): if not isinstance(prefix, bytes): prefix = prefix.encode('ascii') diff --git a/RNS/Cryptography/pure25519/eddsa.py b/RNS/Cryptography/pure25519/eddsa.py index f6a89dc..ce01cca 100644 --- a/RNS/Cryptography/pure25519/eddsa.py +++ b/RNS/Cryptography/pure25519/eddsa.py @@ -78,16 +78,16 @@ def sign(skbytes, msg): """Return just the signature, given the message and just the secret key.""" if len(skbytes) != 32: - raise ValueError("Bad signing key length %d" % len(skbytes)) + raise ValueError(f"Bad signing key length {len(skbytes)}") vkbytes = create_verifying_key(skbytes) sig = signature(msg, skbytes, vkbytes) return sig def verify(vkbytes, sig, msg): if len(vkbytes) != 32: - raise ValueError("Bad verifying key length %d" % len(vkbytes)) + raise ValueError(f"Bad verifying key length {len(vkbytes)}") if len(sig) != 64: - raise ValueError("Bad signature length %d" % len(sig)) + raise ValueError(f"Bad signature length {len(sig)}") rc = checkvalid(sig, msg, vkbytes) if not rc: raise ValueError("rc != 0", rc) diff --git a/RNS/Destination.py b/RNS/Destination.py index bca8f35..68d854c 100755 --- a/RNS/Destination.py +++ b/RNS/Destination.py @@ -96,10 +96,10 @@ class Destination: name = app_name for aspect in aspects: if "." in aspect: raise ValueError("Dots can't be used in aspects") - name += "." + aspect + name += f".{aspect}" if identity != None: - name += "." + identity.hexhash + name += f".{identity.hexhash}" return name @@ -192,7 +192,7 @@ class Destination: """ :returns: A human-readable representation of the destination including addressable hash and full name. """ - return "<"+self.name+"/"+self.hexhash+">" + return f"<{self.name}/{self.hexhash}>" def _clean_ratchets(self): if self.ratchets != None: @@ -210,13 +210,13 @@ class Destination: except Exception as e: self.ratchets = None self.ratchets_path = None - raise OSError("Could not write ratchet file contents for "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + raise OSError(f"Could not write ratchet file contents for {self}. The contained exception was: {e}", RNS.LOG_ERROR) def rotate_ratchets(self): if self.ratchets != None: now = time.time() if now > self.latest_ratchet_time+self.ratchet_interval: - RNS.log("Rotating ratchets for "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Rotating ratchets for {self}", RNS.LOG_DEBUG) new_ratchet = RNS.Identity._generate_ratchet() self.ratchets.insert(0, new_ratchet) self.latest_ratchet_time = now @@ -224,7 +224,7 @@ class Destination: self._persist_ratchets() return True else: - raise SystemError("Cannot rotate ratchet on "+str(self)+", ratchets are not enabled") + raise SystemError(f"Cannot rotate ratchet on {self}, ratchets are not enabled") return False @@ -262,7 +262,7 @@ class Destination: # received via multiple paths. The difference in reception time will # potentially also be useful in determining characteristics of the # multiple available paths, and to choose the best one. - RNS.log("Using cached announce data for answering path request with tag "+RNS.prettyhexrep(tag), RNS.LOG_EXTREME) + RNS.log(f"Using cached announce data for answering path request with tag {RNS.prettyhexrep(tag)}", RNS.LOG_EXTREME) announce_data = self.path_responses[tag][1] else: @@ -413,7 +413,7 @@ class Destination: try: self.callbacks.packet(plaintext, packet) except Exception as e: - RNS.log("Error while executing receive callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing receive callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def incoming_link_request(self, data, packet): if self.accept_link_requests: @@ -437,9 +437,9 @@ class Destination: except Exception as e: self.ratchets = None self.ratchets_path = None - raise OSError("Could not read ratchet file contents for "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + raise OSError(f"Could not read ratchet file contents for {self}. The contained exception was: {e}", RNS.LOG_ERROR) else: - RNS.log("No existing ratchet data found, initialising new ratchet file for "+str(self), RNS.LOG_DEBUG) + RNS.log(f"No existing ratchet data found, initialising new ratchet file for {self}", RNS.LOG_DEBUG) self.ratchets = [] self.ratchets_path = ratchets_path self._persist_ratchets() @@ -464,11 +464,11 @@ class Destination: self._reload_ratchets(ratchets_path) # TODO: Remove at some point - RNS.log("Ratchets enabled on "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Ratchets enabled on {self}", RNS.LOG_DEBUG) return True else: - raise ValueError("No ratchet file path specified for "+str(self)) + raise ValueError(f"No ratchet file path specified for {self}") def enforce_ratchets(self): """ @@ -478,7 +478,7 @@ class Destination: """ if self.ratchets != None: self.__enforce_ratchets = True - RNS.log("Ratchets enforced on "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Ratchets enforced on {self}", RNS.LOG_DEBUG) return True else: return False @@ -586,7 +586,7 @@ class Destination: return self.prv.encrypt(plaintext) except Exception as e: RNS.log("The GROUP destination could not encrypt data", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) else: raise ValueError("No private key held by GROUP destination. Did you create or load one?") @@ -630,7 +630,7 @@ class Destination: return self.prv.decrypt(ciphertext) except Exception as e: RNS.log("The GROUP destination could not decrypt data", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) else: raise ValueError("No private key held by GROUP destination. Did you create or load one?") diff --git a/RNS/Identity.py b/RNS/Identity.py index b2de82a..a1cc638 100644 --- a/RNS/Identity.py +++ b/RNS/Identity.py @@ -87,7 +87,7 @@ class Identity: @staticmethod def remember(packet_hash, destination_hash, public_key, app_data = None): if len(public_key) != Identity.KEYSIZE//8: - raise TypeError("Can't remember "+RNS.prettyhexrep(destination_hash)+", the public key size of "+str(len(public_key))+" is not valid.", RNS.LOG_ERROR) + raise TypeError(f"Can't remember {RNS.prettyhexrep(destination_hash)}, the public key size of {len(public_key)} is not valid.", RNS.LOG_ERROR) else: Identity.known_destinations[destination_hash] = [time.time(), packet_hash, public_key, app_data] @@ -153,9 +153,9 @@ class Identity: save_start = time.time() storage_known_destinations = {} - if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"): + if os.path.isfile(f"{RNS.Reticulum.storagepath}/known_destinations"): try: - file = open(RNS.Reticulum.storagepath+"/known_destinations","rb") + file = open(f"{RNS.Reticulum.storagepath}/known_destinations","rb") storage_known_destinations = umsgpack.load(file) file.close() except: @@ -166,32 +166,32 @@ class Identity: if not destination_hash in Identity.known_destinations: Identity.known_destinations[destination_hash] = storage_known_destinations[destination_hash] except Exception as e: - RNS.log("Skipped recombining known destinations from disk, since an error occurred: "+str(e), RNS.LOG_WARNING) + RNS.log(f"Skipped recombining known destinations from disk, since an error occurred: {e}", RNS.LOG_WARNING) - RNS.log("Saving "+str(len(Identity.known_destinations))+" known destinations to storage...", RNS.LOG_DEBUG) - file = open(RNS.Reticulum.storagepath+"/known_destinations","wb") + RNS.log(f"Saving {len(Identity.known_destinations)} known destinations to storage...", RNS.LOG_DEBUG) + file = open(f"{RNS.Reticulum.storagepath}/known_destinations","wb") umsgpack.dump(Identity.known_destinations, file) file.close() save_time = time.time() - save_start if save_time < 1: - time_str = str(round(save_time*1000,2))+"ms" + time_str = f"{round(save_time * 1000, 2)}ms" else: - time_str = str(round(save_time,2))+"s" + time_str = f"{round(save_time, 2)}s" - RNS.log("Saved known destinations to storage in "+time_str, RNS.LOG_DEBUG) + RNS.log(f"Saved known destinations to storage in {time_str}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Error while saving known destinations to disk, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while saving known destinations to disk, the contained exception was: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) Identity.saving_known_destinations = False @staticmethod def load_known_destinations(): - if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"): + if os.path.isfile(f"{RNS.Reticulum.storagepath}/known_destinations"): try: - file = open(RNS.Reticulum.storagepath+"/known_destinations","rb") + file = open(f"{RNS.Reticulum.storagepath}/known_destinations","rb") loaded_known_destinations = umsgpack.load(file) file.close() @@ -200,7 +200,7 @@ class Identity: if len(known_destination) == RNS.Reticulum.TRUNCATED_HASHLENGTH//8: Identity.known_destinations[known_destination] = loaded_known_destinations[known_destination] - RNS.log("Loaded "+str(len(Identity.known_destinations))+" known destination from storage", RNS.LOG_VERBOSE) + RNS.log(f"Loaded {len(Identity.known_destinations)} known destination from storage", RNS.LOG_VERBOSE) except Exception as e: RNS.log("Error loading known destinations from disk, file will be recreated on exit", RNS.LOG_ERROR) @@ -278,7 +278,7 @@ class Identity: hexhash = RNS.hexrep(destination_hash, delimit=False) ratchet_data = {"ratchet": ratchet, "received": time.time()} - ratchetdir = RNS.Reticulum.storagepath+"/ratchets" + ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets" if not os.path.isdir(ratchetdir): os.makedirs(ratchetdir) @@ -303,7 +303,7 @@ class Identity: RNS.log("Cleaning ratchets...", RNS.LOG_DEBUG) try: now = time.time() - ratchetdir = RNS.Reticulum.storagepath+"/ratchets" + ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets" if os.path.isdir(ratchetdir): for filename in os.listdir(ratchetdir): try: @@ -326,7 +326,7 @@ class Identity: @staticmethod def get_ratchet(destination_hash): if not destination_hash in Identity.known_ratchets: - ratchetdir = RNS.Reticulum.storagepath+"/ratchets" + ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets" hexhash = RNS.hexrep(destination_hash, delimit=False) ratchet_path = f"{ratchetdir}/{hexhash}" if os.path.isfile(ratchet_path): @@ -417,19 +417,19 @@ class Identity: if packet.rssi != None or packet.snr != None: signal_str = " [" if packet.rssi != None: - signal_str += "RSSI "+str(packet.rssi)+"dBm" + signal_str += f"RSSI {packet.rssi}dBm" if packet.snr != None: signal_str += ", " if packet.snr != None: - signal_str += "SNR "+str(packet.snr)+"dB" + signal_str += f"SNR {packet.snr}dB" signal_str += "]" else: signal_str = "" if hasattr(packet, "transport_id") and packet.transport_id != None: - RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received via "+RNS.prettyhexrep(packet.transport_id)+" on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME) + RNS.log(f"Valid announce for {RNS.prettyhexrep(destination_hash)} {packet.hops} hops away, received via {RNS.prettyhexrep(packet.transport_id)} on {packet.receiving_interface}{signal_str}", RNS.LOG_EXTREME) else: - RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME) + RNS.log(f"Valid announce for {RNS.prettyhexrep(destination_hash)} {packet.hops} hops away, received on {packet.receiving_interface}{signal_str}", RNS.LOG_EXTREME) if ratchet: Identity._remember_ratchet(destination_hash, ratchet) @@ -437,16 +437,16 @@ class Identity: return True else: - RNS.log("Received invalid announce for "+RNS.prettyhexrep(destination_hash)+": Destination mismatch.", RNS.LOG_DEBUG) + RNS.log(f"Received invalid announce for {RNS.prettyhexrep(destination_hash)}: Destination mismatch.", RNS.LOG_DEBUG) return False else: - RNS.log("Received invalid announce for "+RNS.prettyhexrep(destination_hash)+": Invalid signature.", RNS.LOG_DEBUG) + RNS.log(f"Received invalid announce for {RNS.prettyhexrep(destination_hash)}: Invalid signature.", RNS.LOG_DEBUG) del announced_identity return False except Exception as e: - RNS.log("Error occurred while validating announce. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while validating announce. The contained exception was: {e}", RNS.LOG_ERROR) return False @staticmethod @@ -505,8 +505,8 @@ class Identity: return True return False except Exception as e: - RNS.log("Error while saving identity to "+str(path), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e)) + RNS.log(f"Error while saving identity to {path}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}") def __init__(self,create_keys=True): # Initialize keys to none @@ -541,7 +541,7 @@ class Identity: self.update_hashes() - RNS.log("Identity keys created for "+RNS.prettyhexrep(self.hash), RNS.LOG_VERBOSE) + RNS.log(f"Identity keys created for {RNS.prettyhexrep(self.hash)}", RNS.LOG_VERBOSE) def get_private_key(self): """ @@ -581,7 +581,7 @@ class Identity: except Exception as e: raise e RNS.log("Failed to load identity key", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) return False def load_public_key(self, pub_bytes): @@ -600,7 +600,7 @@ class Identity: self.update_hashes() except Exception as e: - RNS.log("Error while loading public key, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while loading public key, the contained exception was: {e}", RNS.LOG_ERROR) def update_hashes(self): self.hash = Identity.truncated_hash(self.get_public_key()) @@ -613,8 +613,8 @@ class Identity: return self.load_private_key(prv_bytes) return False except Exception as e: - RNS.log("Error while loading identity from "+str(path), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while loading identity from {path}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) def get_salt(self): return self.hash @@ -697,7 +697,7 @@ class Identity: pass if enforce_ratchets and plaintext == None: - RNS.log("Decryption with ratchet enforcement by "+RNS.prettyhexrep(self.hash)+" failed. Dropping packet.", RNS.LOG_DEBUG) + RNS.log(f"Decryption with ratchet enforcement by {RNS.prettyhexrep(self.hash)} failed. Dropping packet.", RNS.LOG_DEBUG) if ratchet_id_receiver: ratchet_id_receiver.latest_ratchet_id = None return None @@ -717,7 +717,7 @@ class Identity: ratchet_id_receiver.latest_ratchet_id = None except Exception as e: - RNS.log("Decryption by "+RNS.prettyhexrep(self.hash)+" failed: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"Decryption by {RNS.prettyhexrep(self.hash)} failed: {e}", RNS.LOG_DEBUG) if ratchet_id_receiver: ratchet_id_receiver.latest_ratchet_id = None @@ -741,7 +741,7 @@ class Identity: try: return self.sig_prv.sign(message) except Exception as e: - RNS.log("The identity "+str(self)+" could not sign the requested message. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The identity {self} could not sign the requested message. The contained exception was: {e}", RNS.LOG_ERROR) raise e else: raise KeyError("Signing failed because identity does not hold a private key") diff --git a/RNS/Interfaces/AX25KISSInterface.py b/RNS/Interfaces/AX25KISSInterface.py index 483c562..cf99a0b 100644 --- a/RNS/Interfaces/AX25KISSInterface.py +++ b/RNS/Interfaces/AX25KISSInterface.py @@ -87,7 +87,7 @@ class AX25KISSInterface(Interface): self.name = name self.src_call = callsign.upper().encode("ascii") self.src_ssid = ssid - self.dst_call = "APZRNS".encode("ascii") + self.dst_call = b"APZRNS" self.dst_ssid = 0 self.port = port self.speed = speed @@ -105,10 +105,10 @@ class AX25KISSInterface(Interface): self.flow_control_locked = time.time() if (len(self.src_call) < 3 or len(self.src_call) > 6): - raise ValueError("Invalid callsign for "+str(self)) + raise ValueError(f"Invalid callsign for {self}") if (self.src_ssid < 0 or self.src_ssid > 15): - raise ValueError("Invalid SSID for "+str(self)) + raise ValueError(f"Invalid SSID for {self}") self.preamble = preamble if preamble != None else 350; self.txtail = txtail if txtail != None else 20; @@ -124,16 +124,16 @@ class AX25KISSInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...", RNS.LOG_VERBOSE) + RNS.log(f"Opening serial port {self.port}...", RNS.LOG_VERBOSE) self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -155,7 +155,7 @@ class AX25KISSInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Configuring AX.25 KISS interface parameters...") self.setPreamble(self.preamble) self.setTxTail(self.txtail) @@ -176,7 +176,7 @@ class AX25KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXDELAY])+bytes([preamble])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure AX.25 KISS interface preamble to "+str(preamble_ms)+" (command value "+str(preamble)+")") + raise OSError(f"Could not configure AX.25 KISS interface preamble to {preamble_ms} (command value {preamble})") def setTxTail(self, txtail): txtail_ms = txtail @@ -189,7 +189,7 @@ class AX25KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXTAIL])+bytes([txtail])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure AX.25 KISS interface TX tail to "+str(txtail_ms)+" (command value "+str(txtail)+")") + raise OSError(f"Could not configure AX.25 KISS interface TX tail to {txtail_ms} (command value {txtail})") def setPersistence(self, persistence): if persistence < 0: @@ -200,7 +200,7 @@ class AX25KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure AX.25 KISS interface persistence to "+str(persistence)) + raise OSError(f"Could not configure AX.25 KISS interface persistence to {persistence}") def setSlotTime(self, slottime): slottime_ms = slottime @@ -213,16 +213,16 @@ class AX25KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SLOTTIME])+bytes([slottime])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure AX.25 KISS interface slot time to "+str(slottime_ms)+" (command value "+str(slottime)+")") + raise OSError(f"Could not configure AX.25 KISS interface slot time to {slottime_ms} (command value {slottime})") def setFlowControl(self, flow_control): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): if (flow_control): - raise IOError("Could not enable AX.25 KISS interface flow control") + raise OSError("Could not enable AX.25 KISS interface flow control") else: - raise IOError("Could not enable AX.25 KISS interface flow control") + raise OSError("Could not enable AX.25 KISS interface flow control") def processIncoming(self, data): @@ -270,7 +270,7 @@ class AX25KISSInterface(Interface): if written != len(kiss_frame): if self.flow_control: self.interface_ready = True - raise IOError("AX.25 interface only wrote "+str(written)+" bytes of "+str(len(kiss_frame))) + raise OSError(f"AX.25 interface only wrote {written} bytes of {len(kiss_frame)}") else: self.queue(data) @@ -336,13 +336,13 @@ class AX25KISSInterface(Interface): if self.flow_control: if not self.interface_ready: if time.time() > self.flow_control_locked + self.flow_control_timeout: - RNS.log("Interface "+str(self)+" is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) + RNS.log(f"Interface {self} is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) self.process_queue() except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -357,17 +357,17 @@ class AX25KISSInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "AX25KISSInterface["+self.name+"]" \ No newline at end of file + return f"AX25KISSInterface[{self.name}]" \ No newline at end of file diff --git a/RNS/Interfaces/Android/KISSInterface.py b/RNS/Interfaces/Android/KISSInterface.py index 88514b5..4c3c8cb 100644 --- a/RNS/Interfaces/Android/KISSInterface.py +++ b/RNS/Interfaces/Android/KISSInterface.py @@ -125,17 +125,17 @@ class KISSInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port "+self.port, RNS.LOG_ERROR) + RNS.log(f"Could not open serial port {self.port}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") # Get device parameters from usb4a import usb device = usb.get_usb_device(self.port) @@ -147,7 +147,7 @@ class KISSInterface(Interface): proxy = self.pyserial.get_serial_port if vid == 0x1A86 and pid == 0x55D4: # Force CDC driver for Qinheng CH34x - RNS.log(str(self)+" using CDC driver for "+RNS.hexrep(vid)+":"+RNS.hexrep(pid), RNS.LOG_DEBUG) + RNS.log(f"{self} using CDC driver for {RNS.hexrep(vid)}:{RNS.hexrep(pid)}", RNS.LOG_DEBUG) from usbserial4a.cdcacmserial4a import CdcAcmSerial proxy = CdcAcmSerial @@ -186,9 +186,9 @@ class KISSInterface(Interface): self.serial.USB_READ_TIMEOUT_MILLIS = 100 self.serial.timeout = 0.1 - RNS.log(str(self)+" USB read buffer size set to "+RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE), RNS.LOG_DEBUG) - RNS.log(str(self)+" USB read timeout set to "+str(self.serial.USB_READ_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) - RNS.log(str(self)+" USB write timeout set to "+str(self.serial.USB_WRITE_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read buffer size set to {RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE)}", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read timeout set to {self.serial.USB_READ_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB write timeout set to {self.serial.USB_WRITE_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) def configure_device(self): # Allow time for interface to initialise before config @@ -197,7 +197,7 @@ class KISSInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Configuring KISS interface parameters...") self.setPreamble(self.preamble) self.setTxTail(self.txtail) @@ -218,7 +218,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXDELAY])+bytes([preamble])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface preamble to "+str(preamble_ms)+" (command value "+str(preamble)+")") + raise OSError(f"Could not configure KISS interface preamble to {preamble_ms} (command value {preamble})") def setTxTail(self, txtail): txtail_ms = txtail @@ -231,7 +231,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXTAIL])+bytes([txtail])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface TX tail to "+str(txtail_ms)+" (command value "+str(txtail)+")") + raise OSError(f"Could not configure KISS interface TX tail to {txtail_ms} (command value {txtail})") def setPersistence(self, persistence): if persistence < 0: @@ -242,7 +242,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface persistence to "+str(persistence)) + raise OSError(f"Could not configure KISS interface persistence to {persistence}") def setSlotTime(self, slottime): slottime_ms = slottime @@ -255,16 +255,16 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SLOTTIME])+bytes([slottime])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface slot time to "+str(slottime_ms)+" (command value "+str(slottime)+")") + raise OSError(f"Could not configure KISS interface slot time to {slottime_ms} (command value {slottime})") def setFlowControl(self, flow_control): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): if (flow_control): - raise IOError("Could not enable KISS interface flow control") + raise OSError("Could not enable KISS interface flow control") else: - raise IOError("Could not enable KISS interface flow control") + raise OSError("Could not enable KISS interface flow control") def processIncoming(self, data): @@ -295,7 +295,7 @@ class KISSInterface(Interface): self.first_tx = time.time() if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") else: self.queue(data) @@ -365,20 +365,20 @@ class KISSInterface(Interface): if self.flow_control: if not self.interface_ready: if time.time() > self.flow_control_locked + self.flow_control_timeout: - RNS.log("Interface "+str(self)+" is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) + RNS.log(f"Interface {self} is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) self.process_queue() if self.beacon_i != None and self.beacon_d != None: if self.first_tx != None: if time.time() > self.first_tx + self.beacon_i: - RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.beacon_d.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data: {self.beacon_d.decode('utf-8')}", RNS.LOG_DEBUG) self.first_tx = None self.processOutgoing(self.beacon_d) except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -393,17 +393,17 @@ class KISSInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "KISSInterface["+self.name+"]" \ No newline at end of file + return f"KISSInterface[{self.name}]" \ No newline at end of file diff --git a/RNS/Interfaces/Android/RNodeInterface.py b/RNS/Interfaces/Android/RNodeInterface.py index 9594acc..d600bd5 100644 --- a/RNS/Interfaces/Android/RNodeInterface.py +++ b/RNS/Interfaces/Android/RNodeInterface.py @@ -172,7 +172,7 @@ class AndroidBluetoothManager(): try: self.rfcomm_socket = device.createRfcommSocketToServiceRecord(self.bt_rfcomm_service_record) if self.rfcomm_socket == None: - raise IOError("Bluetooth stack returned no socket object") + raise OSError("Bluetooth stack returned no socket object") else: if not self.rfcomm_socket.isConnected(): try: @@ -181,13 +181,13 @@ class AndroidBluetoothManager(): self.rfcomm_writer = self.rfcomm_socket.getOutputStream() self.connected = True self.connected_device = device - RNS.log("Bluetooth device "+str(self.connected_device.getName())+" "+str(self.connected_device.getAddress())+" connected.") + RNS.log(f"Bluetooth device {self.connected_device.getName()} {self.connected_device.getAddress()} connected.") except Exception as e: - raise IOError("The Bluetooth RFcomm socket could not be connected: "+str(e)) + raise OSError(f"The Bluetooth RFcomm socket could not be connected: {e}") except Exception as e: - RNS.log("Could not create and connect Bluetooth RFcomm socket for "+str(device.getName())+" "+str(device.getAddress()), RNS.LOG_EXTREME) - RNS.log("The contained exception was: "+str(e), RNS.LOG_EXTREME) + RNS.log(f"Could not create and connect Bluetooth RFcomm socket for {device.getName()} {device.getAddress()}", RNS.LOG_EXTREME) + RNS.log(f"The contained exception was: {e}", RNS.LOG_EXTREME) def close(self): if self.connected: @@ -209,7 +209,7 @@ class AndroidBluetoothManager(): def read(self, len = None): if self.connection_failed: - raise IOError("Bluetooth connection failed") + raise OSError("Bluetooth connection failed") else: if self.connected and self.rfcomm_reader != None: available = self.rfcomm_reader.available() @@ -223,7 +223,7 @@ class AndroidBluetoothManager(): else: return bytes([]) else: - raise IOError("No RFcomm socket available") + raise OSError("No RFcomm socket available") def write(self, data): try: @@ -231,7 +231,7 @@ class AndroidBluetoothManager(): self.rfcomm_writer.flush() return len(data) except Exception as e: - RNS.log("Bluetooth connection failed for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Bluetooth connection failed for {self}", RNS.LOG_ERROR) self.connection_failed = True return 0 @@ -274,7 +274,7 @@ class RNodeInterface(Interface): bluetooth_state = 0x00 if port != None: - RNS.log("Opening serial port "+port+"...") + RNS.log(f"Opening serial port {port}...") # Get device parameters from usb4a import usb device = usb.get_usb_device(port) @@ -287,7 +287,7 @@ class RNodeInterface(Interface): proxy = pyserial.get_serial_port if vid == 0x1A86 and pid == 0x55D4: # Force CDC driver for Qinheng CH34x - RNS.log("Using CDC driver for "+RNS.hexrep(vid)+":"+RNS.hexrep(pid), RNS.LOG_DEBUG) + RNS.log(f"Using CDC driver for {RNS.hexrep(vid)}:{RNS.hexrep(pid)}", RNS.LOG_DEBUG) from usbserial4a.cdcacmserial4a import CdcAcmSerial proxy = CdcAcmSerial @@ -466,31 +466,31 @@ class RNodeInterface(Interface): self.validcfg = True if (self.frequency < RNodeInterface.FREQ_MIN or self.frequency > RNodeInterface.FREQ_MAX): - RNS.log("Invalid frequency configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid frequency configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.txpower < 0 or self.txpower > 22): - RNS.log("Invalid TX power configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid TX power configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.bandwidth < 7800 or self.bandwidth > 500000): - RNS.log("Invalid bandwidth configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid bandwidth configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.sf < 5 or self.sf > 12): - RNS.log("Invalid spreading factor configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid spreading factor configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.cr < 5 or self.cr > 8): - RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid coding rate configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)): - RNS.log("Invalid short-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid short-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)): - RNS.log("Invalid long-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid long-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if id_interval != None and id_callsign != None: @@ -499,14 +499,14 @@ class RNodeInterface(Interface): self.id_callsign = id_callsign.encode("utf-8") self.id_interval = id_interval else: - RNS.log("The encoded ID callsign for "+str(self)+" exceeds the max length of "+str(RNodeInterface.CALLSIGN_MAX_LEN)+" bytes.", RNS.LOG_ERROR) + RNS.log(f"The encoded ID callsign for {self} exceeds the max length of {RNodeInterface.CALLSIGN_MAX_LEN} bytes.", RNS.LOG_ERROR) self.validcfg = False else: self.id_interval = None self.id_callsign = None if (not self.validcfg): - raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline") + raise ValueError(f"The configuration for {self} contains errors, interface is offline") try: self.open_port() @@ -515,18 +515,18 @@ class RNodeInterface(Interface): if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") elif self.bt_manager != None: if self.bt_manager.connected: self.configure_device() else: - raise IOError("Could not connect to any Bluetooth devices") + raise OSError("Could not connect to any Bluetooth devices") else: - raise IOError("Neither serial port nor Bluetooth devices available") + raise OSError("Neither serial port nor Bluetooth devices available") except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) if len(self.hw_errors) == 0: RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR) thread = threading.Thread(target=self.reconnect_port, daemon=True).start() @@ -538,7 +538,7 @@ class RNodeInterface(Interface): elif self.bt_manager != None: return self.bt_manager.read() else: - raise IOError("No ports available for reading") + raise OSError("No ports available for reading") def write_mux(self, data): if self.serial != None: @@ -551,7 +551,7 @@ class RNodeInterface(Interface): self.last_port_io = time.time() return written else: - raise IOError("No ports available for writing") + raise OSError("No ports available for writing") # def reset_ble(self): # RNS.log(f"Clearing previous connection instance: "+str(self.ble)) @@ -565,7 +565,7 @@ class RNodeInterface(Interface): def open_port(self): if not self.use_ble: if self.port != None: - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") # Get device parameters from usb4a import usb device = usb.get_usb_device(self.port) @@ -577,7 +577,7 @@ class RNodeInterface(Interface): proxy = self.pyserial.get_serial_port if vid == 0x1A86 and pid == 0x55D4: # Force CDC driver for Qinheng CH34x - RNS.log(str(self)+" using CDC driver for "+RNS.hexrep(vid)+":"+RNS.hexrep(pid), RNS.LOG_DEBUG) + RNS.log(f"{self} using CDC driver for {RNS.hexrep(vid)}:{RNS.hexrep(pid)}", RNS.LOG_DEBUG) from usbserial4a.cdcacmserial4a import CdcAcmSerial proxy = CdcAcmSerial @@ -616,9 +616,9 @@ class RNodeInterface(Interface): self.serial.USB_READ_TIMEOUT_MILLIS = 100 self.serial.timeout = 0.1 - RNS.log(str(self)+" USB read buffer size set to "+RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE), RNS.LOG_DEBUG) - RNS.log(str(self)+" USB read timeout set to "+str(self.serial.USB_READ_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) - RNS.log(str(self)+" USB write timeout set to "+str(self.serial.USB_WRITE_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read buffer size set to {RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE)}", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read timeout set to {self.serial.USB_READ_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB write timeout set to {self.serial.USB_WRITE_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) elif self.allow_bluetooth: if self.bt_manager == None: @@ -660,17 +660,17 @@ class RNodeInterface(Interface): RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR) if not self.detected: - raise IOError("Could not detect device") + raise OSError("Could not detect device") else: if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52: self.display = True if not self.firmware_ok: - raise IOError("Invalid device firmware") + raise OSError("Invalid device firmware") if self.serial != None and self.port != None: self.timeout = 200 - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") if self.bt_manager != None and self.bt_manager.connected: self.timeout = 1500 @@ -680,11 +680,11 @@ class RNodeInterface(Interface): self.initRadio() if (self.validateRadioState()): self.interface_ready = True - RNS.log(str(self)+" is configured and powered up") + RNS.log(f"{self} is configured and powered up") sleep(0.3) self.online = True else: - RNS.log("After configuring "+str(self)+", the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) + RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR) @@ -693,7 +693,7 @@ class RNodeInterface(Interface): if self.bt_manager != None: self.bt_manager.close() - raise IOError("RNode interface did not pass configuration validation") + raise OSError("RNode interface did not pass configuration validation") def initRadio(self): @@ -728,45 +728,45 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while detecting hardware for "+str(self)) + raise OSError(f"An IO error occurred while detecting hardware for {self}") def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending host left command to device") + raise OSError("An IO error occurred while sending host left command to device") def enable_bluetooth(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth enable command to device") + raise OSError("An IO error occurred while sending bluetooth enable command to device") def disable_bluetooth(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x00, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth disable command to device") + raise OSError("An IO error occurred while sending bluetooth disable command to device") def bluetooth_pair(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x02, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth pair command to device") + raise OSError("An IO error occurred while sending bluetooth pair command to device") def enable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while enabling external framebuffer on device") + raise OSError("An IO error occurred while enabling external framebuffer on device") def disable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while disabling external framebuffer on device") + raise OSError("An IO error occurred while disabling external framebuffer on device") FB_PIXEL_WIDTH = 64 FB_BITS_PER_PIXEL = 1 @@ -791,13 +791,13 @@ class RNodeInterface(Interface): written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while writing framebuffer data device") + raise OSError("An IO error occurred while writing framebuffer data device") def hard_reset(self): kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while restarting device") + raise OSError("An IO error occurred while restarting device") sleep(4.0); def setFrequency(self): @@ -810,7 +810,7 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring frequency for "+str(self)) + raise OSError(f"An IO error occurred while configuring frequency for {self}") def setBandwidth(self): c1 = self.bandwidth >> 24 @@ -822,28 +822,28 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring bandwidth for "+str(self)) + raise OSError(f"An IO error occurred while configuring bandwidth for {self}") def setTXPower(self): txp = bytes([self.txpower]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring TX power for "+str(self)) + raise OSError(f"An IO error occurred while configuring TX power for {self}") def setSpreadingFactor(self): sf = bytes([self.sf]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring spreading factor for "+str(self)) + raise OSError(f"An IO error occurred while configuring spreading factor for {self}") def setCodingRate(self): cr = bytes([self.cr]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring coding rate for "+str(self)) + raise OSError(f"An IO error occurred while configuring coding rate for {self}") def setSTALock(self): if self.st_alock != None: @@ -855,7 +855,7 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring short-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring short-term airtime limit for {self}") def setLTALock(self): if self.lt_alock != None: @@ -867,14 +867,14 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring long-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring long-term airtime limit for {self}") def setRadioState(self, state): self.state = state kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) written = self.write_mux(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state for "+str(self)) + raise OSError(f"An IO error occurred while configuring radio state for {self}") def validate_firmware(self): if (self.maj_version > RNodeInterface.REQUIRED_FW_VER_MAJ): @@ -887,17 +887,17 @@ class RNodeInterface(Interface): if self.firmware_ok: return - RNS.log("The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version), RNS.LOG_ERROR) - RNS.log("This version of Reticulum requires at least version "+str(RNodeInterface.REQUIRED_FW_VER_MAJ)+"."+str(RNodeInterface.REQUIRED_FW_VER_MIN), RNS.LOG_ERROR) + RNS.log(f"The firmware version of the connected RNode is {self.maj_version}.{self.min_version}", RNS.LOG_ERROR) + RNS.log(f"This version of Reticulum requires at least version {RNodeInterface.REQUIRED_FW_VER_MAJ}.{RNodeInterface.REQUIRED_FW_VER_MIN}", RNS.LOG_ERROR) RNS.log("Please update your RNode firmware with rnodeconf from https://github.com/markqvist/reticulum/") - error_description = "The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version)+". " - error_description += "This version of Reticulum requires at least version "+str(RNodeInterface.REQUIRED_FW_VER_MAJ)+"."+str(RNodeInterface.REQUIRED_FW_VER_MIN)+". " + error_description = f"The firmware version of the connected RNode is {self.maj_version}.{self.min_version}. " + error_description += f"This version of Reticulum requires at least version {RNodeInterface.REQUIRED_FW_VER_MAJ}.{RNodeInterface.REQUIRED_FW_VER_MIN}. " error_description += "Please update your RNode firmware with rnodeconf from: https://github.com/markqvist/rnodeconfigutil/" self.hw_errors.append({"error": KISS.ERROR_INVALID_FIRMWARE, "description": error_description}) def validateRadioState(self): - RNS.log("Waiting for radio configuration validation for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Waiting for radio configuration validation for {self}...", RNS.LOG_VERBOSE) if not self.platform == KISS.PLATFORM_ESP32: sleep(1.00); else: @@ -937,7 +937,7 @@ class RNodeInterface(Interface): try: self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 self.bitrate_kbps = round(self.bitrate/1000.0, 2) - RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_VERBOSE) + RNS.log(f"{self} On-air bitrate is now {self.bitrate_kbps} kbps", RNS.LOG_VERBOSE) except: self.bitrate = 0 @@ -969,7 +969,7 @@ class RNodeInterface(Interface): self.txb += datalen if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") else: self.queue(data) @@ -1042,7 +1042,7 @@ class RNodeInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self)+" Radio reporting frequency is "+str(self.r_frequency/1000000.0)+" MHz", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting frequency is {self.r_frequency / 1000000.0} MHz", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_BANDWIDTH): @@ -1058,26 +1058,26 @@ class RNodeInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self)+" Radio reporting bandwidth is "+str(self.r_bandwidth/1000.0)+" KHz", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting bandwidth is {self.r_bandwidth / 1000.0} KHz", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_TXPOWER): self.r_txpower = byte - RNS.log(str(self)+" Radio reporting TX power is "+str(self.r_txpower)+" dBm", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting TX power is {self.r_txpower} dBm", RNS.LOG_DEBUG) elif (command == KISS.CMD_SF): self.r_sf = byte - RNS.log(str(self)+" Radio reporting spreading factor is "+str(self.r_sf), RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting spreading factor is {self.r_sf}", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_CR): self.r_cr = byte - RNS.log(str(self)+" Radio reporting coding rate is "+str(self.r_cr), RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting coding rate is {self.r_cr}", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_RADIO_STATE): self.r_state = byte if self.r_state: - RNS.log(str(self)+" Radio reporting state is online", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting state is online", RNS.LOG_DEBUG) else: - RNS.log(str(self)+" Radio reporting state is offline", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting state is offline", RNS.LOG_DEBUG) elif (command == KISS.CMD_RADIO_LOCK): self.r_lock = byte @@ -1156,7 +1156,7 @@ class RNodeInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.r_st_alock = at/100.0 - RNS.log(str(self)+" Radio reporting short-term airtime limit is "+str(self.r_st_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting short-term airtime limit is {self.r_st_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_LT_ALOCK): if (byte == KISS.FESC): escape = True @@ -1171,7 +1171,7 @@ class RNodeInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.r_lt_alock = at/100.0 - RNS.log(str(self)+" Radio reporting long-term airtime limit is "+str(self.r_lt_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting long-term airtime limit is {self.r_lt_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_CHTM): if (byte == KISS.FESC): escape = True @@ -1217,9 +1217,9 @@ class RNodeInterface(Interface): self.r_preamble_symbols = prs self.r_premable_time_ms = prt self.r_csma_slot_time_ms = cst - RNS.log(str(self)+" Radio reporting symbol time is "+str(round(self.r_symbol_time_ms,2))+"ms (at "+str(self.r_symbol_rate)+" baud)", RNS.LOG_DEBUG) - RNS.log(str(self)+" Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", RNS.LOG_DEBUG) - RNS.log(str(self)+" Radio reporting CSMA slot time is "+str(self.r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting symbol time is {round(self.r_symbol_time_ms, 2)}ms (at {self.r_symbol_rate} baud)", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting preamble is {self.r_preamble_symbols} symbols ({self.r_premable_time_ms}ms)", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting CSMA slot time is {self.r_csma_slot_time_ms}ms", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_BAT): if (byte == KISS.FESC): escape = True @@ -1247,26 +1247,26 @@ class RNodeInterface(Interface): self.mcu = byte elif (command == KISS.CMD_ERROR): if (byte == KISS.ERROR_INITRADIO): - RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Radio initialisation failure") + RNS.log(f"{self} hardware initialisation error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Radio initialisation failure") elif (byte == KISS.ERROR_TXFAILED): - RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Hardware transmit failure") + RNS.log(f"{self} hardware TX error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Hardware transmit failure") elif (byte == KISS.ERROR_MEMORY_LOW): - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+"): Memory exhausted", RNS.LOG_ERROR) + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)}): Memory exhausted", RNS.LOG_ERROR) self.hw_errors.append({"error": KISS.ERROR_MEMORY_LOW, "description": "Memory exhausted on connected device"}) elif (byte == KISS.ERROR_MODEM_TIMEOUT): - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+"): Modem communication timed out", RNS.LOG_ERROR) + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)}): Modem communication timed out", RNS.LOG_ERROR) self.hw_errors.append({"error": KISS.ERROR_MODEM_TIMEOUT, "description": "Modem communication timed out on connected device"}) else: - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Unknown hardware failure") + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Unknown hardware failure") elif (command == KISS.CMD_RESET): if (byte == 0xF8): if self.platform == KISS.PLATFORM_ESP32: if self.online: RNS.log("Detected reset while device was online, reinitialising device...", RNS.LOG_ERROR) - raise IOError("ESP32 reset") + raise OSError("ESP32 reset") elif (command == KISS.CMD_READY): self.process_queue() elif (command == KISS.CMD_DETECT): @@ -1278,7 +1278,7 @@ class RNodeInterface(Interface): if got == 0: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: - RNS.log(str(self)+" serial read timeout in command "+str(command), RNS.LOG_WARNING) + RNS.log(f"{self} serial read timeout in command {command}", RNS.LOG_WARNING) data_buffer = b"" in_frame = False command = KISS.CMD_UNKNOWN @@ -1287,22 +1287,22 @@ class RNodeInterface(Interface): if self.id_interval != None and self.id_callsign != None: if self.first_tx != None: if time.time() > self.first_tx + self.id_interval: - RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.id_callsign.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data: {self.id_callsign.decode('utf-8')}", RNS.LOG_DEBUG) self.processOutgoing(self.id_callsign) if (time.time() - self.last_port_io > self.port_io_timeout): self.detect() if (time.time() - self.last_port_io > self.port_io_timeout*3): - raise IOError("Connected port for "+str(self)+" became unresponsive") + raise OSError(f"Connected port for {self} became unresponsive") if self.bt_manager != None: sleep(0.08) except Exception as e: self.online = False - RNS.log("A serial port occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -1330,10 +1330,10 @@ class RNodeInterface(Interface): try: time.sleep(self.reconnect_w) if self.serial != None and self.port != None: - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_EXTREME) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_EXTREME) if self.bt_manager != None: - RNS.log("Attempting to reconnect Bluetooth device for "+str(self)+"...", RNS.LOG_EXTREME) + RNS.log(f"Attempting to reconnect Bluetooth device for {self}...", RNS.LOG_EXTREME) self.open_port() @@ -1352,10 +1352,10 @@ class RNodeInterface(Interface): self.enable_external_framebuffer() except Exception as e: - RNS.log("Error while reconnecting RNode, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting RNode, the contained exception was: {e}", RNS.LOG_ERROR) if self.online: - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def detach(self): self.detached = True @@ -1399,7 +1399,7 @@ class RNodeInterface(Interface): return data def __str__(self): - return "RNodeInterface["+str(self.name)+"]" + return f"RNodeInterface[{self.name}]" class BLEConnection(BluetoothDispatcher): UART_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e" @@ -1472,7 +1472,7 @@ class BLEConnection(BluetoothDispatcher): RNS.trace_exception(e) def __init__(self, owner=None, target_name=None, target_bt_addr=None): - super(BLEConnection, self).__init__() + super().__init__() self.owner = owner self.target_name = target_name self.target_bt_addr = target_bt_addr diff --git a/RNS/Interfaces/Android/SerialInterface.py b/RNS/Interfaces/Android/SerialInterface.py index 7d3d905..db7d47a 100644 --- a/RNS/Interfaces/Android/SerialInterface.py +++ b/RNS/Interfaces/Android/SerialInterface.py @@ -98,17 +98,17 @@ class SerialInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") # Get device parameters from usb4a import usb device = usb.get_usb_device(self.port) @@ -120,7 +120,7 @@ class SerialInterface(Interface): proxy = self.pyserial.get_serial_port if vid == 0x1A86 and pid == 0x55D4: # Force CDC driver for Qinheng CH34x - RNS.log(str(self)+" using CDC driver for "+RNS.hexrep(vid)+":"+RNS.hexrep(pid), RNS.LOG_DEBUG) + RNS.log(f"{self} using CDC driver for {RNS.hexrep(vid)}:{RNS.hexrep(pid)}", RNS.LOG_DEBUG) from usbserial4a.cdcacmserial4a import CdcAcmSerial proxy = CdcAcmSerial @@ -159,9 +159,9 @@ class SerialInterface(Interface): self.serial.USB_READ_TIMEOUT_MILLIS = 100 self.serial.timeout = 0.1 - RNS.log(str(self)+" USB read buffer size set to "+RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE), RNS.LOG_DEBUG) - RNS.log(str(self)+" USB read timeout set to "+str(self.serial.USB_READ_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) - RNS.log(str(self)+" USB write timeout set to "+str(self.serial.USB_WRITE_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read buffer size set to {RNS.prettysize(self.serial.DEFAULT_READ_BUFFER_SIZE)}", RNS.LOG_DEBUG) + RNS.log(f"{self} USB read timeout set to {self.serial.USB_READ_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) + RNS.log(f"{self} USB write timeout set to {self.serial.USB_WRITE_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG) def configure_device(self): sleep(0.5) @@ -169,7 +169,7 @@ class SerialInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open", RNS.LOG_VERBOSE) + RNS.log(f"Serial port {self.port} is now open", RNS.LOG_VERBOSE) def processIncoming(self, data): @@ -184,7 +184,7 @@ class SerialInterface(Interface): written = self.serial.write(data) self.txb += len(data) if written != len(data): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") def readLoop(self): try: @@ -228,8 +228,8 @@ class SerialInterface(Interface): except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -244,17 +244,17 @@ class SerialInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "SerialInterface["+self.name+"]" + return f"SerialInterface[{self.name}]" diff --git a/RNS/Interfaces/Android/__init__.py b/RNS/Interfaces/Android/__init__.py index ba9eae1..b92fa56 100644 --- a/RNS/Interfaces/Android/__init__.py +++ b/RNS/Interfaces/Android/__init__.py @@ -23,5 +23,5 @@ import os import glob -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] \ No newline at end of file diff --git a/RNS/Interfaces/AutoInterface.py b/RNS/Interfaces/AutoInterface.py index 75c52d2..06ed77c 100644 --- a/RNS/Interfaces/AutoInterface.py +++ b/RNS/Interfaces/AutoInterface.py @@ -35,7 +35,7 @@ import RNS class AutoInterface(Interface): DEFAULT_DISCOVERY_PORT = 29716 DEFAULT_DATA_PORT = 42671 - DEFAULT_GROUP_ID = "reticulum".encode("utf-8") + DEFAULT_GROUP_ID = b"reticulum" SCOPE_LINK = "2" SCOPE_ADMIN = "4" @@ -169,32 +169,32 @@ class AutoInterface(Interface): self.group_hash = RNS.Identity.full_hash(self.group_id) g = self.group_hash - #gt = "{:02x}".format(g[1]+(g[0]<<8)) + #gt = f"{g[1] + (g[0] << 8):02x}" gt = "0" - gt += ":"+"{:02x}".format(g[3]+(g[2]<<8)) - gt += ":"+"{:02x}".format(g[5]+(g[4]<<8)) - gt += ":"+"{:02x}".format(g[7]+(g[6]<<8)) - gt += ":"+"{:02x}".format(g[9]+(g[8]<<8)) - gt += ":"+"{:02x}".format(g[11]+(g[10]<<8)) - gt += ":"+"{:02x}".format(g[13]+(g[12]<<8)) - self.mcast_discovery_address = "ff"+self.multicast_address_type+self.discovery_scope+":"+gt + gt += f":{g[3] + (g[2] << 8):02x}" + gt += f":{g[5] + (g[4] << 8):02x}" + gt += f":{g[7] + (g[6] << 8):02x}" + gt += f":{g[9] + (g[8] << 8):02x}" + gt += f":{g[11] + (g[10] << 8):02x}" + gt += f":{g[13] + (g[12] << 8):02x}" + self.mcast_discovery_address = f"ff{self.multicast_address_type}{self.discovery_scope}:{gt}" suitable_interfaces = 0 for ifname in self.list_interfaces(): try: if RNS.vendor.platformutils.is_darwin() and ifname in AutoInterface.DARWIN_IGNORE_IFS and not ifname in self.allowed_interfaces: - RNS.log(str(self)+" skipping Darwin AWDL or tethering interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} skipping Darwin AWDL or tethering interface {ifname}", RNS.LOG_EXTREME) elif RNS.vendor.platformutils.is_darwin() and ifname == "lo0": - RNS.log(str(self)+" skipping Darwin loopback interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} skipping Darwin loopback interface {ifname}", RNS.LOG_EXTREME) elif RNS.vendor.platformutils.is_android() and ifname in AutoInterface.ANDROID_IGNORE_IFS and not ifname in self.allowed_interfaces: - RNS.log(str(self)+" skipping Android system interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} skipping Android system interface {ifname}", RNS.LOG_EXTREME) elif ifname in self.ignored_interfaces: - RNS.log(str(self)+" ignoring disallowed interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} ignoring disallowed interface {ifname}", RNS.LOG_EXTREME) elif ifname in AutoInterface.ALL_IGNORE_IFS: - RNS.log(str(self)+" skipping interface "+str(ifname), RNS.LOG_EXTREME) + RNS.log(f"{self} skipping interface {ifname}", RNS.LOG_EXTREME) else: if len(self.allowed_interfaces) > 0 and not ifname in self.allowed_interfaces: - RNS.log(str(self)+" ignoring interface "+str(ifname)+" since it was not allowed", RNS.LOG_EXTREME) + RNS.log(f"{self} ignoring interface {ifname} since it was not allowed", RNS.LOG_EXTREME) else: addresses = self.list_addresses(ifname) if self.netinfo.AF_INET6 in addresses: @@ -213,10 +213,10 @@ class AutoInterface(Interface): RNS.log(f"{self} Selecting link-local address {link_local_addr} for interface {ifname}", RNS.LOG_EXTREME) if link_local_addr == None: - RNS.log(str(self)+" No link-local IPv6 address configured for "+str(ifname)+", skipping interface", RNS.LOG_EXTREME) + RNS.log(f"{self} No link-local IPv6 address configured for {ifname}, skipping interface", RNS.LOG_EXTREME) else: mcast_addr = self.mcast_discovery_address - RNS.log(str(self)+" Creating multicast discovery listener on "+str(ifname)+" with address "+str(mcast_addr), RNS.LOG_EXTREME) + RNS.log(f"{self} Creating multicast discovery listener on {ifname} with address {mcast_addr}", RNS.LOG_EXTREME) # Struct with interface index if_struct = struct.pack("I", self.interface_name_to_index(ifname)) @@ -243,7 +243,7 @@ class AutoInterface(Interface): else: if self.discovery_scope == AutoInterface.SCOPE_LINK: - addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) + addr_info = socket.getaddrinfo(f"{mcast_addr}%{ifname}", self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) else: addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) @@ -267,7 +267,7 @@ class AutoInterface(Interface): RNS.log(f"Could not configure the system interface {ifname} for use with {self}, skipping it. The contained exception was: {e}", RNS.LOG_ERROR) if suitable_interfaces == 0: - RNS.log(str(self)+" could not autoconfigure. This interface currently provides no connectivity.", RNS.LOG_WARNING) + RNS.log(f"{self} could not autoconfigure. This interface currently provides no connectivity.", RNS.LOG_WARNING) else: self.receives = True @@ -277,13 +277,13 @@ class AutoInterface(Interface): self.bitrate = AutoInterface.BITRATE_GUESS peering_wait = self.announce_interval*1.2 - RNS.log(str(self)+" discovering peers for "+str(round(peering_wait, 2))+" seconds...", RNS.LOG_VERBOSE) + RNS.log(f"{self} discovering peers for {round(peering_wait, 2)} seconds...", RNS.LOG_VERBOSE) self.owner = owner socketserver.UDPServer.address_family = socket.AF_INET6 for ifname in self.adopted_interfaces: - local_addr = self.adopted_interfaces[ifname]+"%"+str(self.interface_name_to_index(ifname)) + local_addr = f"{self.adopted_interfaces[ifname]}%{self.interface_name_to_index(ifname)}" addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) address = addr_info[0][4] @@ -317,7 +317,7 @@ class AutoInterface(Interface): if data == expected_hash: self.add_peer(ipv6_src[0], ifname) else: - RNS.log(str(self)+" received peering packet on "+str(ifname)+" from "+str(ipv6_src[0])+", but authentication hash was incorrect.", RNS.LOG_DEBUG) + RNS.log(f"{self} received peering packet on {ifname} from {ipv6_src[0]}, but authentication hash was incorrect.", RNS.LOG_DEBUG) def peer_jobs(self): while True: @@ -335,7 +335,7 @@ class AutoInterface(Interface): # Remove any timed out peers for peer_addr in timed_out_peers: removed_peer = self.peers.pop(peer_addr) - RNS.log(str(self)+" removed peer "+str(peer_addr)+" on "+str(removed_peer[0]), RNS.LOG_DEBUG) + RNS.log(f"{self} removed peer {peer_addr} on {removed_peer[0]}", RNS.LOG_DEBUG) for ifname in self.adopted_interfaces: # Check that the link-local address has not changed @@ -349,25 +349,25 @@ class AutoInterface(Interface): link_local_addr = self.descope_linklocal(address["addr"]) if link_local_addr != self.adopted_interfaces[ifname]: old_link_local_address = self.adopted_interfaces[ifname] - RNS.log("Replacing link-local address "+str(old_link_local_address)+" for "+str(ifname)+" with "+str(link_local_addr), RNS.LOG_DEBUG) + RNS.log(f"Replacing link-local address {old_link_local_address} for {ifname} with {link_local_addr}", RNS.LOG_DEBUG) self.adopted_interfaces[ifname] = link_local_addr self.link_local_addresses.append(link_local_addr) if old_link_local_address in self.link_local_addresses: self.link_local_addresses.remove(old_link_local_address) - local_addr = link_local_addr+"%"+ifname + local_addr = f"{link_local_addr}%{ifname}" addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) listen_address = addr_info[0][4] if ifname in self.interface_servers: - RNS.log("Shutting down previous UDP listener for "+str(self)+" "+str(ifname), RNS.LOG_DEBUG) + RNS.log(f"Shutting down previous UDP listener for {self} {ifname}", RNS.LOG_DEBUG) previous_server = self.interface_servers[ifname] def shutdown_server(): previous_server.shutdown() threading.Thread(target=shutdown_server, daemon=True).start() - RNS.log("Starting new UDP listener for "+str(self)+" "+str(ifname), RNS.LOG_DEBUG) + RNS.log(f"Starting new UDP listener for {self} {ifname}", RNS.LOG_DEBUG) udp_server = socketserver.UDPServer(listen_address, self.handler_factory(self.processIncoming)) self.interface_servers[ifname] = udp_server @@ -379,7 +379,7 @@ class AutoInterface(Interface): self.carrier_changed = True except Exception as e: - RNS.log("Could not get device information while updating link-local addresses for "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not get device information while updating link-local addresses for {self}. The contained exception was: {e}", RNS.LOG_ERROR) # Check multicast echo timeouts last_multicast_echo = 0 @@ -389,12 +389,12 @@ class AutoInterface(Interface): if now - last_multicast_echo > self.multicast_echo_timeout: if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == False: self.carrier_changed = True - RNS.log("Multicast echo timeout for "+str(ifname)+". Carrier lost.", RNS.LOG_WARNING) + RNS.log(f"Multicast echo timeout for {ifname}. Carrier lost.", RNS.LOG_WARNING) self.timed_out_interfaces[ifname] = True else: if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == True: self.carrier_changed = True - RNS.log(str(self)+" Carrier recovered on "+str(ifname), RNS.LOG_WARNING) + RNS.log(f"{self} Carrier recovered on {ifname}", RNS.LOG_WARNING) self.timed_out_interfaces[ifname] = False @@ -417,7 +417,7 @@ class AutoInterface(Interface): except Exception as e: if (ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == False) or not ifname in self.timed_out_interfaces: - RNS.log(str(self)+" Detected possible carrier loss on "+str(ifname)+": "+str(e), RNS.LOG_WARNING) + RNS.log(f"{self} Detected possible carrier loss on {ifname}: {e}", RNS.LOG_WARNING) else: pass @@ -431,12 +431,12 @@ class AutoInterface(Interface): if ifname != None: self.multicast_echoes[ifname] = time.time() else: - RNS.log(str(self)+" received multicast echo on unexpected interface "+str(ifname), RNS.LOG_WARNING) + RNS.log(f"{self} received multicast echo on unexpected interface {ifname}", RNS.LOG_WARNING) else: if not addr in self.peers: self.peers[addr] = [ifname, time.time()] - RNS.log(str(self)+" added peer "+str(addr)+" on "+str(ifname), RNS.LOG_DEBUG) + RNS.log(f"{self} added peer {addr} on {ifname}", RNS.LOG_DEBUG) else: self.refresh_peer(addr) @@ -464,12 +464,12 @@ class AutoInterface(Interface): if self.outbound_udp_socket == None: self.outbound_udp_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) - peer_addr = str(peer)+"%"+str(self.interface_name_to_index(self.peers[peer][0])) + peer_addr = f"{peer}%{self.interface_name_to_index(self.peers[peer][0])}" addr_info = socket.getaddrinfo(peer_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) self.outbound_udp_socket.sendto(data, addr_info[0][4]) except Exception as e: - RNS.log("Could not transmit on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR) self.txb += len(data) @@ -481,7 +481,7 @@ class AutoInterface(Interface): return False def __str__(self): - return "AutoInterface["+self.name+"]" + return f"AutoInterface[{self.name}]" class AutoInterfaceHandler(socketserver.BaseRequestHandler): def __init__(self, callback, *args, **keys): diff --git a/RNS/Interfaces/I2PInterface.py b/RNS/Interfaces/I2PInterface.py index 64dee4a..7448bfa 100644 --- a/RNS/Interfaces/I2PInterface.py +++ b/RNS/Interfaces/I2PInterface.py @@ -90,7 +90,7 @@ class I2PController: time.sleep(0.10) if self.loop == None: - RNS.log("Could not get event loop for "+str(self)+", waiting for event loop to appear", RNS.LOG_VERBOSE) + RNS.log(f"Could not get event loop for {self}, waiting for event loop to appear", RNS.LOG_VERBOSE) while self.loop == None: self.loop = asyncio.get_event_loop() @@ -101,7 +101,7 @@ class I2PController: self.loop.run_forever() except Exception as e: self.ready = False - RNS.log("Exception on event loop for "+str(self)+": "+str(e), RNS.LOG_ERROR) + RNS.log(f"Exception on event loop for {self}: {e}", RNS.LOG_ERROR) finally: self.loop.close() @@ -136,7 +136,7 @@ class I2PController: if not self.client_tunnels[i2p_destination]: try: async def tunnel_up(): - RNS.log("Bringing up I2P tunnel to "+str(owner)+", this may take a while...", RNS.LOG_INFO) + RNS.log(f"Bringing up I2P tunnel to {owner}, this may take a while...", RNS.LOG_INFO) tunnel = self.i2plib.ClientTunnel(i2p_destination, owner.local_addr, sam_address=self.sam_address, loop=self.loop) self.i2plib_tunnels[i2p_destination] = tunnel await tunnel.run() @@ -145,7 +145,7 @@ class I2PController: result = asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result() if not i2p_destination in self.i2plib_tunnels: - raise IOError("No tunnel control instance was created") + raise OSError("No tunnel control instance was created") else: tn = self.i2plib_tunnels[i2p_destination] @@ -167,19 +167,19 @@ class I2PController: try: owner.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(owner)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {owner}: {e}") try: owner.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(owner)+": "+str(e)) + RNS.log(f"Error while closing socket for {owner}: {e}") self.client_tunnels[i2p_destination] = True owner.awaiting_i2p_tunnel = False - RNS.log(str(owner)+" tunnel setup complete", RNS.LOG_VERBOSE) + RNS.log(f"{owner} tunnel setup complete", RNS.LOG_VERBOSE) else: - raise IOError("Got no status response from SAM API") + raise OSError("Got no status response from SAM API") except ConnectionRefusedError as e: raise e @@ -188,7 +188,7 @@ class I2PController: raise e except Exception as e: - RNS.log("Unexpected error type from I2P SAM: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Unexpected error type from I2P SAM: {e}", RNS.LOG_ERROR) raise e else: @@ -197,16 +197,16 @@ class I2PController: i2p_exception = i2ptunnel.status["exception"] if i2ptunnel.status["setup_ran"] == False: - RNS.log(str(self)+" I2P tunnel setup did not complete", RNS.LOG_ERROR) + RNS.log(f"{self} I2P tunnel setup did not complete", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False elif i2p_exception != None: - RNS.log("An error ocurred while setting up I2P tunnel to "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while setting up I2P tunnel to {i2p_destination}", RNS.LOG_ERROR) if isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.CantReachPeer): - RNS.log("The I2P daemon can't reach peer "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon can't reach peer {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.DuplicatedDest): RNS.log("The I2P daemon reported that the destination is already in use", RNS.LOG_ERROR) @@ -218,19 +218,19 @@ class I2PController: RNS.log("The I2P daemon reported that the stream session ID doesn't exist", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.InvalidKey): - RNS.log("The I2P daemon reported that the key for "+str(i2p_destination)+" is invalid", RNS.LOG_ERROR) + RNS.log(f"The I2P daemon reported that the key for {i2p_destination} is invalid", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.KeyNotFound): - RNS.log("The I2P daemon could not find the key for "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon could not find the key for {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.PeerNotFound): - RNS.log("The I2P daemon mould not find the peer "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon mould not find the peer {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError): RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): - RNS.log("I2P daemon timed out while setting up client tunnel to "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"I2P daemon timed out while setting up client tunnel to {i2p_destination}", RNS.LOG_ERROR) RNS.log("Resetting I2P tunnel and retrying later", RNS.LOG_ERROR) @@ -238,13 +238,13 @@ class I2PController: return False elif i2ptunnel.status["setup_failed"] == True: - RNS.log(str(self)+" Unspecified I2P tunnel setup error, resetting I2P tunnel", RNS.LOG_ERROR) + RNS.log(f"{self} Unspecified I2P tunnel setup error, resetting I2P tunnel", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False else: - RNS.log(str(self)+" Got no status from SAM API, resetting I2P tunnel", RNS.LOG_ERROR) + RNS.log(f"{self} Got no status from SAM API, resetting I2P tunnel", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False @@ -259,11 +259,11 @@ class I2PController: # Old format i2p_dest_hash_of = RNS.Identity.full_hash(RNS.Identity.full_hash(owner.name.encode("utf-8"))) - i2p_keyfile_of = self.storagepath+"/"+RNS.hexrep(i2p_dest_hash_of, delimit=False)+".i2p" + i2p_keyfile_of = f"{self.storagepath}/{RNS.hexrep(i2p_dest_hash_of, delimit=False)}.i2p" # New format i2p_dest_hash_nf = RNS.Identity.full_hash(RNS.Identity.full_hash(owner.name.encode("utf-8"))+RNS.Identity.full_hash(RNS.Transport.identity.hash)) - i2p_keyfile_nf = self.storagepath+"/"+RNS.hexrep(i2p_dest_hash_nf, delimit=False)+".i2p" + i2p_keyfile_nf = f"{self.storagepath}/{RNS.hexrep(i2p_dest_hash_nf, delimit=False)}.i2p" # Use old format if a key is already present if os.path.isfile(i2p_keyfile_of): @@ -279,7 +279,7 @@ class I2PController: key_file.write(i2p_dest.private_key.base64) key_file.close() else: - key_file = open(i2p_keyfile, "r") + key_file = open(i2p_keyfile) prvd = key_file.read() key_file.close() i2p_dest = self.i2plib.Destination(data=prvd, has_private_key=True) @@ -294,12 +294,12 @@ class I2PController: if self.server_tunnels[i2p_b32] == False: try: async def tunnel_up(): - RNS.log(str(owner)+" Bringing up I2P endpoint, this may take a while...", RNS.LOG_INFO) + RNS.log(f"{owner} Bringing up I2P endpoint, this may take a while...", RNS.LOG_INFO) tunnel = self.i2plib.ServerTunnel((owner.bind_ip, owner.bind_port), loop=self.loop, destination=i2p_dest, sam_address=self.sam_address) self.i2plib_tunnels[i2p_b32] = tunnel await tunnel.run() owner.online = True - RNS.log(str(owner)+ " endpoint setup complete. Now reachable at: "+str(i2p_dest.base32)+".b32.i2p", RNS.LOG_VERBOSE) + RNS.log(f"{owner} endpoint setup complete. Now reachable at: {i2p_dest.base32}.b32.i2p", RNS.LOG_VERBOSE) asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result() self.server_tunnels[i2p_b32] = True @@ -313,7 +313,7 @@ class I2PController: i2p_exception = i2ptunnel.status["exception"] if i2ptunnel.status["setup_ran"] == False: - RNS.log(str(self)+" I2P tunnel setup did not complete", RNS.LOG_ERROR) + RNS.log(f"{self} I2P tunnel setup did not complete", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False @@ -322,7 +322,7 @@ class I2PController: RNS.log("An error ocurred while setting up I2P tunnel", RNS.LOG_ERROR) if isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.CantReachPeer): - RNS.log("The I2P daemon can't reach peer "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon can't reach peer {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.DuplicatedDest): RNS.log("The I2P daemon reported that the destination is already in use", RNS.LOG_ERROR) @@ -334,19 +334,19 @@ class I2PController: RNS.log("The I2P daemon reported that the stream session ID doesn't exist", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.InvalidKey): - RNS.log("The I2P daemon reported that the key for "+str(i2p_destination)+" is invalid", RNS.LOG_ERROR) + RNS.log(f"The I2P daemon reported that the key for {i2p_destination} is invalid", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.KeyNotFound): - RNS.log("The I2P daemon could not find the key for "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon could not find the key for {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.PeerNotFound): - RNS.log("The I2P daemon mould not find the peer "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"The I2P daemon mould not find the peer {i2p_destination}", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError): RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): - RNS.log("I2P daemon timed out while setting up client tunnel to "+str(i2p_destination), RNS.LOG_ERROR) + RNS.log(f"I2P daemon timed out while setting up client tunnel to {i2p_destination}", RNS.LOG_ERROR) RNS.log("Resetting I2P tunnel and retrying later", RNS.LOG_ERROR) @@ -354,13 +354,13 @@ class I2PController: return False elif i2ptunnel.status["setup_failed"] == True: - RNS.log(str(self)+" Unspecified I2P tunnel setup error, resetting I2P tunnel", RNS.LOG_ERROR) + RNS.log(f"{self} Unspecified I2P tunnel setup error, resetting I2P tunnel", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False else: - RNS.log(str(self)+" Got no status from SAM API, resetting I2P tunnel", RNS.LOG_ERROR) + RNS.log(f"{self} Got no status from SAM API, resetting I2P tunnel", RNS.LOG_ERROR) self.stop_tunnel(i2ptunnel) return False @@ -475,11 +475,11 @@ class I2PInterfacePeer(Interface): self.target_port = self.bind_port if not self.parent_interface.i2p.client_tunnel(self, target_i2p_dest): - RNS.log(str(self)+" I2P control process experienced an error, requesting new tunnel...", RNS.LOG_ERROR) + RNS.log(f"{self} I2P control process experienced an error, requesting new tunnel...", RNS.LOG_ERROR) self.awaiting_i2p_tunnel = True except Exception as e: - RNS.log("Error while while configuring "+str(self)+": "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while while configuring {self}: {e}", RNS.LOG_ERROR) RNS.log("Check that I2P is installed and running, and that SAM is enabled. Retrying tunnel setup later.", RNS.LOG_ERROR) time.sleep(8) @@ -532,16 +532,16 @@ class I2PInterfacePeer(Interface): if socket != None: target_socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: if socket != None: target_socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") def detach(self): - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) if self.socket != None: if hasattr(self.socket, "close"): if callable(self.socket.close): @@ -550,12 +550,12 @@ class I2PInterfacePeer(Interface): try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: self.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") self.socket = None @@ -568,8 +568,8 @@ class I2PInterfacePeer(Interface): except Exception as e: if initial: if not self.awaiting_i2p_tunnel: - RNS.log("Initial connection for "+str(self)+" could not be established: "+str(e), RNS.LOG_ERROR) - RNS.log("Leaving unconnected and retrying connection in "+str(I2PInterfacePeer.RECONNECT_WAIT)+" seconds.", RNS.LOG_ERROR) + RNS.log(f"Initial connection for {self} could not be established: {e}", RNS.LOG_ERROR) + RNS.log(f"Leaving unconnected and retrying connection in {I2PInterfacePeer.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR) return False @@ -600,7 +600,7 @@ class I2PInterfacePeer(Interface): attempts += 1 if self.max_reconnect_tries != None and attempts > self.max_reconnect_tries: - RNS.log("Max reconnection attempts reached for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Max reconnection attempts reached for {self}", RNS.LOG_ERROR) self.teardown() break @@ -609,12 +609,12 @@ class I2PInterfacePeer(Interface): except Exception as e: if not self.awaiting_i2p_tunnel: - RNS.log("Connection attempt for "+str(self)+" failed: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"Connection attempt for {self} failed: {e}", RNS.LOG_DEBUG) else: - RNS.log(str(self)+" still waiting for I2P tunnel to appear", RNS.LOG_VERBOSE) + RNS.log(f"{self} still waiting for I2P tunnel to appear", RNS.LOG_VERBOSE) if not self.never_connected: - RNS.log(str(self)+" Re-established connection via I2P tunnel", RNS.LOG_INFO) + RNS.log(f"{self} Re-established connection via I2P tunnel", RNS.LOG_INFO) self.reconnecting = False thread = threading.Thread(target=self.read_loop) @@ -625,7 +625,7 @@ class I2PInterfacePeer(Interface): else: RNS.log("Attempt to reconnect on a non-initiator I2P interface. This should not happen.", RNS.LOG_ERROR) - raise IOError("Attempt to reconnect on a non-initiator I2P interface") + raise OSError("Attempt to reconnect on a non-initiator I2P interface") def processIncoming(self, data): self.rxb += len(data) @@ -656,8 +656,8 @@ class I2PInterfacePeer(Interface): self.parent_interface.txb += len(data) except Exception as e: - RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Exception occurred while transmitting via {self}, tearing down interface", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.teardown() @@ -683,7 +683,7 @@ class I2PInterfacePeer(Interface): if self.socket != None: self.socket.sendall(bytes([HDLC.FLAG, HDLC.FLAG])) except Exception as e: - RNS.log("An error ocurred while sending I2P keepalive. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while sending I2P keepalive. The contained exception was: {e}", RNS.LOG_ERROR) self.shutdown_socket(self.socket) should_run = False @@ -693,12 +693,12 @@ class I2PInterfacePeer(Interface): try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: self.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") should_run = False @@ -782,10 +782,10 @@ class I2PInterfacePeer(Interface): self.wd_reset = False if self.initiator and not self.detached: - RNS.log("Socket for "+str(self)+" was closed, attempting to reconnect...", RNS.LOG_WARNING) + RNS.log(f"Socket for {self} was closed, attempting to reconnect...", RNS.LOG_WARNING) self.reconnect() else: - RNS.log("Socket for remote client "+str(self)+" was closed.", RNS.LOG_VERBOSE) + RNS.log(f"Socket for remote client {self} was closed.", RNS.LOG_VERBOSE) self.teardown() break @@ -793,7 +793,7 @@ class I2PInterfacePeer(Interface): except Exception as e: self.online = False - RNS.log("An interface error occurred for "+str(self)+", the contained exception was: "+str(e), RNS.LOG_WARNING) + RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING) if self.initiator: RNS.log("Attempting to reconnect...", RNS.LOG_WARNING) @@ -803,12 +803,12 @@ class I2PInterfacePeer(Interface): def teardown(self): if self.initiator and not self.detached: - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() else: - RNS.log("The interface "+str(self)+" is being torn down.", RNS.LOG_VERBOSE) + RNS.log(f"The interface {self} is being torn down.", RNS.LOG_VERBOSE) self.online = False self.OUT = False @@ -824,7 +824,7 @@ class I2PInterfacePeer(Interface): def __str__(self): - return "I2PInterfacePeer["+str(self.name)+"]" + return f"I2PInterfacePeer[{self.name}]" class I2PInterface(Interface): @@ -895,11 +895,11 @@ class I2PInterface(Interface): while True: try: if not self.i2p.server_tunnel(self): - RNS.log(str(self)+" I2P control process experienced an error, requesting new tunnel...", RNS.LOG_ERROR) + RNS.log(f"{self} I2P control process experienced an error, requesting new tunnel...", RNS.LOG_ERROR) self.online = False except Exception as e: - RNS.log("Error while while configuring "+str(self)+": "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while while configuring {self}: {e}", RNS.LOG_ERROR) RNS.log("Check that I2P is installed and running, and that SAM is enabled. Retrying tunnel setup later.", RNS.LOG_ERROR) time.sleep(15) @@ -911,7 +911,7 @@ class I2PInterface(Interface): if peers != None: for peer_addr in peers: - interface_name = self.name+" to "+peer_addr + interface_name = f"{self.name} to {peer_addr}" peer_interface = I2PInterfacePeer(self, self.owner, interface_name, peer_addr) peer_interface.OUT = True peer_interface.IN = True @@ -921,7 +921,7 @@ class I2PInterface(Interface): def incoming_connection(self, handler): RNS.log("Accepting incoming I2P connection", RNS.LOG_VERBOSE) - interface_name = "Connected peer on "+self.name + interface_name = f"Connected peer on {self.name}" spawned_interface = I2PInterfacePeer(self, self.owner, interface_name, connected_socket=handler.request) spawned_interface.OUT = True spawned_interface.IN = True @@ -954,7 +954,7 @@ class I2PInterface(Interface): spawned_interface.announce_rate_penalty = self.announce_rate_penalty spawned_interface.mode = self.mode spawned_interface.HW_MTU = self.HW_MTU - RNS.log("Spawned new I2PInterface Peer: "+str(spawned_interface), RNS.LOG_VERBOSE) + RNS.log(f"Spawned new I2PInterface Peer: {spawned_interface}", RNS.LOG_VERBOSE) RNS.Transport.interfaces.append(spawned_interface) self.clients += 1 spawned_interface.read_loop() @@ -969,11 +969,11 @@ class I2PInterface(Interface): if from_spawned: self.oa_freq_deque.append(time.time()) def detach(self): - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.i2p.stop() def __str__(self): - return "I2PInterface["+self.name+"]" + return f"I2PInterface[{self.name}]" class I2PInterfaceHandler(socketserver.BaseRequestHandler): def __init__(self, callback, *args, **keys): diff --git a/RNS/Interfaces/Interface.py b/RNS/Interfaces/Interface.py index eb987a2..e72e9c8 100755 --- a/RNS/Interfaces/Interface.py +++ b/RNS/Interfaces/Interface.py @@ -140,7 +140,7 @@ class Interface: selected_announce_packet = announce_packet if selected_announce_packet != None: - RNS.log("Releasing held announce packet "+str(selected_announce_packet)+" from "+str(self), RNS.LOG_EXTREME) + RNS.log(f"Releasing held announce packet {selected_announce_packet} from {self}", RNS.LOG_EXTREME) self.ic_held_release = time.time() + self.ic_held_release_interval self.held_announces.pop(selected_announce_packet.destination_hash) def release(): @@ -148,8 +148,8 @@ class Interface: threading.Thread(target=release, daemon=True).start() except Exception as e: - RNS.log("An error occurred while processing held announces for "+str(self), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while processing held announces for {self}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) def received_announce(self): self.ia_freq_deque.append(time.time()) @@ -234,7 +234,7 @@ class Interface: except Exception as e: self.announce_queue = [] - RNS.log("Error while processing announce queue on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while processing announce queue on {self}. The contained exception was: {e}", RNS.LOG_ERROR) RNS.log("The announce queue for this interface has been cleared.", RNS.LOG_ERROR) def detach(self): diff --git a/RNS/Interfaces/KISSInterface.py b/RNS/Interfaces/KISSInterface.py index 4dad095..13c9197 100644 --- a/RNS/Interfaces/KISSInterface.py +++ b/RNS/Interfaces/KISSInterface.py @@ -113,17 +113,17 @@ class KISSInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port "+self.port, RNS.LOG_ERROR) + RNS.log(f"Could not open serial port {self.port}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...", RNS.LOG_VERBOSE) + RNS.log(f"Opening serial port {self.port}...", RNS.LOG_VERBOSE) self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -146,7 +146,7 @@ class KISSInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Configuring KISS interface parameters...") self.setPreamble(self.preamble) self.setTxTail(self.txtail) @@ -168,7 +168,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXDELAY])+bytes([preamble])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface preamble to "+str(preamble_ms)+" (command value "+str(preamble)+")") + raise OSError(f"Could not configure KISS interface preamble to {preamble_ms} (command value {preamble})") def setTxTail(self, txtail): txtail_ms = txtail @@ -181,7 +181,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXTAIL])+bytes([txtail])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface TX tail to "+str(txtail_ms)+" (command value "+str(txtail)+")") + raise OSError(f"Could not configure KISS interface TX tail to {txtail_ms} (command value {txtail})") def setPersistence(self, persistence): if persistence < 0: @@ -192,7 +192,7 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface persistence to "+str(persistence)) + raise OSError(f"Could not configure KISS interface persistence to {persistence}") def setSlotTime(self, slottime): slottime_ms = slottime @@ -205,16 +205,16 @@ class KISSInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SLOTTIME])+bytes([slottime])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("Could not configure KISS interface slot time to "+str(slottime_ms)+" (command value "+str(slottime)+")") + raise OSError(f"Could not configure KISS interface slot time to {slottime_ms} (command value {slottime})") def setFlowControl(self, flow_control): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): if (flow_control): - raise IOError("Could not enable KISS interface flow control") + raise OSError("Could not enable KISS interface flow control") else: - raise IOError("Could not enable KISS interface flow control") + raise OSError("Could not enable KISS interface flow control") def processIncoming(self, data): @@ -244,7 +244,7 @@ class KISSInterface(Interface): self.first_tx = time.time() if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") else: self.queue(data) @@ -311,20 +311,20 @@ class KISSInterface(Interface): if self.flow_control: if not self.interface_ready: if time.time() > self.flow_control_locked + self.flow_control_timeout: - RNS.log("Interface "+str(self)+" is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) + RNS.log(f"Interface {self} is unlocking flow control due to time-out. This should not happen. Your hardware might have missed a flow-control READY command, or maybe it does not support flow-control.", RNS.LOG_WARNING) self.process_queue() if self.beacon_i != None and self.beacon_d != None: if self.first_tx != None: if time.time() > self.first_tx + self.beacon_i: - RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.beacon_d.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data: {self.beacon_d.decode('utf-8')}", RNS.LOG_DEBUG) self.first_tx = None self.processOutgoing(self.beacon_d) except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -339,17 +339,17 @@ class KISSInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "KISSInterface["+self.name+"]" \ No newline at end of file + return f"KISSInterface[{self.name}]" \ No newline at end of file diff --git a/RNS/Interfaces/LocalInterface.py b/RNS/Interfaces/LocalInterface.py index 23fd068..1fedf00 100644 --- a/RNS/Interfaces/LocalInterface.py +++ b/RNS/Interfaces/LocalInterface.py @@ -133,10 +133,10 @@ class LocalClientInterface(Interface): self.connect() except Exception as e: - RNS.log("Connection attempt for "+str(self)+" failed: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"Connection attempt for {self} failed: {e}", RNS.LOG_DEBUG) if not self.never_connected: - RNS.log("Reconnected socket for "+str(self)+".", RNS.LOG_INFO) + RNS.log(f"Reconnected socket for {self}.", RNS.LOG_INFO) self.reconnecting = False thread = threading.Thread(target=self.read_loop) @@ -149,7 +149,7 @@ class LocalClientInterface(Interface): else: RNS.log("Attempt to reconnect on a non-initiator shared local interface. This should not happen.", RNS.LOG_ERROR) - raise IOError("Attempt to reconnect on a non-initiator local interface") + raise OSError("Attempt to reconnect on a non-initiator local interface") def processIncoming(self, data): @@ -188,8 +188,8 @@ class LocalClientInterface(Interface): self.parent_interface.txb += len(data) except Exception as e: - RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Exception occurred while transmitting via {self}, tearing down interface", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.teardown() @@ -226,7 +226,7 @@ class LocalClientInterface(Interface): else: self.online = False if self.is_connected_to_shared_instance and not self.detached: - RNS.log("Socket for "+str(self)+" was closed, attempting to reconnect...", RNS.LOG_WARNING) + RNS.log(f"Socket for {self} was closed, attempting to reconnect...", RNS.LOG_WARNING) RNS.Transport.shared_connection_disappeared() self.reconnect() else: @@ -237,26 +237,26 @@ class LocalClientInterface(Interface): except Exception as e: self.online = False - RNS.log("An interface error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("Tearing down "+str(self), RNS.LOG_ERROR) + RNS.log(f"An interface error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"Tearing down {self}", RNS.LOG_ERROR) self.teardown() def detach(self): if self.socket != None: if hasattr(self.socket, "close"): if callable(self.socket.close): - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.detached = True try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: self.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") self.socket = None @@ -276,7 +276,7 @@ class LocalClientInterface(Interface): RNS.Transport.owner._should_persist_data() if nowarning == False: - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -288,7 +288,7 @@ class LocalClientInterface(Interface): def __str__(self): - return "LocalInterface["+str(self.target_port)+"]" + return f"LocalInterface[{self.target_port}]" class LocalServerInterface(Interface): @@ -360,7 +360,7 @@ class LocalServerInterface(Interface): if from_spawned: self.oa_freq_deque.append(time.time()) def __str__(self): - return "Shared Instance["+str(self.bind_port)+"]" + return f"Shared Instance[{self.bind_port}]" class LocalInterfaceHandler(socketserver.BaseRequestHandler): def __init__(self, callback, *args, **keys): diff --git a/RNS/Interfaces/PipeInterface.py b/RNS/Interfaces/PipeInterface.py index ffe5c9e..87c67f2 100644 --- a/RNS/Interfaces/PipeInterface.py +++ b/RNS/Interfaces/PipeInterface.py @@ -72,17 +72,17 @@ class PipeInterface(Interface): self.open_pipe() except Exception as e: - RNS.log("Could connect pipe for interface "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could connect pipe for interface {self}", RNS.LOG_ERROR) raise e if self.pipe_is_open: self.configure_pipe() else: - raise IOError("Could not connect pipe") + raise OSError("Could not connect pipe") def open_pipe(self): - RNS.log("Connecting subprocess pipe for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Connecting subprocess pipe for {self}...", RNS.LOG_VERBOSE) try: self.process = subprocess.Popen(shlex.split(self.command), stdin=subprocess.PIPE, stdout=subprocess.PIPE) @@ -98,7 +98,7 @@ class PipeInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Subprocess pipe for "+str(self)+" is now connected", RNS.LOG_VERBOSE) + RNS.log(f"Subprocess pipe for {self} is now connected", RNS.LOG_VERBOSE) def processIncoming(self, data): @@ -113,7 +113,7 @@ class PipeInterface(Interface): self.process.stdin.flush() self.txb += len(data) if written != len(data): - raise IOError("Pipe interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Pipe interface only wrote {written} bytes of {len(data)}") def readLoop(self): @@ -150,7 +150,7 @@ class PipeInterface(Interface): escape = False data_buffer = data_buffer+bytes([byte]) - RNS.log("Subprocess terminated on "+str(self)) + RNS.log(f"Subprocess terminated on {self}") self.process.kill() except Exception as e: @@ -160,8 +160,8 @@ class PipeInterface(Interface): except Exception as e: pass - RNS.log("A pipe error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A pipe error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -175,14 +175,14 @@ class PipeInterface(Interface): while not self.online: try: time.sleep(self.respawn_delay) - RNS.log("Attempting to respawn subprocess for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to respawn subprocess for {self}...", RNS.LOG_VERBOSE) self.open_pipe() if self.pipe_is_open: self.configure_pipe() except Exception as e: - RNS.log("Error while spawning subprocess, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while spawning subprocess, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected pipe for "+str(self)) + RNS.log(f"Reconnected pipe for {self}") def __str__(self): - return "PipeInterface["+self.name+"]" + return f"PipeInterface[{self.name}]" diff --git a/RNS/Interfaces/RNodeInterface.py b/RNS/Interfaces/RNodeInterface.py index 1755fe6..9d955d5 100644 --- a/RNS/Interfaces/RNodeInterface.py +++ b/RNS/Interfaces/RNodeInterface.py @@ -211,31 +211,31 @@ class RNodeInterface(Interface): self.validcfg = True if (self.frequency < RNodeInterface.FREQ_MIN or self.frequency > RNodeInterface.FREQ_MAX): - RNS.log("Invalid frequency configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid frequency configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.txpower < 0 or self.txpower > 22): - RNS.log("Invalid TX power configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid TX power configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.bandwidth < 7800 or self.bandwidth > 1625000): - RNS.log("Invalid bandwidth configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid bandwidth configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.sf < 5 or self.sf > 12): - RNS.log("Invalid spreading factor configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid spreading factor configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.cr < 5 or self.cr > 8): - RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid coding rate configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)): - RNS.log("Invalid short-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid short-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)): - RNS.log("Invalid long-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid long-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if id_interval != None and id_callsign != None: @@ -244,14 +244,14 @@ class RNodeInterface(Interface): self.id_callsign = id_callsign.encode("utf-8") self.id_interval = id_interval else: - RNS.log("The encoded ID callsign for "+str(self)+" exceeds the max length of "+str(RNodeInterface.CALLSIGN_MAX_LEN)+" bytes.", RNS.LOG_ERROR) + RNS.log(f"The encoded ID callsign for {self} exceeds the max length of {RNodeInterface.CALLSIGN_MAX_LEN} bytes.", RNS.LOG_ERROR) self.validcfg = False else: self.id_interval = None self.id_callsign = None if (not self.validcfg): - raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline") + raise ValueError(f"The configuration for {self} contains errors, interface is offline") try: self.open_port() @@ -259,11 +259,11 @@ class RNodeInterface(Interface): if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR) if not self.detached and not self.reconnecting: thread = threading.Thread(target=self.reconnect_port) @@ -273,7 +273,7 @@ class RNodeInterface(Interface): def open_port(self): if not self.use_ble: - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -327,22 +327,22 @@ class RNodeInterface(Interface): RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR) if not self.detected: - RNS.log("Could not detect device for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR) self.serial.close() else: if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52: self.display = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Configuring RNode interface...", RNS.LOG_VERBOSE) self.initRadio() if (self.validateRadioState()): self.interface_ready = True - RNS.log(str(self)+" is configured and powered up") + RNS.log(f"{self} is configured and powered up") sleep(0.3) self.online = True else: - RNS.log("After configuring "+str(self)+", the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) + RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR) self.serial.close() @@ -365,27 +365,27 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while detecting hardware for "+str(self)) + raise OSError(f"An IO error occurred while detecting hardware for {self}") def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending host left command to device") + raise OSError("An IO error occurred while sending host left command to device") def enable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while enabling external framebuffer on device") + raise OSError("An IO error occurred while enabling external framebuffer on device") def disable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while disabling external framebuffer on device") + raise OSError("An IO error occurred while disabling external framebuffer on device") FB_PIXEL_WIDTH = 64 FB_BITS_PER_PIXEL = 1 @@ -409,13 +409,13 @@ class RNodeInterface(Interface): written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while writing framebuffer data device") + raise OSError("An IO error occurred while writing framebuffer data device") def hard_reset(self): kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while restarting device") + raise OSError("An IO error occurred while restarting device") sleep(2.25); def setFrequency(self): @@ -428,7 +428,7 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring frequency for "+str(self)) + raise OSError(f"An IO error occurred while configuring frequency for {self}") def setBandwidth(self): c1 = self.bandwidth >> 24 @@ -440,28 +440,28 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring bandwidth for "+str(self)) + raise OSError(f"An IO error occurred while configuring bandwidth for {self}") def setTXPower(self): txp = bytes([self.txpower]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring TX power for "+str(self)) + raise OSError(f"An IO error occurred while configuring TX power for {self}") def setSpreadingFactor(self): sf = bytes([self.sf]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring spreading factor for "+str(self)) + raise OSError(f"An IO error occurred while configuring spreading factor for {self}") def setCodingRate(self): cr = bytes([self.cr]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring coding rate for "+str(self)) + raise OSError(f"An IO error occurred while configuring coding rate for {self}") def setSTALock(self): if self.st_alock != None: @@ -473,7 +473,7 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring short-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring short-term airtime limit for {self}") def setLTALock(self): if self.lt_alock != None: @@ -485,14 +485,14 @@ class RNodeInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring long-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring long-term airtime limit for {self}") def setRadioState(self, state): self.state = state kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state for "+str(self)) + raise OSError(f"An IO error occurred while configuring radio state for {self}") def validate_firmware(self): if (self.maj_version > RNodeInterface.REQUIRED_FW_VER_MAJ): @@ -505,14 +505,14 @@ class RNodeInterface(Interface): if self.firmware_ok: return - RNS.log("The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version), RNS.LOG_ERROR) - RNS.log("This version of Reticulum requires at least version "+str(RNodeInterface.REQUIRED_FW_VER_MAJ)+"."+str(RNodeInterface.REQUIRED_FW_VER_MIN), RNS.LOG_ERROR) + RNS.log(f"The firmware version of the connected RNode is {self.maj_version}.{self.min_version}", RNS.LOG_ERROR) + RNS.log(f"This version of Reticulum requires at least version {RNodeInterface.REQUIRED_FW_VER_MAJ}.{RNodeInterface.REQUIRED_FW_VER_MIN}", RNS.LOG_ERROR) RNS.log("Please update your RNode firmware with rnodeconf from https://github.com/markqvist/rnodeconfigutil/") RNS.panic() def validateRadioState(self): - RNS.log("Waiting for radio configuration validation for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Waiting for radio configuration validation for {self}...", RNS.LOG_VERBOSE) sleep(0.25); self.validcfg = True @@ -542,7 +542,7 @@ class RNodeInterface(Interface): try: self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 self.bitrate_kbps = round(self.bitrate/1000.0, 2) - RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_VERBOSE) + RNS.log(f"{self} On-air bitrate is now {self.bitrate_kbps} kbps", RNS.LOG_VERBOSE) except: self.bitrate = 0 @@ -573,7 +573,7 @@ class RNodeInterface(Interface): self.txb += datalen if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") else: self.queue(data) @@ -639,7 +639,7 @@ class RNodeInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self)+" Radio reporting frequency is "+str(self.r_frequency/1000000.0)+" MHz", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting frequency is {self.r_frequency / 1000000.0} MHz", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_BANDWIDTH): @@ -655,26 +655,26 @@ class RNodeInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self)+" Radio reporting bandwidth is "+str(self.r_bandwidth/1000.0)+" KHz", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting bandwidth is {self.r_bandwidth / 1000.0} KHz", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_TXPOWER): self.r_txpower = byte - RNS.log(str(self)+" Radio reporting TX power is "+str(self.r_txpower)+" dBm", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting TX power is {self.r_txpower} dBm", RNS.LOG_DEBUG) elif (command == KISS.CMD_SF): self.r_sf = byte - RNS.log(str(self)+" Radio reporting spreading factor is "+str(self.r_sf), RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting spreading factor is {self.r_sf}", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_CR): self.r_cr = byte - RNS.log(str(self)+" Radio reporting coding rate is "+str(self.r_cr), RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting coding rate is {self.r_cr}", RNS.LOG_DEBUG) self.updateBitrate() elif (command == KISS.CMD_RADIO_STATE): self.r_state = byte if self.r_state: pass else: - RNS.log(str(self)+" Radio reporting state is offline", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting state is offline", RNS.LOG_DEBUG) elif (command == KISS.CMD_RADIO_LOCK): self.r_lock = byte @@ -752,7 +752,7 @@ class RNodeInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.r_st_alock = at/100.0 - RNS.log(str(self)+" Radio reporting short-term airtime limit is "+str(self.r_st_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting short-term airtime limit is {self.r_st_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_LT_ALOCK): if (byte == KISS.FESC): escape = True @@ -767,7 +767,7 @@ class RNodeInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.r_lt_alock = at/100.0 - RNS.log(str(self)+" Radio reporting long-term airtime limit is "+str(self.r_lt_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting long-term airtime limit is {self.r_lt_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_CHTM): if (byte == KISS.FESC): escape = True @@ -813,9 +813,9 @@ class RNodeInterface(Interface): self.r_preamble_symbols = prs self.r_premable_time_ms = prt self.r_csma_slot_time_ms = cst - RNS.log(str(self)+" Radio reporting symbol time is "+str(round(self.r_symbol_time_ms,2))+"ms (at "+str(self.r_symbol_rate)+" baud)", RNS.LOG_DEBUG) - RNS.log(str(self)+" Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", RNS.LOG_DEBUG) - RNS.log(str(self)+" Radio reporting CSMA slot time is "+str(self.r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting symbol time is {round(self.r_symbol_time_ms, 2)}ms (at {self.r_symbol_rate} baud)", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting preamble is {self.r_preamble_symbols} symbols ({self.r_premable_time_ms}ms)", RNS.LOG_DEBUG) + RNS.log(f"{self} Radio reporting CSMA slot time is {self.r_csma_slot_time_ms}ms", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_BAT): if (byte == KISS.FESC): escape = True @@ -843,26 +843,26 @@ class RNodeInterface(Interface): self.mcu = byte elif (command == KISS.CMD_ERROR): if (byte == KISS.ERROR_INITRADIO): - RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Radio initialisation failure") + RNS.log(f"{self} hardware initialisation error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Radio initialisation failure") elif (byte == KISS.ERROR_TXFAILED): - RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Hardware transmit failure") + RNS.log(f"{self} hardware TX error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Hardware transmit failure") elif (byte == KISS.ERROR_MEMORY_LOW): - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+"): Memory exhausted", RNS.LOG_ERROR) + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)}): Memory exhausted", RNS.LOG_ERROR) self.hw_errors.append({"error": KISS.ERROR_MEMORY_LOW, "description": "Memory exhausted on connected device"}) elif (byte == KISS.ERROR_MODEM_TIMEOUT): - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+"): Modem communication timed out", RNS.LOG_ERROR) + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)}): Modem communication timed out", RNS.LOG_ERROR) self.hw_errors.append({"error": KISS.ERROR_MODEM_TIMEOUT, "description": "Modem communication timed out on connected device"}) else: - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Unknown hardware failure") + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Unknown hardware failure") elif (command == KISS.CMD_RESET): if (byte == 0xF8): if self.platform == KISS.PLATFORM_ESP32: if self.online: RNS.log("Detected reset while device was online, reinitialising device...", RNS.LOG_ERROR) - raise IOError("ESP32 reset") + raise OSError("ESP32 reset") elif (command == KISS.CMD_READY): self.process_queue() elif (command == KISS.CMD_DETECT): @@ -874,7 +874,7 @@ class RNodeInterface(Interface): else: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: - RNS.log(str(self)+" serial read timeout in command "+str(command), RNS.LOG_WARNING) + RNS.log(f"{self} serial read timeout in command {command}", RNS.LOG_WARNING) data_buffer = b"" in_frame = False command = KISS.CMD_UNKNOWN @@ -883,15 +883,15 @@ class RNodeInterface(Interface): if self.id_interval != None and self.id_callsign != None: if self.first_tx != None: if time.time() > self.first_tx + self.id_interval: - RNS.log("Interface "+str(self)+" is transmitting beacon data: "+str(self.id_callsign.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data: {self.id_callsign.decode('utf-8')}", RNS.LOG_DEBUG) self.processOutgoing(self.id_callsign) sleep(0.08) except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -912,16 +912,16 @@ class RNodeInterface(Interface): while not self.online and not self.detached: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) self.reconnecting = False if self.online: - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def detach(self): self.detached = True @@ -965,7 +965,7 @@ class RNodeInterface(Interface): return data def __str__(self): - return "RNodeInterface["+str(self.name)+"]" + return f"RNodeInterface[{self.name}]" class BLEConnection(): UART_SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" diff --git a/RNS/Interfaces/RNodeMultiInterface.py b/RNS/Interfaces/RNodeMultiInterface.py index df3fed2..021bbb1 100644 --- a/RNS/Interfaces/RNodeMultiInterface.py +++ b/RNS/Interfaces/RNodeMultiInterface.py @@ -241,14 +241,14 @@ class RNodeMultiInterface(Interface): self.id_callsign = id_callsign.encode("utf-8") self.id_interval = id_interval else: - RNS.log("The encoded ID callsign for "+str(self)+" exceeds the max length of "+str(RNodeMultiInterface.CALLSIGN_MAX_LEN)+" bytes.", RNS.LOG_ERROR) + RNS.log(f"The encoded ID callsign for {self} exceeds the max length of {RNodeMultiInterface.CALLSIGN_MAX_LEN} bytes.", RNS.LOG_ERROR) self.validcfg = False else: self.id_interval = None self.id_callsign = None if (not self.validcfg): - raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline") + raise ValueError(f"The configuration for {self} contains errors, interface is offline") def start(self): try: @@ -257,11 +257,11 @@ class RNodeMultiInterface(Interface): if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR) if not self.detached and not self.reconnecting: thread = threading.Thread(target=self.reconnect_port) @@ -269,7 +269,7 @@ class RNodeMultiInterface(Interface): thread.start() def open_port(self): - RNS.log("Opening serial port "+self.port+"...") + RNS.log(f"Opening serial port {self.port}...") self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -296,13 +296,13 @@ class RNodeMultiInterface(Interface): sleep(0.2) if not self.detected: - RNS.log("Could not detect device for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR) self.serial.close() else: if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52: self.display = True - RNS.log("Serial port "+self.port+" is now open") + RNS.log(f"Serial port {self.port} is now open") RNS.log("Creating subinterfaces...", RNS.LOG_VERBOSE) for subint in self.subint_config: subint_vport = int(subint[1]) @@ -333,38 +333,38 @@ class RNodeMultiInterface(Interface): interface.HW_MTU = self.HW_MTU interface.detected = True RNS.Transport.interfaces.append(interface) - RNS.log("Spawned new RNode subinterface: "+str(interface), RNS.LOG_VERBOSE) + RNS.log(f"Spawned new RNode subinterface: {interface}", RNS.LOG_VERBOSE) self.clients += 1 else: - raise ValueError("Virtual port \""+subint[1]+"\" for subinterface "+subint[0]+" does not exist on "+self.name) + raise ValueError(f"Virtual port \"{subint[1]}\" for subinterface {subint[0]} does not exist on {self.name}") self.online = True def detect(self): kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND, KISS.CMD_INTERFACES, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while detecting hardware for "+str(self)) + raise OSError(f"An IO error occurred while detecting hardware for {self}") def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending host left command to device") + raise OSError("An IO error occurred while sending host left command to device") def enable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while enabling external framebuffer on device") + raise OSError("An IO error occurred while enabling external framebuffer on device") def disable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while disabling external framebuffer on device") + raise OSError("An IO error occurred while disabling external framebuffer on device") FB_PIXEL_WIDTH = 64 FB_BITS_PER_PIXEL = 1 @@ -388,13 +388,13 @@ class RNodeMultiInterface(Interface): written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while writing framebuffer data device") + raise OSError("An IO error occurred while writing framebuffer data device") def hard_reset(self): kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while restarting device") + raise OSError("An IO error occurred while restarting device") sleep(2.25); def setFrequency(self, frequency, interface): @@ -407,7 +407,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring frequency for "+str(self)) + raise OSError(f"An IO error occurred while configuring frequency for {self}") self.selected_index = interface.index def setBandwidth(self, bandwidth, interface): @@ -420,7 +420,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring bandwidth for "+str(self)) + raise OSError(f"An IO error occurred while configuring bandwidth for {self}") self.selected_index = interface.index def setTXPower(self, txpower, interface): @@ -428,7 +428,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring TX power for "+str(self)) + raise OSError(f"An IO error occurred while configuring TX power for {self}") self.selected_index = interface.index def setSpreadingFactor(self, sf, interface): @@ -436,7 +436,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring spreading factor for "+str(self)) + raise OSError(f"An IO error occurred while configuring spreading factor for {self}") self.selected_index = interface.index def setCodingRate(self, cr, interface): @@ -444,7 +444,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring coding rate for "+str(self)) + raise OSError(f"An IO error occurred while configuring coding rate for {self}") self.selected_index = interface.index def setSTALock(self, st_alock, interface): @@ -457,7 +457,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring short-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring short-term airtime limit for {self}") self.selected_index = interface.index def setLTALock(self, lt_alock, interface): @@ -470,7 +470,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring long-term airtime limit for "+str(self)) + raise OSError(f"An IO error occurred while configuring long-term airtime limit for {self}") self.selected_index = interface.index def setRadioState(self, state, interface): @@ -478,7 +478,7 @@ class RNodeMultiInterface(Interface): kiss_command = bytes([KISS.FEND])+bytes([interface.sel_cmd])+bytes([KISS.FEND])+bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state for "+str(self)) + raise OSError(f"An IO error occurred while configuring radio state for {self}") self.selected_index = interface.index def validate_firmware(self): @@ -489,8 +489,8 @@ class RNodeMultiInterface(Interface): if self.firmware_ok: return - RNS.log("The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version), RNS.LOG_ERROR) - RNS.log("This version of Reticulum requires at least version "+str(RNodeMultiInterface.REQUIRED_FW_VER_MAJ)+"."+str(RNodeMultiInterface.REQUIRED_FW_VER_MIN), RNS.LOG_ERROR) + RNS.log(f"The firmware version of the connected RNode is {self.maj_version}.{self.min_version}", RNS.LOG_ERROR) + RNS.log(f"This version of Reticulum requires at least version {RNodeMultiInterface.REQUIRED_FW_VER_MAJ}.{RNodeMultiInterface.REQUIRED_FW_VER_MIN}", RNS.LOG_ERROR) RNS.log("Please update your RNode firmware with rnodeconf from https://github.com/markqvist/Reticulum/RNS/Utilities/rnodeconf.py") RNS.panic() @@ -506,7 +506,7 @@ class RNodeMultiInterface(Interface): self.txb += len(data) if written != len(frame): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") def received_announce(self, from_spawned=False): if from_spawned: self.ia_freq_deque.append(time.time()) @@ -589,7 +589,7 @@ class RNodeMultiInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.subinterfaces[self.selected_index].r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting frequency is "+str(self.subinterfaces[self.selected_index].r_frequency/1000000.0)+" MHz", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting frequency is {self.subinterfaces[self.selected_index].r_frequency / 1000000.0} MHz", RNS.LOG_DEBUG) self.subinterfaces[self.selected_index].updateBitrate() elif (command == KISS.CMD_BANDWIDTH): @@ -605,20 +605,20 @@ class RNodeMultiInterface(Interface): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.subinterfaces[self.selected_index].r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting bandwidth is "+str(self.subinterfaces[self.selected_index].r_bandwidth/1000.0)+" KHz", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting bandwidth is {self.subinterfaces[self.selected_index].r_bandwidth / 1000.0} KHz", RNS.LOG_DEBUG) self.subinterfaces[self.selected_index].updateBitrate() elif (command == KISS.CMD_TXPOWER): txp = byte - 256 if byte > 127 else byte self.subinterfaces[self.selected_index].r_txpower = txp - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting TX power is "+str(self.subinterfaces[self.selected_index].r_txpower)+" dBm", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting TX power is {self.subinterfaces[self.selected_index].r_txpower} dBm", RNS.LOG_DEBUG) elif (command == KISS.CMD_SF): self.subinterfaces[self.selected_index].r_sf = byte - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting spreading factor is "+str(self.subinterfaces[self.selected_index].r_sf), RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting spreading factor is {self.subinterfaces[self.selected_index].r_sf}", RNS.LOG_DEBUG) self.subinterfaces[self.selected_index].updateBitrate() elif (command == KISS.CMD_CR): self.subinterfaces[self.selected_index].r_cr = byte - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting coding rate is "+str(self.subinterfaces[self.selected_index].r_cr), RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting coding rate is {self.subinterfaces[self.selected_index].r_cr}", RNS.LOG_DEBUG) self.subinterfaces[self.selected_index].updateBitrate() elif (command == KISS.CMD_RADIO_STATE): self.subinterfaces[self.selected_index].r_state = byte @@ -626,7 +626,7 @@ class RNodeMultiInterface(Interface): pass #RNS.log(str(self)+" Radio reporting state is online", RNS.LOG_DEBUG) else: - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting state is offline", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting state is offline", RNS.LOG_DEBUG) elif (command == KISS.CMD_RADIO_LOCK): self.subinterfaces[self.selected_index].r_lock = byte @@ -705,7 +705,7 @@ class RNodeMultiInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.subinterfaces[self.selected_index].r_st_alock = at/100.0 - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting short-term airtime limit is "+str(self.subinterfaces[self.selected_index].r_st_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting short-term airtime limit is {self.subinterfaces[self.selected_index].r_st_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_LT_ALOCK): if (byte == KISS.FESC): escape = True @@ -720,7 +720,7 @@ class RNodeMultiInterface(Interface): if (len(command_buffer) == 2): at = command_buffer[0] << 8 | command_buffer[1] self.subinterfaces[self.selected_index].r_lt_alock = at/100.0 - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting long-term airtime limit is "+str(self.subinterfaces[self.selected_index].r_lt_alock)+"%", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting long-term airtime limit is {self.subinterfaces[self.selected_index].r_lt_alock}%", RNS.LOG_DEBUG) elif (command == KISS.CMD_STAT_CHTM): if (byte == KISS.FESC): escape = True @@ -766,9 +766,9 @@ class RNodeMultiInterface(Interface): self.subinterfaces[self.selected_index].r_preamble_symbols = prs self.subinterfaces[self.selected_index].r_premable_time_ms = prt self.subinterfaces[self.selected_index].r_csma_slot_time_ms = cst - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting symbol time is "+str(round(self.subinterfaces[self.selected_index].r_symbol_time_ms,2))+"ms (at "+str(self.subinterfaces[self.selected_index].r_symbol_rate)+" baud)", RNS.LOG_DEBUG) - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting preamble is "+str(self.subinterfaces[self.selected_index].r_preamble_symbols)+" symbols ("+str(self.subinterfaces[self.selected_index].r_premable_time_ms)+"ms)", RNS.LOG_DEBUG) - RNS.log(str(self.subinterfaces[self.selected_index])+" Radio reporting CSMA slot time is "+str(self.subinterfaces[self.selected_index].r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting symbol time is {round(self.subinterfaces[self.selected_index].r_symbol_time_ms, 2)}ms (at {self.subinterfaces[self.selected_index].r_symbol_rate} baud)", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting preamble is {self.subinterfaces[self.selected_index].r_preamble_symbols} symbols ({self.subinterfaces[self.selected_index].r_premable_time_ms}ms)", RNS.LOG_DEBUG) + RNS.log(f"{self.subinterfaces[self.selected_index]} Radio reporting CSMA slot time is {self.subinterfaces[self.selected_index].r_csma_slot_time_ms}ms", RNS.LOG_DEBUG) elif (command == KISS.CMD_RANDOM): self.r_random = byte elif (command == KISS.CMD_PLATFORM): @@ -777,20 +777,20 @@ class RNodeMultiInterface(Interface): self.mcu = byte elif (command == KISS.CMD_ERROR): if (byte == KISS.ERROR_INITRADIO): - RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Radio initialisation failure") + RNS.log(f"{self} hardware initialisation error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Radio initialisation failure") elif (byte == KISS.ERROR_TXFAILED): - RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Hardware transmit failure") + RNS.log(f"{self} hardware TX error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Hardware transmit failure") else: - RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) - raise IOError("Unknown hardware failure") + RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR) + raise OSError("Unknown hardware failure") elif (command == KISS.CMD_RESET): if (byte == 0xF8): if self.platform == KISS.PLATFORM_ESP32: if self.online: RNS.log("Detected reset while device was online, reinitialising device...", RNS.LOG_ERROR) - raise IOError("ESP32 reset") + raise OSError("ESP32 reset") elif (command == KISS.CMD_READY): self.process_queue() elif (command == KISS.CMD_DETECT): @@ -808,7 +808,7 @@ class RNodeMultiInterface(Interface): else: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: - RNS.log(str(self)+" serial read timeout in command "+str(command), RNS.LOG_WARNING) + RNS.log(f"{self} serial read timeout in command {command}", RNS.LOG_WARNING) data_buffer = b"" in_frame = False command = KISS.CMD_UNKNOWN @@ -824,14 +824,14 @@ class RNodeMultiInterface(Interface): self.subinterfaces[interface.index].processOutgoing(self.id_callsign) if interface_available: - RNS.log("Interface "+str(self)+" is transmitting beacon data on all subinterfaces: "+str(self.id_callsign.decode("utf-8")), RNS.LOG_DEBUG) + RNS.log(f"Interface {self} is transmitting beacon data on all subinterfaces: {self.id_callsign.decode('utf-8')}", RNS.LOG_DEBUG) sleep(0.08) except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -854,16 +854,16 @@ class RNodeMultiInterface(Interface): while not self.online and not self.detached: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) self.reconnecting = False if self.online: - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def detach(self): self.detached = True @@ -890,7 +890,7 @@ class RNodeMultiInterface(Interface): interface.process_queue() def __str__(self): - return "RNodeMultiInterface["+str(self.name)+"]" + return f"RNodeMultiInterface[{self.name}]" class RNodeSubInterface(Interface): LOW_FREQ_MIN = 137000000 @@ -1019,42 +1019,42 @@ class RNodeSubInterface(Interface): self.validcfg = True if (self.interface_type == "SX126X" or self.interface_type == "SX127X"): if (self.frequency < RNodeSubInterface.LOW_FREQ_MIN or self.frequency > RNodeSubInterface.LOW_FREQ_MAX): - RNS.log("Invalid frequency configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid frequency configured for {self}", RNS.LOG_ERROR) self.validcfg = False elif (self.interface_type == "SX128X"): if (self.frequency < RNodeSubInterface.HIGH_FREQ_MIN or self.frequency > RNodeSubInterface.HIGH_FREQ_MAX): - RNS.log("Invalid frequency configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid frequency configured for {self}", RNS.LOG_ERROR) self.validcfg = False else: - RNS.log("Invalid interface type configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid interface type configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.txpower < -9 or self.txpower > 27): - RNS.log("Invalid TX power configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid TX power configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.bandwidth < 7800 or self.bandwidth > 1625000): - RNS.log("Invalid bandwidth configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid bandwidth configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.sf < 5 or self.sf > 12): - RNS.log("Invalid spreading factor configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid spreading factor configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.cr < 5 or self.cr > 8): - RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid coding rate configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)): - RNS.log("Invalid short-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid short-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)): - RNS.log("Invalid long-term airtime limit configured for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Invalid long-term airtime limit configured for {self}", RNS.LOG_ERROR) self.validcfg = False if (not self.validcfg): - raise ValueError("The configuration for "+str(self)+" contains errors, interface is offline") + raise ValueError(f"The configuration for {self} contains errors, interface is offline") self.configure_device() @@ -1068,15 +1068,15 @@ class RNodeSubInterface(Interface): self.r_lock = None sleep(2.0) - RNS.log("Configuring RNode subinterface "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Configuring RNode subinterface {self}...", RNS.LOG_VERBOSE) self.initRadio() if (self.validateRadioState()): self.interface_ready = True - RNS.log(str(self)+" is configured and powered up") + RNS.log(f"{self} is configured and powered up") sleep(0.3) self.online = True else: - RNS.log("After configuring "+str(self)+", the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) + RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR) @@ -1093,7 +1093,7 @@ class RNodeSubInterface(Interface): self.state = KISS.RADIO_STATE_ON def validateRadioState(self): - RNS.log("Waiting for radio configuration validation for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Waiting for radio configuration validation for {self}...", RNS.LOG_VERBOSE) sleep(0.25); self.validcfg = True @@ -1123,7 +1123,7 @@ class RNodeSubInterface(Interface): try: self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 self.bitrate_kbps = round(self.bitrate/1000.0, 2) - RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_VERBOSE) + RNS.log(f"{self} On-air bitrate is now {self.bitrate_kbps} kbps", RNS.LOG_VERBOSE) except: self.bitrate = 0 @@ -1162,4 +1162,4 @@ class RNodeSubInterface(Interface): self.interface_ready = True def __str__(self): - return self.parent_interface.name+"["+self.name+"]" + return f"{self.parent_interface.name}[{self.name}]" diff --git a/RNS/Interfaces/SerialInterface.py b/RNS/Interfaces/SerialInterface.py index 89f73c6..e69b347 100755 --- a/RNS/Interfaces/SerialInterface.py +++ b/RNS/Interfaces/SerialInterface.py @@ -86,17 +86,17 @@ class SerialInterface(Interface): try: self.open_port() except Exception as e: - RNS.log("Could not open serial port for interface "+str(self), RNS.LOG_ERROR) + RNS.log(f"Could not open serial port for interface {self}", RNS.LOG_ERROR) raise e if self.serial.is_open: self.configure_device() else: - raise IOError("Could not open serial port") + raise OSError("Could not open serial port") def open_port(self): - RNS.log("Opening serial port "+self.port+"...", RNS.LOG_VERBOSE) + RNS.log(f"Opening serial port {self.port}...", RNS.LOG_VERBOSE) self.serial = self.pyserial.Serial( port = self.port, baudrate = self.speed, @@ -118,7 +118,7 @@ class SerialInterface(Interface): thread.daemon = True thread.start() self.online = True - RNS.log("Serial port "+self.port+" is now open", RNS.LOG_VERBOSE) + RNS.log(f"Serial port {self.port} is now open", RNS.LOG_VERBOSE) def processIncoming(self, data): @@ -132,7 +132,7 @@ class SerialInterface(Interface): written = self.serial.write(data) self.txb += len(data) if written != len(data): - raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data))) + raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") def readLoop(self): @@ -175,8 +175,8 @@ class SerialInterface(Interface): except Exception as e: self.online = False - RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) + RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() @@ -191,17 +191,17 @@ class SerialInterface(Interface): while not self.online: try: time.sleep(5) - RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE) + RNS.log(f"Attempting to reconnect serial port {self.port} for {self}...", RNS.LOG_VERBOSE) self.open_port() if self.serial.is_open: self.configure_device() except Exception as e: - RNS.log("Error while reconnecting port, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while reconnecting port, the contained exception was: {e}", RNS.LOG_ERROR) - RNS.log("Reconnected serial port for "+str(self)) + RNS.log(f"Reconnected serial port for {self}") def should_ingress_limit(self): return False def __str__(self): - return "SerialInterface["+self.name+"]" + return f"SerialInterface[{self.name}]" diff --git a/RNS/Interfaces/TCPInterface.py b/RNS/Interfaces/TCPInterface.py index 54eadb0..fbdb3f3 100644 --- a/RNS/Interfaces/TCPInterface.py +++ b/RNS/Interfaces/TCPInterface.py @@ -180,25 +180,25 @@ class TCPClientInterface(Interface): if self.socket != None: if hasattr(self.socket, "close"): if callable(self.socket.close): - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.detached = True try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: - RNS.log("Error while shutting down socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down socket for {self}: {e}") try: self.socket.close() except Exception as e: - RNS.log("Error while closing socket for "+str(self)+": "+str(e)) + RNS.log(f"Error while closing socket for {self}: {e}") self.socket = None def connect(self, initial=False): try: if initial: - RNS.log("Establishing TCP connection for "+str(self)+"...", RNS.LOG_DEBUG) + RNS.log(f"Establishing TCP connection for {self}...", RNS.LOG_DEBUG) self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.settimeout(TCPClientInterface.INITIAL_CONNECT_TIMEOUT) @@ -208,12 +208,12 @@ class TCPClientInterface(Interface): self.online = True if initial: - RNS.log("TCP connection for "+str(self)+" established", RNS.LOG_DEBUG) + RNS.log(f"TCP connection for {self} established", RNS.LOG_DEBUG) except Exception as e: if initial: - RNS.log("Initial connection for "+str(self)+" could not be established: "+str(e), RNS.LOG_ERROR) - RNS.log("Leaving unconnected and retrying connection in "+str(TCPClientInterface.RECONNECT_WAIT)+" seconds.", RNS.LOG_ERROR) + RNS.log(f"Initial connection for {self} could not be established: {e}", RNS.LOG_ERROR) + RNS.log(f"Leaving unconnected and retrying connection in {TCPClientInterface.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR) return False else: @@ -241,7 +241,7 @@ class TCPClientInterface(Interface): attempts += 1 if self.max_reconnect_tries != None and attempts > self.max_reconnect_tries: - RNS.log("Max reconnection attempts reached for "+str(self), RNS.LOG_ERROR) + RNS.log(f"Max reconnection attempts reached for {self}", RNS.LOG_ERROR) self.teardown() break @@ -249,10 +249,10 @@ class TCPClientInterface(Interface): self.connect() except Exception as e: - RNS.log("Connection attempt for "+str(self)+" failed: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"Connection attempt for {self} failed: {e}", RNS.LOG_DEBUG) if not self.never_connected: - RNS.log("Reconnected socket for "+str(self)+".", RNS.LOG_INFO) + RNS.log(f"Reconnected socket for {self}.", RNS.LOG_INFO) self.reconnecting = False thread = threading.Thread(target=self.read_loop) @@ -263,7 +263,7 @@ class TCPClientInterface(Interface): else: RNS.log("Attempt to reconnect on a non-initiator TCP interface. This should not happen.", RNS.LOG_ERROR) - raise IOError("Attempt to reconnect on a non-initiator TCP interface") + raise OSError("Attempt to reconnect on a non-initiator TCP interface") def processIncoming(self, data): self.rxb += len(data) @@ -292,8 +292,8 @@ class TCPClientInterface(Interface): self.parent_interface.txb += len(data) except Exception as e: - RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Exception occurred while transmitting via {self}, tearing down interface", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.teardown() @@ -361,10 +361,10 @@ class TCPClientInterface(Interface): else: self.online = False if self.initiator and not self.detached: - RNS.log("The socket for "+str(self)+" was closed, attempting to reconnect...", RNS.LOG_WARNING) + RNS.log(f"The socket for {self} was closed, attempting to reconnect...", RNS.LOG_WARNING) self.reconnect() else: - RNS.log("The socket for remote client "+str(self)+" was closed.", RNS.LOG_VERBOSE) + RNS.log(f"The socket for remote client {self} was closed.", RNS.LOG_VERBOSE) self.teardown() break @@ -372,7 +372,7 @@ class TCPClientInterface(Interface): except Exception as e: self.online = False - RNS.log("An interface error occurred for "+str(self)+", the contained exception was: "+str(e), RNS.LOG_WARNING) + RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING) if self.initiator: RNS.log("Attempting to reconnect...", RNS.LOG_WARNING) @@ -382,12 +382,12 @@ class TCPClientInterface(Interface): def teardown(self): if self.initiator and not self.detached: - RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) + RNS.log(f"The interface {self} experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR) if RNS.Reticulum.panic_on_interface_error: RNS.panic() else: - RNS.log("The interface "+str(self)+" is being torn down.", RNS.LOG_VERBOSE) + RNS.log(f"The interface {self} is being torn down.", RNS.LOG_VERBOSE) self.online = False self.OUT = False @@ -402,7 +402,7 @@ class TCPClientInterface(Interface): def __str__(self): - return "TCPInterface["+str(self.name)+"/"+str(self.target_ip)+":"+str(self.target_port)+"]" + return f"TCPInterface[{self.name}/{self.target_ip}:{self.target_port}]" class TCPServerInterface(Interface): @@ -466,7 +466,7 @@ class TCPServerInterface(Interface): def incoming_connection(self, handler): RNS.log("Accepting incoming TCP connection", RNS.LOG_VERBOSE) - interface_name = "Client on "+self.name + interface_name = f"Client on {self.name}" spawned_interface = TCPClientInterface(self.owner, interface_name, target_ip=None, target_port=None, connected_socket=handler.request, i2p_tunneled=self.i2p_tunneled) spawned_interface.OUT = self.OUT spawned_interface.IN = self.IN @@ -501,7 +501,7 @@ class TCPServerInterface(Interface): spawned_interface.mode = self.mode spawned_interface.HW_MTU = self.HW_MTU spawned_interface.online = True - RNS.log("Spawned new TCPClient Interface: "+str(spawned_interface), RNS.LOG_VERBOSE) + RNS.log(f"Spawned new TCPClient Interface: {spawned_interface}", RNS.LOG_VERBOSE) RNS.Transport.interfaces.append(spawned_interface) self.clients += 1 spawned_interface.read_loop() @@ -521,17 +521,17 @@ class TCPServerInterface(Interface): if hasattr(self.server, "shutdown"): if callable(self.server.shutdown): try: - RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) + RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.server.shutdown() self.detached = True self.server = None except Exception as e: - RNS.log("Error while shutting down server for "+str(self)+": "+str(e)) + RNS.log(f"Error while shutting down server for {self}: {e}") def __str__(self): - return "TCPServerInterface["+self.name+"/"+self.bind_ip+":"+str(self.bind_port)+"]" + return f"TCPServerInterface[{self.name}/{self.bind_ip}:{self.bind_port}]" class TCPInterfaceHandler(socketserver.BaseRequestHandler): diff --git a/RNS/Interfaces/UDPInterface.py b/RNS/Interfaces/UDPInterface.py index f230af9..d407a78 100644 --- a/RNS/Interfaces/UDPInterface.py +++ b/RNS/Interfaces/UDPInterface.py @@ -101,11 +101,11 @@ class UDPInterface(Interface): self.txb += len(data) except Exception as e: - RNS.log("Could not transmit on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR) def __str__(self): - return "UDPInterface["+self.name+"/"+self.bind_ip+":"+str(self.bind_port)+"]" + return f"UDPInterface[{self.name}/{self.bind_ip}:{self.bind_port}]" class UDPInterfaceHandler(socketserver.BaseRequestHandler): def __init__(self, callback, *args, **keys): diff --git a/RNS/Interfaces/__init__.py b/RNS/Interfaces/__init__.py index 84fff6a..33fc3d8 100755 --- a/RNS/Interfaces/__init__.py +++ b/RNS/Interfaces/__init__.py @@ -24,5 +24,5 @@ import os import glob import RNS.Interfaces.Android -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] diff --git a/RNS/Link.py b/RNS/Link.py index 01641b1..a74a444 100644 --- a/RNS/Link.py +++ b/RNS/Link.py @@ -115,8 +115,8 @@ class Link: link.destination = packet.destination link.establishment_timeout = Link.ESTABLISHMENT_TIMEOUT_PER_HOP * max(1, packet.hops) + Link.KEEPALIVE link.establishment_cost += len(packet.raw) - RNS.log("Validating link request "+RNS.prettyhexrep(link.link_id), RNS.LOG_VERBOSE) - RNS.log(f"Establishment timeout is {RNS.prettytime(link.establishment_timeout)} for incoming link request "+RNS.prettyhexrep(link.link_id), RNS.LOG_EXTREME) + RNS.log(f"Validating link request {RNS.prettyhexrep(link.link_id)}", RNS.LOG_VERBOSE) + RNS.log(f"Establishment timeout is {RNS.prettytime(link.establishment_timeout)} for incoming link request {RNS.prettyhexrep(link.link_id)}", RNS.LOG_EXTREME) link.handshake() link.attached_interface = packet.receiving_interface link.prove() @@ -125,12 +125,12 @@ class Link: link.last_inbound = time.time() link.start_watchdog() - RNS.log("Incoming link request "+str(link)+" accepted on "+str(link.attached_interface), RNS.LOG_DEBUG) + RNS.log(f"Incoming link request {link} accepted on {link.attached_interface}", RNS.LOG_DEBUG) return link except Exception as e: RNS.log("Validating link request failed", RNS.LOG_VERBOSE) - RNS.log("exc: "+str(e)) + RNS.log(f"exc: {e}") return None else: @@ -219,8 +219,8 @@ class Link: self.start_watchdog() self.packet.send() self.had_outbound() - RNS.log("Link request "+RNS.prettyhexrep(self.link_id)+" sent to "+str(self.destination), RNS.LOG_DEBUG) - RNS.log(f"Establishment timeout is {RNS.prettytime(self.establishment_timeout)} for link request "+RNS.prettyhexrep(self.link_id), RNS.LOG_EXTREME) + RNS.log(f"Link request {RNS.prettyhexrep(self.link_id)} sent to {self.destination}", RNS.LOG_DEBUG) + RNS.log(f"Establishment timeout is {RNS.prettytime(self.establishment_timeout)} for link request {RNS.prettyhexrep(self.link_id)}", RNS.LOG_EXTREME) def load_peer(self, peer_pub_bytes, peer_sig_pub_bytes): @@ -249,7 +249,7 @@ class Link: context=self.get_context(), ) else: - RNS.log("Handshake attempt on "+str(self)+" with invalid state "+str(self.status), RNS.LOG_ERROR) + RNS.log(f"Handshake attempt on {self} with invalid state {self.status}", RNS.LOG_ERROR) def prove(self): @@ -291,7 +291,7 @@ class Link: if self.destination.identity.validate(signature, signed_data): if self.status != Link.HANDSHAKE: - raise IOError("Invalid link state for proof validation: "+str(self.status)) + raise OSError(f"Invalid link state for proof validation: {self.status}") self.rtt = time.time() - self.request_time self.attached_interface = packet.receiving_interface @@ -300,7 +300,7 @@ class Link: self.activated_at = time.time() self.last_proof = self.activated_at RNS.Transport.activate_link(self) - RNS.log("Link "+str(self)+" established with "+str(self.destination)+", RTT is "+str(round(self.rtt, 3))+"s", RNS.LOG_VERBOSE) + RNS.log(f"Link {self} established with {self.destination}, RTT is {round(self.rtt, 3)}s", RNS.LOG_VERBOSE) if self.rtt != None and self.establishment_cost != None and self.rtt > 0 and self.establishment_cost > 0: self.establishment_rate = self.establishment_cost/self.rtt @@ -315,12 +315,12 @@ class Link: thread.daemon = True thread.start() else: - RNS.log("Invalid link proof signature received by "+str(self)+". Ignoring.", RNS.LOG_DEBUG) + RNS.log(f"Invalid link proof signature received by {self}. Ignoring.", RNS.LOG_DEBUG) except Exception as e: self.status = Link.CLOSED - RNS.log("An error ocurred while validating link request proof on "+str(self)+".", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while validating link request proof on {self}.", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) def identify(self, identity): @@ -380,7 +380,7 @@ class Link: else: request_id = RNS.Identity.truncated_hash(packed_request) - RNS.log("Sending request "+RNS.prettyhexrep(request_id)+" as resource.", RNS.LOG_DEBUG) + RNS.log(f"Sending request {RNS.prettyhexrep(request_id)} as resource.", RNS.LOG_DEBUG) request_resource = RNS.Resource(packed_request, self, request_id = request_id, is_response = False, timeout = timeout) return RequestReceipt( @@ -411,10 +411,10 @@ class Link: if self.owner.callbacks.link_established != None: self.owner.callbacks.link_established(self) except Exception as e: - RNS.log("Error occurred in external link establishment callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred in external link establishment callback. The contained exception was: {e}", RNS.LOG_ERROR) except Exception as e: - RNS.log("Error occurred while processing RTT packet, tearing down link. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while processing RTT packet, tearing down link. The contained exception was: {e}", RNS.LOG_ERROR) self.teardown() def track_phy_stats(self, track): @@ -563,7 +563,7 @@ class Link: try: self.callbacks.link_closed(self) except Exception as e: - RNS.log("Error while executing link closed callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing link closed callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def start_watchdog(self): @@ -634,7 +634,7 @@ class Link: if sleep_time == 0: RNS.log("Warning! Link watchdog sleep time of 0!", RNS.LOG_ERROR) if sleep_time == None or sleep_time < 0: - RNS.log("Timing error! Tearing down link "+str(self)+" now.", RNS.LOG_ERROR) + RNS.log(f"Timing error! Tearing down link {self} now.", RNS.LOG_ERROR) self.teardown() sleep_time = 0.1 @@ -683,7 +683,7 @@ class Link: allowed = True if allowed: - RNS.log("Handling request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_DEBUG) + RNS.log(f"Handling request {RNS.prettyhexrep(request_id)} for: {path}", RNS.LOG_DEBUG) if len(inspect.signature(response_generator).parameters) == 5: response = response_generator(path, request_data, request_id, self.__remote_identity, requested_at) elif len(inspect.signature(response_generator).parameters) == 6: @@ -700,7 +700,7 @@ class Link: response_resource = RNS.Resource(packed_response, self, request_id = request_id, is_response = True) else: identity_string = str(self.get_remote_identity()) if self.get_remote_identity() != None else "" - RNS.log("Request "+RNS.prettyhexrep(request_id)+" from "+identity_string+" not allowed for: "+str(path), RNS.LOG_DEBUG) + RNS.log(f"Request {RNS.prettyhexrep(request_id)} from {identity_string} not allowed for: {path}", RNS.LOG_DEBUG) def handle_response(self, request_id, response_data, response_size, response_transfer_size): if self.status == Link.ACTIVE: @@ -715,7 +715,7 @@ class Link: pending_request.response_transfer_size += response_transfer_size pending_request.response_received(response_data) except Exception as e: - RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while handling response. The contained exception was: {e}", RNS.LOG_ERROR) break @@ -732,7 +732,7 @@ class Link: self.handle_request(request_id, request_data) else: - RNS.log("Incoming request resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG) + RNS.log(f"Incoming request resource failed with status: {RNS.hexrep([resource.status])}", RNS.LOG_DEBUG) def response_resource_concluded(self, resource): if resource.status == RNS.Resource.COMPLETE: @@ -743,7 +743,7 @@ class Link: self.handle_response(request_id, response_data, resource.total_size, resource.size) else: - RNS.log("Incoming response resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG) + RNS.log(f"Incoming response resource failed with status: {RNS.hexrep([resource.status])}", RNS.LOG_DEBUG) for pending_request in self.pending_requests: if pending_request.request_id == resource.request_id: pending_request.request_timed_out(None) @@ -794,7 +794,7 @@ class Link: packet.prove() should_query = True except Exception as e: - RNS.log("Error while executing proof request callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing proof request callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) self.__update_phy_stats(packet, query_shared=should_query) @@ -814,7 +814,7 @@ class Link: try: self.callbacks.remote_identified(self, self.__remote_identity) except Exception as e: - RNS.log("Error while executing remote identified callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing remote identified callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) self.__update_phy_stats(packet, query_shared=True) @@ -827,7 +827,7 @@ class Link: self.handle_request(request_id, unpacked_request) self.__update_phy_stats(packet, query_shared=True) except Exception as e: - RNS.log("Error occurred while handling request. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while handling request. The contained exception was: {e}", RNS.LOG_ERROR) elif packet.context == RNS.Packet.RESPONSE: try: @@ -840,7 +840,7 @@ class Link: self.handle_response(request_id, response_data, transfer_size, transfer_size) self.__update_phy_stats(packet, query_shared=True) except Exception as e: - RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error occurred while handling response. The contained exception was: {e}", RNS.LOG_ERROR) elif packet.context == RNS.Packet.LRRTT: if not self.initiator: @@ -883,7 +883,7 @@ class Link: if self.callbacks.resource(resource_advertisement): RNS.Resource.accept(packet, self.callbacks.resource_concluded) except Exception as e: - RNS.log("Error while executing resource accept callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing resource accept callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) elif self.resource_strategy == Link.ACCEPT_ALL: RNS.Resource.accept(packet, self.callbacks.resource_concluded) @@ -970,13 +970,13 @@ class Link: try: self.fernet = Fernet(self.derived_key) except Exception as e: - RNS.log("Could not instantiate Fernet while performin encryption on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not instantiate Fernet while performin encryption on link {self}. The contained exception was: {e}", RNS.LOG_ERROR) raise e return self.fernet.encrypt(plaintext) except Exception as e: - RNS.log("Encryption on link "+str(self)+" failed. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Encryption on link {self} failed. The contained exception was: {e}", RNS.LOG_ERROR) raise e @@ -988,7 +988,7 @@ class Link: return self.fernet.decrypt(ciphertext) except Exception as e: - RNS.log("Decryption failed on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Decryption failed on link {self}. The contained exception was: {e}", RNS.LOG_ERROR) return None @@ -1169,7 +1169,7 @@ class RequestReceipt(): def request_resource_concluded(self, resource): if resource.status == RNS.Resource.COMPLETE: - RNS.log("Request "+RNS.prettyhexrep(self.request_id)+" successfully sent as resource.", RNS.LOG_DEBUG) + RNS.log(f"Request {RNS.prettyhexrep(self.request_id)} successfully sent as resource.", RNS.LOG_DEBUG) if self.started_at == None: self.started_at = time.time() self.status = RequestReceipt.DELIVERED @@ -1178,7 +1178,7 @@ class RequestReceipt(): response_timeout_thread.daemon = True response_timeout_thread.start() else: - RNS.log("Sending request "+RNS.prettyhexrep(self.request_id)+" as resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG) + RNS.log(f"Sending request {RNS.prettyhexrep(self.request_id)} as resource failed with status: {RNS.hexrep([resource.status])}", RNS.LOG_DEBUG) self.status = RequestReceipt.FAILED self.concluded_at = time.time() self.link.pending_requests.remove(self) @@ -1187,7 +1187,7 @@ class RequestReceipt(): try: self.callbacks.failed(self) except Exception as e: - RNS.log("Error while executing request failed callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing request failed callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def __response_timeout_job(self): @@ -1208,7 +1208,7 @@ class RequestReceipt(): try: self.callbacks.failed(self) except Exception as e: - RNS.log("Error while executing request timed out callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing request timed out callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def response_resource_progress(self, resource): @@ -1229,7 +1229,7 @@ class RequestReceipt(): try: self.callbacks.progress(self) except Exception as e: - RNS.log("Error while executing response progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing response progress callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) else: resource.cancel() @@ -1252,13 +1252,13 @@ class RequestReceipt(): try: self.callbacks.progress(self) except Exception as e: - RNS.log("Error while executing response progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing response progress callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) if self.callbacks.response != None: try: self.callbacks.response(self) except Exception as e: - RNS.log("Error while executing response received callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing response received callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def get_request_id(self): """ diff --git a/RNS/Packet.py b/RNS/Packet.py index 2db664b..03eccf0 100755 --- a/RNS/Packet.py +++ b/RNS/Packet.py @@ -208,14 +208,14 @@ class Packet: # Announce packets are not encrypted self.ciphertext = self.data else: - raise IOError("Packet with header type 2 must have a transport ID") + raise OSError("Packet with header type 2 must have a transport ID") self.header += bytes([self.context]) self.raw = self.header + self.ciphertext if len(self.raw) > self.MTU: - raise IOError("Packet size of "+str(len(self.raw))+" exceeds MTU of "+str(self.MTU)+" bytes") + raise OSError(f"Packet size of {len(self.raw)} exceeds MTU of {self.MTU} bytes") self.packed = True self.update_hash() @@ -250,7 +250,7 @@ class Packet: return True except Exception as e: - RNS.log("Received malformed packet, dropping it. The contained exception was: "+str(e), RNS.LOG_EXTREME) + RNS.log(f"Received malformed packet, dropping it. The contained exception was: {e}", RNS.LOG_EXTREME) return False def send(self): @@ -262,7 +262,7 @@ class Packet: if not self.sent: if self.destination.type == RNS.Destination.LINK: if self.destination.status == RNS.Link.CLOSED: - raise IOError("Attempt to transmit over a closed link") + raise OSError("Attempt to transmit over a closed link") else: self.destination.last_outbound = time.time() self.destination.tx += 1 @@ -280,7 +280,7 @@ class Packet: return False else: - raise IOError("Packet was already sent") + raise OSError("Packet was already sent") def resend(self): """ @@ -301,7 +301,7 @@ class Packet: self.receipt = None return False else: - raise IOError("Packet was not sent yet") + raise OSError("Packet was not sent yet") def prove(self, destination=None): if self.fromPacked and hasattr(self, "destination") and self.destination: @@ -419,8 +419,8 @@ class PacketReceipt: try: self.callbacks.delivery(self) except Exception as e: - RNS.log("An error occurred while evaluating external delivery callback for "+str(link), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while evaluating external delivery callback for {link}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) return True @@ -465,7 +465,7 @@ class PacketReceipt: try: self.callbacks.delivery(self) except Exception as e: - RNS.log("Error while executing proof validated callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing proof validated callback. The contained exception was: {e}", RNS.LOG_ERROR) return True else: @@ -489,7 +489,7 @@ class PacketReceipt: try: self.callbacks.delivery(self) except Exception as e: - RNS.log("Error while executing proof validated callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing proof validated callback. The contained exception was: {e}", RNS.LOG_ERROR) return True else: diff --git a/RNS/Resource.py b/RNS/Resource.py index 61fff48..7632ca2 100644 --- a/RNS/Resource.py +++ b/RNS/Resource.py @@ -172,7 +172,7 @@ class Resource: resource.window_flexibility = Resource.WINDOW_FLEXIBILITY resource.last_activity = time.time() - resource.storagepath = RNS.Reticulum.resourcepath+"/"+resource.original_hash.hex() + resource.storagepath = f"{RNS.Reticulum.resourcepath}/{resource.original_hash.hex()}" resource.segment_index = adv.i resource.total_segments = adv.l if adv.l > 1: @@ -194,7 +194,7 @@ class Resource: try: resource.link.callbacks.resource_started(resource) except Exception as e: - RNS.log("Error while executing resource started callback from "+str(resource)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing resource started callback from {resource}. The contained exception was: {e}", RNS.LOG_ERROR) resource.hashmap_update(0, resource.hashmap_raw) @@ -203,7 +203,7 @@ class Resource: return resource else: - RNS.log("Ignoring resource advertisement for "+RNS.prettyhexrep(resource.hash)+", resource already transferring", RNS.LOG_DEBUG) + RNS.log(f"Ignoring resource advertisement for {RNS.prettyhexrep(resource.hash)}, resource already transferring", RNS.LOG_DEBUG) return None except Exception as e: @@ -309,7 +309,7 @@ class Resource: if (auto_compress and len(self.uncompressed_data) <= Resource.AUTO_COMPRESS_MAX_SIZE): RNS.log("Compressing resource data...", RNS.LOG_DEBUG) self.compressed_data = bz2.compress(self.uncompressed_data) - RNS.log("Compression completed in "+str(round(time.time()-compression_began, 3))+" seconds", RNS.LOG_DEBUG) + RNS.log(f"Compression completed in {round(time.time() - compression_began, 3)} seconds", RNS.LOG_DEBUG) else: self.compressed_data = self.uncompressed_data @@ -318,7 +318,7 @@ class Resource: if (self.compressed_size < self.uncompressed_size and auto_compress): saved_bytes = len(self.uncompressed_data) - len(self.compressed_data) - RNS.log("Compression saved "+str(saved_bytes)+" bytes, sending compressed", RNS.LOG_DEBUG) + RNS.log(f"Compression saved {saved_bytes} bytes, sending compressed", RNS.LOG_DEBUG) self.data = b"" self.data += RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE] @@ -352,7 +352,7 @@ class Resource: hashmap_ok = False while not hashmap_ok: hashmap_computation_began = time.time() - RNS.log("Starting resource hashmap computation with "+str(hashmap_entries)+" entries...", RNS.LOG_DEBUG) + RNS.log(f"Starting resource hashmap computation with {hashmap_entries} entries...", RNS.LOG_DEBUG) self.random_hash = RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE] self.hash = RNS.Identity.full_hash(data+self.random_hash) @@ -388,7 +388,7 @@ class Resource: self.hashmap += part.map_hash self.parts.append(part) - RNS.log("Hashmap computation concluded in "+str(round(time.time()-hashmap_computation_began, 3))+" seconds", RNS.LOG_DEBUG) + RNS.log(f"Hashmap computation concluded in {round(time.time() - hashmap_computation_began, 3)} seconds", RNS.LOG_DEBUG) if advertise: self.advertise() @@ -447,9 +447,9 @@ class Resource: self.status = Resource.ADVERTISED self.retries_left = self.max_adv_retries self.link.register_outgoing_resource(self) - RNS.log("Sent resource advertisement for "+RNS.prettyhexrep(self.hash), RNS.LOG_DEBUG) + RNS.log(f"Sent resource advertisement for {RNS.prettyhexrep(self.hash)}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Could not advertise resource, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not advertise resource, the contained exception was: {e}", RNS.LOG_ERROR) self.cancel() return @@ -487,7 +487,7 @@ class Resource: self.adv_sent = self.last_activity sleep_time = 0.001 except Exception as e: - RNS.log("Could not resend advertisement packet, cancelling resource. The contained exception was: "+str(e), RNS.LOG_VERBOSE) + RNS.log(f"Could not resend advertisement packet, cancelling resource. The contained exception was: {e}", RNS.LOG_VERBOSE) self.cancel() @@ -508,7 +508,7 @@ class Resource: if sleep_time < 0: if self.retries_left > 0: ms = "" if self.outstanding_parts == 1 else "s" - RNS.log("Timed out waiting for "+str(self.outstanding_parts)+" part"+ms+", requesting retry", RNS.LOG_DEBUG) + RNS.log(f"Timed out waiting for {self.outstanding_parts} part{ms}, requesting retry", RNS.LOG_DEBUG) if self.window > self.window_min: self.window -= 1 if self.window_max > self.window_min: @@ -591,7 +591,7 @@ class Resource: except Exception as e: RNS.log("Error while assembling received resource.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.status = Resource.CORRUPT self.link.resource_concluded(self) @@ -602,7 +602,7 @@ class Resource: try: self.callback(self) except Exception as e: - RNS.log("Error while executing resource assembled callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing resource assembled callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) try: if hasattr(self.data, "close") and callable(self.data.close): @@ -614,7 +614,7 @@ class Resource: RNS.log("Error while cleaning up resource files, the contained exception was:", RNS.LOG_ERROR) RNS.log(str(e)) else: - RNS.log("Resource segment "+str(self.segment_index)+" of "+str(self.total_segments)+" received, waiting for next segment to be announced", RNS.LOG_DEBUG) + RNS.log(f"Resource segment {self.segment_index} of {self.total_segments} received, waiting for next segment to be announced", RNS.LOG_DEBUG) def prove(self): @@ -626,7 +626,7 @@ class Resource: proof_packet.send() except Exception as e: RNS.log("Could not send proof packet, cancelling resource", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) self.cancel() def __prepare_next_segment(self): @@ -657,7 +657,7 @@ class Resource: try: self.callback(self) except Exception as e: - RNS.log("Error while executing resource concluded callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing resource concluded callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) finally: try: if hasattr(self, "input_file"): @@ -665,7 +665,7 @@ class Resource: self.input_file.close() except Exception as e: - RNS.log("Error while closing resource input file: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while closing resource input file: {e}", RNS.LOG_ERROR) else: # Otherwise we'll recursively create the # next segment of the resource @@ -742,7 +742,7 @@ class Resource: try: self.__progress_callback(self) except Exception as e: - RNS.log("Error while executing progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing progress callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) i += 1 @@ -830,7 +830,7 @@ class Resource: except Exception as e: RNS.log("Could not send resource request packet, cancelling resource", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) self.cancel() # Called on outgoing resource to make it send more data @@ -876,7 +876,7 @@ class Resource: except Exception as e: RNS.log("Resource could not send parts, cancelling transfer!", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) self.cancel() if wants_more_hashmap: @@ -915,7 +915,7 @@ class Resource: self.last_activity = time.time() except Exception as e: RNS.log("Could not send resource HMU packet, cancelling resource", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) self.cancel() if self.sent_parts == len(self.parts): @@ -925,7 +925,7 @@ class Resource: try: self.__progress_callback(self) except Exception as e: - RNS.log("Error while executing progress callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing progress callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def cancel(self): """ @@ -939,7 +939,7 @@ class Resource: cancel_packet = RNS.Packet(self.link, self.hash, context=RNS.Packet.RESOURCE_ICL) cancel_packet.send() except Exception as e: - RNS.log("Could not send resource cancel packet, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not send resource cancel packet, the contained exception was: {e}", RNS.LOG_ERROR) self.link.cancel_outgoing_resource(self) else: self.link.cancel_incoming_resource(self) @@ -949,7 +949,7 @@ class Resource: self.link.resource_concluded(self) self.callback(self) except Exception as e: - RNS.log("Error while executing callbacks on resource cancel from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing callbacks on resource cancel from {self}. The contained exception was: {e}", RNS.LOG_ERROR) def set_callback(self, callback): self.callback = callback @@ -1015,7 +1015,7 @@ class Resource: return self.compressed def __str__(self): - return "<"+RNS.hexrep(self.hash,delimit=False)+"/"+RNS.hexrep(self.link.link_id,delimit=False)+">" + return f"<{RNS.hexrep(self.hash, delimit=False)}/{RNS.hexrep(self.link.link_id, delimit=False)}>" class ResourceAdvertisement: diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index 424063c..b9b9a1a 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -203,20 +203,20 @@ class Reticulum: else: if os.path.isdir("/etc/reticulum") and os.path.isfile("/etc/reticulum/config"): Reticulum.configdir = "/etc/reticulum" - elif os.path.isdir(Reticulum.userdir+"/.config/reticulum") and os.path.isfile(Reticulum.userdir+"/.config/reticulum/config"): - Reticulum.configdir = Reticulum.userdir+"/.config/reticulum" + elif os.path.isdir(f"{Reticulum.userdir}/.config/reticulum") and os.path.isfile(f"{Reticulum.userdir}/.config/reticulum/config"): + Reticulum.configdir = f"{Reticulum.userdir}/.config/reticulum" else: - Reticulum.configdir = Reticulum.userdir+"/.reticulum" + Reticulum.configdir = f"{Reticulum.userdir}/.reticulum" if logdest == RNS.LOG_FILE: RNS.logdest = RNS.LOG_FILE - RNS.logfile = Reticulum.configdir+"/logfile" + RNS.logfile = f"{Reticulum.configdir}/logfile" - Reticulum.configpath = Reticulum.configdir+"/config" - Reticulum.storagepath = Reticulum.configdir+"/storage" - Reticulum.cachepath = Reticulum.configdir+"/storage/cache" - Reticulum.resourcepath = Reticulum.configdir+"/storage/resources" - Reticulum.identitypath = Reticulum.configdir+"/storage/identities" + Reticulum.configpath = f"{Reticulum.configdir}/config" + Reticulum.storagepath = f"{Reticulum.configdir}/storage" + Reticulum.cachepath = f"{Reticulum.configdir}/storage/cache" + Reticulum.resourcepath = f"{Reticulum.configdir}/storage/resources" + Reticulum.identitypath = f"{Reticulum.configdir}/storage/identities" Reticulum.__transport_enabled = False Reticulum.__remote_management_enabled = False @@ -266,17 +266,17 @@ class Reticulum: try: self.config = ConfigObj(self.configpath) except Exception as e: - RNS.log("Could not parse the configuration at "+self.configpath, RNS.LOG_ERROR) + RNS.log(f"Could not parse the configuration at {self.configpath}", RNS.LOG_ERROR) RNS.log("Check your configuration file for errors!", RNS.LOG_ERROR) RNS.panic() else: RNS.log("Could not load config file, creating default configuration file...") self.__create_default_config() - RNS.log("Default config file created. Make any necessary changes in "+Reticulum.configdir+"/config and restart Reticulum if needed.") + RNS.log(f"Default config file created. Make any necessary changes in {Reticulum.configdir}/config and restart Reticulum if needed.") time.sleep(1.5) self.__apply_config() - RNS.log("Configuration loaded from "+self.configpath, RNS.LOG_VERBOSE) + RNS.log(f"Configuration loaded from {self.configpath}", RNS.LOG_VERBOSE) RNS.Identity.load_known_destinations() @@ -331,7 +331,7 @@ class Reticulum: RNS.Transport.interfaces.append(interface) self.is_shared_instance = True - RNS.log("Started shared instance interface: "+str(interface), RNS.LOG_DEBUG) + RNS.log(f"Started shared instance interface: {interface}", RNS.LOG_DEBUG) self.__start_jobs() except Exception as e: @@ -353,10 +353,10 @@ class Reticulum: Reticulum.__transport_enabled = False Reticulum.__remote_management_enabled = False Reticulum.__allow_probes = False - RNS.log("Connected to locally available Reticulum instance via: "+str(interface), RNS.LOG_DEBUG) + RNS.log(f"Connected to locally available Reticulum instance via: {interface}", RNS.LOG_DEBUG) except Exception as e: RNS.log("Local shared instance appears to be running, but it could not be connected", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) self.is_shared_instance = False self.is_standalone_instance = True self.is_connected_to_shared_instance = False @@ -411,11 +411,11 @@ class Reticulum: for hexhash in v: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(hexhash) != dest_len: - raise ValueError("Identity hash length for remote management ACL "+str(hexhash)+" is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Identity hash length for remote management ACL {hexhash} is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: allowed_hash = bytes.fromhex(hexhash) except Exception as e: - raise ValueError("Invalid identity hash for remote management ACL: "+str(hexhash)) + raise ValueError(f"Invalid identity hash for remote management ACL: {hexhash}") if not allowed_hash in RNS.Transport.remote_management_allowed: RNS.Transport.remote_management_allowed.append(allowed_hash) @@ -658,7 +658,7 @@ class Reticulum: interface.OUT = True if interface_mode == Interface.Interface.MODE_ACCESS_POINT: - RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) + RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) interface_mode = Interface.Interface.MODE_FULL interface.mode = interface_mode @@ -695,7 +695,7 @@ class Reticulum: interface.OUT = True if interface_mode == Interface.Interface.MODE_ACCESS_POINT: - RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) + RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) interface_mode = Interface.Interface.MODE_FULL interface.mode = interface_mode @@ -732,7 +732,7 @@ class Reticulum: interface.OUT = True if interface_mode == Interface.Interface.MODE_ACCESS_POINT: - RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) + RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) interface_mode = Interface.Interface.MODE_FULL interface.mode = interface_mode @@ -1029,17 +1029,17 @@ class Reticulum: # if no subinterfaces are defined if count == 0: - raise ValueError("No subinterfaces configured for "+name) + raise ValueError(f"No subinterfaces configured for {name}") # if no subinterfaces are enabled elif enabled_count == 0: - raise ValueError("No subinterfaces enabled for "+name) + raise ValueError(f"No subinterfaces enabled for {name}") id_interval = int(c["id_interval"]) if "id_interval" in c else None id_callsign = c["id_callsign"] if "id_callsign" in c else None port = c["port"] if "port" in c else None if port == None: - raise ValueError("No port specified for "+name) + raise ValueError(f"No port specified for {name}") interface = RNodeMultiInterface.RNodeMultiInterface( RNS.Transport, @@ -1106,14 +1106,14 @@ class Reticulum: interface.start() else: - RNS.log("Skipping disabled interface \""+name+"\"", RNS.LOG_DEBUG) + RNS.log(f"Skipping disabled interface \"{name}\"", RNS.LOG_DEBUG) except Exception as e: - RNS.log("The interface \""+name+"\" could not be created. Check your configuration file for errors!", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The interface \"{name}\" could not be created. Check your configuration file for errors!", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.panic() else: - RNS.log("The interface name \""+name+"\" was already used. Check your configuration file for errors!", RNS.LOG_ERROR) + RNS.log(f"The interface name \"{name}\" was already used. Check your configuration file for errors!", RNS.LOG_ERROR) RNS.panic() RNS.log("System interfaces are ready", RNS.LOG_VERBOSE) @@ -1181,27 +1181,27 @@ class Reticulum: for filename in os.listdir(self.resourcepath): try: if len(filename) == (RNS.Identity.HASHLENGTH//8)*2: - filepath = self.resourcepath + "/" + filename + filepath = f"{self.resourcepath}/{filename}" mtime = os.path.getmtime(filepath) age = now - mtime if age > Reticulum.RESOURCE_CACHE: os.unlink(filepath) except Exception as e: - RNS.log("Error while cleaning resources cache, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while cleaning resources cache, the contained exception was: {e}", RNS.LOG_ERROR) # Clean packet caches for filename in os.listdir(self.cachepath): try: if len(filename) == (RNS.Identity.HASHLENGTH//8)*2: - filepath = self.cachepath + "/" + filename + filepath = f"{self.cachepath}/{filename}" mtime = os.path.getmtime(filepath) age = now - mtime if age > RNS.Transport.DESTINATION_TIMEOUT: os.unlink(filepath) except Exception as e: - RNS.log("Error while cleaning resources cache, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while cleaning resources cache, the contained exception was: {e}", RNS.LOG_ERROR) def __create_default_config(self): self.config = ConfigObj(__default_rns_config__) @@ -1266,7 +1266,7 @@ class Reticulum: rpc_connection.close() except Exception as e: - RNS.log("An error ocurred while handling RPC call from local client: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while handling RPC call from local client: {e}", RNS.LOG_ERROR) def get_interface_stats(self): if self.is_connected_to_shared_instance: @@ -1296,7 +1296,7 @@ class Reticulum: if hasattr(interface, "b32"): if interface.b32 != None: - ifstats["i2p_b32"] = interface.b32+".b32.i2p" + ifstats["i2p_b32"] = f"{interface.b32}.b32.i2p" else: ifstats["i2p_b32"] = None @@ -1485,12 +1485,12 @@ class Reticulum: if self.is_connected_to_shared_instance and hasattr(self, "_force_shared_instance_bitrate") and self._force_shared_instance_bitrate: simulated_latency = ((1/self._force_shared_instance_bitrate)*8)*RNS.Reticulum.MTU - RNS.log("Adding simulated latency of "+RNS.prettytime(simulated_latency)+" to first hop timeout", RNS.LOG_DEBUG) + RNS.log(f"Adding simulated latency of {RNS.prettytime(simulated_latency)} to first hop timeout", RNS.LOG_DEBUG) response += simulated_latency return response except Exception as e: - RNS.log("An error occurred while getting first hop timeout from shared instance: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while getting first hop timeout from shared instance: {e}", RNS.LOG_ERROR) return RNS.Reticulum.DEFAULT_PER_HOP_TIMEOUT else: diff --git a/RNS/Transport.py b/RNS/Transport.py index 51c7b36..d1bd685 100755 --- a/RNS/Transport.py +++ b/RNS/Transport.py @@ -148,7 +148,7 @@ class Transport: Transport.owner = reticulum_instance if Transport.identity == None: - transport_identity_path = RNS.Reticulum.storagepath+"/transport_identity" + transport_identity_path = f"{RNS.Reticulum.storagepath}/transport_identity" if os.path.isfile(transport_identity_path): Transport.identity = RNS.Identity.from_file(transport_identity_path) @@ -159,7 +159,7 @@ class Transport: else: RNS.log("Loaded Transport Identity from storage", RNS.LOG_VERBOSE) - packet_hashlist_path = RNS.Reticulum.storagepath+"/packet_hashlist" + packet_hashlist_path = f"{RNS.Reticulum.storagepath}/packet_hashlist" if not Transport.owner.is_connected_to_shared_instance: if os.path.isfile(packet_hashlist_path): try: @@ -167,7 +167,7 @@ class Transport: Transport.packet_hashlist = umsgpack.unpackb(file.read()) file.close() except Exception as e: - RNS.log("Could not load packet hashlist from storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not load packet hashlist from storage, the contained exception was: {e}", RNS.LOG_ERROR) # Create transport-specific destinations Transport.path_request_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, Transport.APP_NAME, "path", "request") @@ -186,15 +186,15 @@ class Transport: Transport.remote_management_destination.register_request_handler("/path", response_generator = Transport.remote_path_handler, allow = RNS.Destination.ALLOW_LIST, allowed_list=Transport.remote_management_allowed) Transport.control_destinations.append(Transport.remote_management_destination) Transport.control_hashes.append(Transport.remote_management_destination.hash) - RNS.log("Enabled remote management on "+str(Transport.remote_management_destination), RNS.LOG_NOTICE) + RNS.log(f"Enabled remote management on {Transport.remote_management_destination}", RNS.LOG_NOTICE) Transport.jobs_running = False thread = threading.Thread(target=Transport.jobloop, daemon=True) thread.start() if RNS.Reticulum.transport_enabled(): - destination_table_path = RNS.Reticulum.storagepath+"/destination_table" - tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels" + destination_table_path = f"{RNS.Reticulum.storagepath}/destination_table" + tunnel_table_path = f"{RNS.Reticulum.storagepath}/tunnels" if os.path.isfile(destination_table_path) and not Transport.owner.is_connected_to_shared_instance: serialised_destinations = [] @@ -223,9 +223,9 @@ class Transport: # increased hop-count. announce_packet.hops += 1 Transport.destination_table[destination_hash] = [timestamp, received_from, hops, expires, random_blobs, receiving_interface, announce_packet] - RNS.log("Loaded path table entry for "+RNS.prettyhexrep(destination_hash)+" from storage", RNS.LOG_DEBUG) + RNS.log(f"Loaded path table entry for {RNS.prettyhexrep(destination_hash)} from storage", RNS.LOG_DEBUG) else: - RNS.log("Could not reconstruct path table entry from storage for "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG) + RNS.log(f"Could not reconstruct path table entry from storage for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_DEBUG) if announce_packet == None: RNS.log("The announce packet could not be loaded from cache", RNS.LOG_DEBUG) if receiving_interface == None: @@ -236,10 +236,10 @@ class Transport: else: specifier = "entries" - RNS.log("Loaded "+str(len(Transport.destination_table))+" path table "+specifier+" from storage", RNS.LOG_VERBOSE) + RNS.log(f"Loaded {len(Transport.destination_table)} path table {specifier} from storage", RNS.LOG_VERBOSE) except Exception as e: - RNS.log("Could not load destination table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not load destination table from storage, the contained exception was: {e}", RNS.LOG_ERROR) if os.path.isfile(tunnel_table_path) and not Transport.owner.is_connected_to_shared_instance: serialised_tunnels = [] @@ -284,21 +284,21 @@ class Transport: else: specifier = "entries" - RNS.log("Loaded "+str(len(Transport.tunnels))+" tunnel table "+specifier+" from storage", RNS.LOG_VERBOSE) + RNS.log(f"Loaded {len(Transport.tunnels)} tunnel table {specifier} from storage", RNS.LOG_VERBOSE) except Exception as e: - RNS.log("Could not load tunnel table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not load tunnel table from storage, the contained exception was: {e}", RNS.LOG_ERROR) if RNS.Reticulum.probe_destination_enabled(): Transport.probe_destination = RNS.Destination(Transport.identity, RNS.Destination.IN, RNS.Destination.SINGLE, Transport.APP_NAME, "probe") Transport.probe_destination.accepts_links(False) Transport.probe_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) Transport.probe_destination.announce() - RNS.log("Transport Instance will respond to probe requests on "+str(Transport.probe_destination), RNS.LOG_NOTICE) + RNS.log(f"Transport Instance will respond to probe requests on {Transport.probe_destination}", RNS.LOG_NOTICE) else: Transport.probe_destination = None - RNS.log("Transport instance "+str(Transport.identity)+" started", RNS.LOG_VERBOSE) + RNS.log(f"Transport instance {Transport.identity} started", RNS.LOG_VERBOSE) Transport.start_time = time.time() # Sort interfaces according to bitrate @@ -354,7 +354,7 @@ class Transport: last_path_request = Transport.path_requests[link.destination.hash] if time.time() - last_path_request > Transport.PATH_REQUEST_MI: - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link.destination.hash)+" since an attempted link was never established", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link.destination.hash)} since an attempted link was never established", RNS.LOG_DEBUG) if not link.destination.hash in path_requests: blocked_if = None path_requests[link.destination.hash] = blocked_if @@ -388,7 +388,7 @@ class Transport: for destination_hash in Transport.announce_table: announce_entry = Transport.announce_table[destination_hash] if announce_entry[2] > Transport.PATHFINDER_R: - RNS.log("Completed announce processing for "+RNS.prettyhexrep(destination_hash)+", retry limit reached", RNS.LOG_EXTREME) + RNS.log(f"Completed announce processing for {RNS.prettyhexrep(destination_hash)}, retry limit reached", RNS.LOG_EXTREME) completed_announces.append(destination_hash) else: if time.time() > announce_entry[1]: @@ -420,9 +420,9 @@ class Transport: new_packet.hops = announce_entry[4] if block_rebroadcasts: - RNS.log("Rebroadcasting announce as path response for "+RNS.prettyhexrep(announce_destination.hash)+" with hop count "+str(new_packet.hops), RNS.LOG_DEBUG) + RNS.log(f"Rebroadcasting announce as path response for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG) else: - RNS.log("Rebroadcasting announce for "+RNS.prettyhexrep(announce_destination.hash)+" with hop count "+str(new_packet.hops), RNS.LOG_DEBUG) + RNS.log(f"Rebroadcasting announce for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG) outgoing.append(new_packet) @@ -490,14 +490,14 @@ class Transport: # If the path has been invalidated between the time of # making the link request and now, try to rediscover it if not Transport.has_path(link_entry[6]): - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted link was never established, and path is now missing", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link_entry[6])} since an attempted link was never established, and path is now missing", RNS.LOG_DEBUG) path_request_conditions =True # If this link request was originated from a local client # attempt to rediscover a path to the destination, if this # has not already happened recently. elif not path_request_throttle and lr_taken_hops == 0: - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted local client link was never established", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link_entry[6])} since an attempted local client link was never established", RNS.LOG_DEBUG) path_request_conditions = True # If the link destination was previously only 1 hop @@ -506,7 +506,7 @@ class Transport: # In that case, try to discover a new path, and mark # the old one as unresponsive. elif not path_request_throttle and Transport.hops_to(link_entry[6]) == 1: - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted link was never established, and destination was previously local to an interface on this instance", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link_entry[6])} since an attempted link was never established, and destination was previously local to an interface on this instance", RNS.LOG_DEBUG) path_request_conditions = True blocked_if = link_entry[4] @@ -528,7 +528,7 @@ class Transport: # changed. In that case, we try to discover a new path, # and mark the old one as potentially unresponsive. elif not path_request_throttle and lr_taken_hops == 1: - RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted link was never established, and link initiator is local to an interface on this instance", RNS.LOG_DEBUG) + RNS.log(f"Trying to rediscover path for {RNS.prettyhexrep(link_entry[6])} since an attempted link was never established, and link initiator is local to an interface on this instance", RNS.LOG_DEBUG) path_request_conditions = True blocked_if = link_entry[4] @@ -561,10 +561,10 @@ class Transport: if time.time() > destination_expiry: stale_paths.append(destination_hash) - RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_DEBUG) + RNS.log(f"Path to {RNS.prettyhexrep(destination_hash)} timed out and was removed", RNS.LOG_DEBUG) elif not attached_interface in Transport.interfaces: stale_paths.append(destination_hash) - RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" was removed since the attached interface no longer exists", RNS.LOG_DEBUG) + RNS.log(f"Path to {RNS.prettyhexrep(destination_hash)} was removed since the attached interface no longer exists", RNS.LOG_DEBUG) # Cull the pending discovery path requests table stale_discovery_path_requests = [] @@ -573,7 +573,7 @@ class Transport: if time.time() > entry["timeout"]: stale_discovery_path_requests.append(destination_hash) - RNS.log("Waiting path request for "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_DEBUG) + RNS.log(f"Waiting path request for {RNS.prettyhexrep(destination_hash)} timed out and was removed", RNS.LOG_DEBUG) # Cull the tunnel table stale_tunnels = [] @@ -584,7 +584,7 @@ class Transport: expires = tunnel_entry[3] if time.time() > expires: stale_tunnels.append(tunnel_id) - RNS.log("Tunnel "+RNS.prettyhexrep(tunnel_id)+" timed out and was removed", RNS.LOG_EXTREME) + RNS.log(f"Tunnel {RNS.prettyhexrep(tunnel_id)} timed out and was removed", RNS.LOG_EXTREME) else: stale_tunnel_paths = [] tunnel_paths = tunnel_entry[2] @@ -593,7 +593,7 @@ class Transport: if time.time() > tunnel_path_entry[0] + Transport.DESTINATION_TIMEOUT: stale_tunnel_paths.append(tunnel_path) - RNS.log("Tunnel path to "+RNS.prettyhexrep(tunnel_path)+" timed out and was removed", RNS.LOG_EXTREME) + RNS.log(f"Tunnel path to {RNS.prettyhexrep(tunnel_path)} timed out and was removed", RNS.LOG_EXTREME) for tunnel_path in stale_tunnel_paths: tunnel_paths.pop(tunnel_path) @@ -602,9 +602,9 @@ class Transport: if ti > 0: if ti == 1: - RNS.log("Removed "+str(ti)+" tunnel path", RNS.LOG_EXTREME) + RNS.log(f"Removed {ti} tunnel path", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(ti)+" tunnel paths", RNS.LOG_EXTREME) + RNS.log(f"Removed {ti} tunnel paths", RNS.LOG_EXTREME) i = 0 for truncated_packet_hash in stale_reverse_entries: @@ -613,9 +613,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Released "+str(i)+" reverse table entry", RNS.LOG_EXTREME) + RNS.log(f"Released {i} reverse table entry", RNS.LOG_EXTREME) else: - RNS.log("Released "+str(i)+" reverse table entries", RNS.LOG_EXTREME) + RNS.log(f"Released {i} reverse table entries", RNS.LOG_EXTREME) i = 0 for link_id in stale_links: @@ -624,9 +624,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Released "+str(i)+" link", RNS.LOG_EXTREME) + RNS.log(f"Released {i} link", RNS.LOG_EXTREME) else: - RNS.log("Released "+str(i)+" links", RNS.LOG_EXTREME) + RNS.log(f"Released {i} links", RNS.LOG_EXTREME) i = 0 for destination_hash in stale_paths: @@ -635,9 +635,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Removed "+str(i)+" path", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} path", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(i)+" paths", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} paths", RNS.LOG_EXTREME) i = 0 for destination_hash in stale_discovery_path_requests: @@ -646,9 +646,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Removed "+str(i)+" waiting path request", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} waiting path request", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(i)+" waiting path requests", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} waiting path requests", RNS.LOG_EXTREME) i = 0 for tunnel_id in stale_tunnels: @@ -657,9 +657,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Removed "+str(i)+" tunnel", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} tunnel", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(i)+" tunnels", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} tunnels", RNS.LOG_EXTREME) i = 0 for destination_hash in stale_path_states: @@ -668,9 +668,9 @@ class Transport: if i > 0: if i == 1: - RNS.log("Removed "+str(i)+" path state entry", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} path state entry", RNS.LOG_EXTREME) else: - RNS.log("Removed "+str(i)+" path state entries", RNS.LOG_EXTREME) + RNS.log(f"Removed {i} path state entries", RNS.LOG_EXTREME) Transport.tables_last_culled = time.time() @@ -686,7 +686,7 @@ class Transport: except Exception as e: RNS.log("An exception occurred while running Transport jobs.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) Transport.jobs_running = False @@ -749,7 +749,7 @@ class Transport: interface.processOutgoing(raw) except Exception as e: - RNS.log("Error while transmitting on "+str(interface)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while transmitting on {interface}. The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def outbound(packet): @@ -857,7 +857,7 @@ class Transport: if packet.packet_type == RNS.Packet.ANNOUNCE: if packet.attached_interface == None: if interface.mode == RNS.Interfaces.Interface.Interface.MODE_ACCESS_POINT: - RNS.log("Blocking announce broadcast on "+str(interface)+" due to AP mode", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} due to AP mode", RNS.LOG_EXTREME) should_transmit = False elif interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING: @@ -870,15 +870,15 @@ class Transport: if from_interface == None or not hasattr(from_interface, "mode"): should_transmit = False if from_interface == None: - RNS.log("Blocking announce broadcast on "+str(interface)+" since next hop interface doesn't exist", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} since next hop interface doesn't exist", RNS.LOG_EXTREME) elif not hasattr(from_interface, "mode"): - RNS.log("Blocking announce broadcast on "+str(interface)+" since next hop interface has no mode configured", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} since next hop interface has no mode configured", RNS.LOG_EXTREME) else: if from_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING: - RNS.log("Blocking announce broadcast on "+str(interface)+" due to roaming-mode next-hop interface", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} due to roaming-mode next-hop interface", RNS.LOG_EXTREME) should_transmit = False elif from_interface.mode == RNS.Interfaces.Interface.Interface.MODE_BOUNDARY: - RNS.log("Blocking announce broadcast on "+str(interface)+" due to boundary-mode next-hop interface", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} due to boundary-mode next-hop interface", RNS.LOG_EXTREME) should_transmit = False elif interface.mode == RNS.Interfaces.Interface.Interface.MODE_BOUNDARY: @@ -891,12 +891,12 @@ class Transport: if from_interface == None or not hasattr(from_interface, "mode"): should_transmit = False if from_interface == None: - RNS.log("Blocking announce broadcast on "+str(interface)+" since next hop interface doesn't exist", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} since next hop interface doesn't exist", RNS.LOG_EXTREME) elif not hasattr(from_interface, "mode"): - RNS.log("Blocking announce broadcast on "+str(interface)+" since next hop interface has no mode configured", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} since next hop interface has no mode configured", RNS.LOG_EXTREME) else: if from_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING: - RNS.log("Blocking announce broadcast on "+str(interface)+" due to roaming-mode next-hop interface", RNS.LOG_EXTREME) + RNS.log(f"Blocking announce broadcast on {interface} due to roaming-mode next-hop interface", RNS.LOG_EXTREME) should_transmit = False else: @@ -959,23 +959,23 @@ class Transport: timer.start() if wait_time < 1: - wait_time_str = str(round(wait_time*1000,2))+"ms" + wait_time_str = f"{round(wait_time * 1000, 2)}ms" else: - wait_time_str = str(round(wait_time*1,2))+"s" + wait_time_str = f"{round(wait_time * 1, 2)}s" ql_str = str(len(interface.announce_queue)) - RNS.log("Added announce to queue (height "+ql_str+") on "+str(interface)+" for processing in "+wait_time_str, RNS.LOG_EXTREME) + RNS.log(f"Added announce to queue (height {ql_str}) on {interface} for processing in {wait_time_str}", RNS.LOG_EXTREME) else: wait_time = max(interface.announce_allowed_at - time.time(), 0) if wait_time < 1: - wait_time_str = str(round(wait_time*1000,2))+"ms" + wait_time_str = f"{round(wait_time * 1000, 2)}ms" else: - wait_time_str = str(round(wait_time*1,2))+"s" + wait_time_str = f"{round(wait_time * 1, 2)}s" ql_str = str(len(interface.announce_queue)) - RNS.log("Added announce to queue (height "+ql_str+") on "+str(interface)+" for processing in "+wait_time_str, RNS.LOG_EXTREME) + RNS.log(f"Added announce to queue (height {ql_str}) on {interface} for processing in {wait_time_str}", RNS.LOG_EXTREME) else: pass @@ -1013,7 +1013,7 @@ class Transport: # Filter packets intended for other transport instances if packet.transport_id != None and packet.packet_type != RNS.Packet.ANNOUNCE: if packet.transport_id != Transport.identity.hash: - RNS.log("Ignored packet "+RNS.prettyhexrep(packet.packet_hash)+" in transport for other transport instance", RNS.LOG_EXTREME) + RNS.log(f"Ignored packet {RNS.prettyhexrep(packet.packet_hash)} in transport for other transport instance", RNS.LOG_EXTREME) return False if packet.context == RNS.Packet.KEEPALIVE: @@ -1032,7 +1032,7 @@ class Transport: if packet.destination_type == RNS.Destination.PLAIN: if packet.packet_type != RNS.Packet.ANNOUNCE: if packet.hops > 1: - RNS.log("Dropped PLAIN packet "+RNS.prettyhexrep(packet.hash)+" with "+str(packet.hops)+" hops", RNS.LOG_DEBUG) + RNS.log(f"Dropped PLAIN packet {RNS.prettyhexrep(packet.hash)} with {packet.hops} hops", RNS.LOG_DEBUG) return False else: return True @@ -1043,7 +1043,7 @@ class Transport: if packet.destination_type == RNS.Destination.GROUP: if packet.packet_type != RNS.Packet.ANNOUNCE: if packet.hops > 1: - RNS.log("Dropped GROUP packet "+RNS.prettyhexrep(packet.hash)+" with "+str(packet.hops)+" hops", RNS.LOG_DEBUG) + RNS.log(f"Dropped GROUP packet {RNS.prettyhexrep(packet.hash)} with {packet.hops} hops", RNS.LOG_DEBUG) return False else: return True @@ -1061,7 +1061,7 @@ class Transport: RNS.log("Dropped invalid announce packet", RNS.LOG_DEBUG) return False - RNS.log("Filtered packet with hash "+RNS.prettyhexrep(packet.packet_hash), RNS.LOG_EXTREME) + RNS.log(f"Filtered packet with hash {RNS.prettyhexrep(packet.packet_hash)}", RNS.LOG_EXTREME) return False @staticmethod @@ -1316,7 +1316,7 @@ class Transport: # TODO: There should probably be some kind of REJECT # mechanism here, to signal to the source that their # expected path failed. - RNS.log("Got packet in transport, but no known path to final destination "+RNS.prettyhexrep(packet.destination_hash)+". Dropping packet.", RNS.LOG_EXTREME) + RNS.log(f"Got packet in transport, but no known path to final destination {RNS.prettyhexrep(packet.destination_hash)}. Dropping packet.", RNS.LOG_EXTREME) # Link transport handling. Directs packets according # to entries in the link tables @@ -1391,17 +1391,17 @@ class Transport: announce_entry = Transport.announce_table[packet.destination_hash] if packet.hops-1 == announce_entry[4]: - RNS.log("Heard a local rebroadcast of announce for "+RNS.prettyhexrep(packet.destination_hash), RNS.LOG_DEBUG) + RNS.log(f"Heard a local rebroadcast of announce for {RNS.prettyhexrep(packet.destination_hash)}", RNS.LOG_DEBUG) announce_entry[6] += 1 if announce_entry[6] >= Transport.LOCAL_REBROADCASTS_MAX: - RNS.log("Max local rebroadcasts of announce for "+RNS.prettyhexrep(packet.destination_hash)+" reached, dropping announce from our table", RNS.LOG_DEBUG) + RNS.log(f"Max local rebroadcasts of announce for {RNS.prettyhexrep(packet.destination_hash)} reached, dropping announce from our table", RNS.LOG_DEBUG) if packet.destination_hash in Transport.announce_table: Transport.announce_table.pop(packet.destination_hash) if packet.hops-1 == announce_entry[4]+1 and announce_entry[2] > 0: now = time.time() if now < announce_entry[1]: - RNS.log("Rebroadcasted announce for "+RNS.prettyhexrep(packet.destination_hash)+" has been passed on to another node, no further tries needed", RNS.LOG_DEBUG) + RNS.log(f"Rebroadcasted announce for {RNS.prettyhexrep(packet.destination_hash)} has been passed on to another node, no further tries needed", RNS.LOG_DEBUG) Transport.announce_table.pop(packet.destination_hash) else: @@ -1458,7 +1458,7 @@ class Transport: if not random_blob in random_blobs: # TODO: Check that this ^ approach actually # works under all circumstances - RNS.log("Replacing destination table entry for "+str(RNS.prettyhexrep(packet.destination_hash))+" with new announce due to expired path", RNS.LOG_DEBUG) + RNS.log(f"Replacing destination table entry for {RNS.prettyhexrep(packet.destination_hash)} with new announce due to expired path", RNS.LOG_DEBUG) Transport.mark_path_unknown_state(packet.destination_hash) should_add = True else: @@ -1469,7 +1469,7 @@ class Transport: # this announce before, update the path table. if (announce_emitted > path_announce_emitted): if not random_blob in random_blobs: - RNS.log("Replacing destination table entry for "+str(RNS.prettyhexrep(packet.destination_hash))+" with new announce, since it was more recently emitted", RNS.LOG_DEBUG) + RNS.log(f"Replacing destination table entry for {RNS.prettyhexrep(packet.destination_hash)} with new announce, since it was more recently emitted", RNS.LOG_DEBUG) Transport.mark_path_unknown_state(packet.destination_hash) should_add = True else: @@ -1481,7 +1481,7 @@ class Transport: # allow updating the path table to this one. elif announce_emitted == path_announce_emitted: if Transport.path_is_unresponsive(packet.destination_hash): - RNS.log("Replacing destination table entry for "+str(RNS.prettyhexrep(packet.destination_hash))+" with new announce, since previously tried path was unresponsive", RNS.LOG_DEBUG) + RNS.log(f"Replacing destination table entry for {RNS.prettyhexrep(packet.destination_hash)} with new announce, since previously tried path was unresponsive", RNS.LOG_DEBUG) should_add = True else: should_add = False @@ -1551,7 +1551,7 @@ class Transport: # Insert announce into announce table for retransmission if rate_blocked: - RNS.log("Blocking rebroadcast of announce from "+RNS.prettyhexrep(packet.destination_hash)+" due to excessive announce rate", RNS.LOG_DEBUG) + RNS.log(f"Blocking rebroadcast of announce from {RNS.prettyhexrep(packet.destination_hash)} due to excessive announce rate", RNS.LOG_DEBUG) else: if Transport.from_local_client(packet): @@ -1648,9 +1648,9 @@ class Transport: pr_entry = Transport.discovery_path_requests[packet.destination_hash] attached_interface = pr_entry["requesting_interface"] - interface_str = " on "+str(attached_interface) + interface_str = f" on {attached_interface}" - RNS.log("Got matching announce, answering waiting discovery path request for "+RNS.prettyhexrep(packet.destination_hash)+interface_str, RNS.LOG_DEBUG) + RNS.log(f"Got matching announce, answering waiting discovery path request for {RNS.prettyhexrep(packet.destination_hash)}{interface_str}", RNS.LOG_DEBUG) announce_identity = RNS.Identity.recall(packet.destination_hash) announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown"); announce_destination.hash = packet.destination_hash @@ -1675,7 +1675,7 @@ class Transport: destination_table_entry = [now, received_from, announce_hops, expires, random_blobs, packet.receiving_interface, packet] Transport.destination_table[packet.destination_hash] = destination_table_entry - RNS.log("Destination "+RNS.prettyhexrep(packet.destination_hash)+" is now "+str(announce_hops)+" hops away via "+RNS.prettyhexrep(received_from)+" on "+str(packet.receiving_interface), RNS.LOG_DEBUG) + RNS.log(f"Destination {RNS.prettyhexrep(packet.destination_hash)} is now {announce_hops} hops away via {RNS.prettyhexrep(received_from)} on {packet.receiving_interface}", RNS.LOG_DEBUG) # If the receiving interface is a tunnel, we add the # announce to the tunnels table @@ -1685,7 +1685,7 @@ class Transport: paths[packet.destination_hash] = destination_table_entry expires = time.time() + Transport.DESTINATION_TIMEOUT tunnel_entry[3] = expires - RNS.log("Path to "+RNS.prettyhexrep(packet.destination_hash)+" associated with tunnel "+RNS.prettyhexrep(packet.receiving_interface.tunnel_id), RNS.LOG_DEBUG) + RNS.log(f"Path to {RNS.prettyhexrep(packet.destination_hash)} associated with tunnel {RNS.prettyhexrep(packet.receiving_interface.tunnel_id)}", RNS.LOG_DEBUG) # Call externally registered callbacks from apps # wanting to know when an announce arrives @@ -1720,7 +1720,7 @@ class Transport: ) except Exception as e: RNS.log("Error while processing external announce callback.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) # Handling for link requests to local destinations @@ -1764,7 +1764,7 @@ class Transport: if destination.callbacks.proof_requested(packet): packet.prove() except Exception as e: - RNS.log("Error while executing proof request callback. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while executing proof request callback. The contained exception was: {e}", RNS.LOG_ERROR) # Handling for proofs and link-request proofs elif packet.packet_type == RNS.Packet.PROOF: @@ -1785,7 +1785,7 @@ class Transport: signature = packet.data[:RNS.Identity.SIGLENGTH//8] if peer_identity.validate(signature, signed_data): - RNS.log("Link request proof validated for transport via "+str(link_entry[4]), RNS.LOG_EXTREME) + RNS.log(f"Link request proof validated for transport via {link_entry[4]}", RNS.LOG_EXTREME) new_raw = packet.raw[0:1] new_raw += struct.pack("!B", packet.hops) new_raw += packet.raw[2:] @@ -1793,10 +1793,10 @@ class Transport: Transport.transmit(link_entry[4], new_raw) else: - RNS.log("Invalid link request proof in transport for link "+RNS.prettyhexrep(packet.destination_hash)+", dropping proof.", RNS.LOG_DEBUG) + RNS.log(f"Invalid link request proof in transport for link {RNS.prettyhexrep(packet.destination_hash)}, dropping proof.", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Error while transporting link request proof. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while transporting link request proof. The contained exception was: {e}", RNS.LOG_ERROR) else: RNS.log("Link request proof received on wrong interface, not transporting it.", RNS.LOG_DEBUG) @@ -1845,7 +1845,7 @@ class Transport: if (RNS.Reticulum.transport_enabled() or from_local_client or proof_for_local_client) and packet.destination_hash in Transport.reverse_table: reverse_entry = Transport.reverse_table.pop(packet.destination_hash) if packet.receiving_interface == reverse_entry[1]: - RNS.log("Proof received on correct interface, transporting it via "+str(reverse_entry[0]), RNS.LOG_EXTREME) + RNS.log(f"Proof received on correct interface, transporting it via {reverse_entry[0]}", RNS.LOG_EXTREME) new_raw = packet.raw[0:1] new_raw += struct.pack("!B", packet.hops) new_raw += packet.raw[2:] @@ -1913,19 +1913,19 @@ class Transport: except Exception as e: RNS.log("An error occurred while validating tunnel establishment packet.", RNS.LOG_DEBUG) - RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG) + RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) @staticmethod def handle_tunnel(tunnel_id, interface): expires = time.time() + Transport.DESTINATION_TIMEOUT if not tunnel_id in Transport.tunnels: - RNS.log("Tunnel endpoint "+RNS.prettyhexrep(tunnel_id)+" established.", RNS.LOG_DEBUG) + RNS.log(f"Tunnel endpoint {RNS.prettyhexrep(tunnel_id)} established.", RNS.LOG_DEBUG) paths = {} tunnel_entry = [tunnel_id, interface, paths, expires] interface.tunnel_id = tunnel_id Transport.tunnels[tunnel_id] = tunnel_entry else: - RNS.log("Tunnel endpoint "+RNS.prettyhexrep(tunnel_id)+" reappeared. Restoring paths...", RNS.LOG_DEBUG) + RNS.log(f"Tunnel endpoint {RNS.prettyhexrep(tunnel_id)} reappeared. Restoring paths...", RNS.LOG_DEBUG) tunnel_entry = Transport.tunnels[tunnel_id] tunnel_entry[1] = interface tunnel_entry[3] = expires @@ -1950,21 +1950,21 @@ class Transport: if announce_hops <= old_hops or time.time() > old_expires: should_add = True else: - RNS.log("Did not restore path to "+RNS.prettyhexrep(packet.destination_hash)+" because a newer path with fewer hops exist", RNS.LOG_DEBUG) + RNS.log(f"Did not restore path to {RNS.prettyhexrep(packet.destination_hash)} because a newer path with fewer hops exist", RNS.LOG_DEBUG) else: if time.time() < expires: should_add = True else: - RNS.log("Did not restore path to "+RNS.prettyhexrep(packet.destination_hash)+" because it has expired", RNS.LOG_DEBUG) + RNS.log(f"Did not restore path to {RNS.prettyhexrep(packet.destination_hash)} because it has expired", RNS.LOG_DEBUG) if should_add: Transport.destination_table[destination_hash] = new_entry - RNS.log("Restored path to "+RNS.prettyhexrep(packet.destination_hash)+" is now "+str(announce_hops)+" hops away via "+RNS.prettyhexrep(received_from)+" on "+str(receiving_interface), RNS.LOG_DEBUG) + RNS.log(f"Restored path to {RNS.prettyhexrep(packet.destination_hash)} is now {announce_hops} hops away via {RNS.prettyhexrep(received_from)} on {receiving_interface}", RNS.LOG_DEBUG) else: deprecated_paths.append(destination_hash) for deprecated_path in deprecated_paths: - RNS.log("Removing path to "+RNS.prettyhexrep(deprecated_path)+" from tunnel "+RNS.prettyhexrep(tunnel_id), RNS.LOG_DEBUG) + RNS.log(f"Removing path to {RNS.prettyhexrep(deprecated_path)} from tunnel {RNS.prettyhexrep(tunnel_id)}", RNS.LOG_DEBUG) paths.pop(deprecated_path) @staticmethod @@ -1988,7 +1988,7 @@ class Transport: @staticmethod def register_link(link): - RNS.log("Registering link "+str(link), RNS.LOG_EXTREME) + RNS.log(f"Registering link {link}", RNS.LOG_EXTREME) if link.initiator: Transport.pending_links.append(link) else: @@ -1996,10 +1996,10 @@ class Transport: @staticmethod def activate_link(link): - RNS.log("Activating link "+str(link), RNS.LOG_EXTREME) + RNS.log(f"Activating link {link}", RNS.LOG_EXTREME) if link in Transport.pending_links: if link.status != RNS.Link.ACTIVE: - raise IOError("Invalid link state for link activation: "+str(link.status)) + raise OSError(f"Invalid link state for link activation: {link.status}") Transport.pending_links.remove(link) Transport.active_links.append(link) link.status = RNS.Link.ACTIVE @@ -2061,18 +2061,18 @@ class Transport: if packet.receiving_interface != None: interface_reference = str(packet.receiving_interface) - file = open(RNS.Reticulum.cachepath+"/"+packet_hash, "wb") + file = open(f"{RNS.Reticulum.cachepath}/{packet_hash}", "wb") file.write(umsgpack.packb([packet.raw, interface_reference])) file.close() except Exception as e: - RNS.log("Error writing packet to cache. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error writing packet to cache. The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def get_cached_packet(packet_hash): try: packet_hash = RNS.hexrep(packet_hash, delimit=False) - path = RNS.Reticulum.cachepath+"/"+packet_hash + path = f"{RNS.Reticulum.cachepath}/{packet_hash}" if os.path.isfile(path): file = open(path, "rb") @@ -2091,7 +2091,7 @@ class Transport: return None except Exception as e: RNS.log("Exception occurred while getting cached packet.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def cache_request_packet(packet): @@ -2281,12 +2281,12 @@ class Transport: queued_announces = True if len(on_interface.announce_queue) > 0 else False if queued_announces: - RNS.log("Blocking recursive path request on "+str(on_interface)+" due to queued announces", RNS.LOG_EXTREME) + RNS.log(f"Blocking recursive path request on {on_interface} due to queued announces", RNS.LOG_EXTREME) return else: now = time.time() if now < on_interface.announce_allowed_at: - RNS.log("Blocking recursive path request on "+str(on_interface)+" due to active announce cap", RNS.LOG_EXTREME) + RNS.log(f"Blocking recursive path request on {on_interface} due to active announce cap", RNS.LOG_EXTREME) return else: tx_time = ((len(path_request_data)+RNS.Reticulum.HEADER_MINSIZE)*8) / on_interface.bitrate @@ -2310,8 +2310,8 @@ class Transport: return response except Exception as e: - RNS.log("An error occurred while processing remote status request from "+str(remote_identity), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while processing remote status request from {remote_identity}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) return None @@ -2346,8 +2346,8 @@ class Transport: return response except Exception as e: - RNS.log("An error occurred while processing remote status request from "+str(remote_identity), RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while processing remote status request from {remote_identity}", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) return None @@ -2393,13 +2393,13 @@ class Transport: ) else: - RNS.log("Ignoring duplicate path request for "+RNS.prettyhexrep(destination_hash)+" with tag "+RNS.prettyhexrep(unique_tag), RNS.LOG_DEBUG) + RNS.log(f"Ignoring duplicate path request for {RNS.prettyhexrep(destination_hash)} with tag {RNS.prettyhexrep(unique_tag)}", RNS.LOG_DEBUG) else: - RNS.log("Ignoring tagless path request for "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG) + RNS.log(f"Ignoring tagless path request for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Error while handling path request. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while handling path request. The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def path_request(destination_hash, is_from_local_client, attached_interface, requestor_transport_id=None, tag=None): @@ -2409,11 +2409,11 @@ class Transport: if RNS.Reticulum.transport_enabled() and attached_interface.mode in RNS.Interfaces.Interface.Interface.DISCOVER_PATHS_FOR: should_search_for_unknown = True - interface_str = " on "+str(attached_interface) + interface_str = f" on {attached_interface}" else: interface_str = "" - RNS.log("Path request for "+RNS.prettyhexrep(destination_hash)+interface_str, RNS.LOG_DEBUG) + RNS.log(f"Path request for {RNS.prettyhexrep(destination_hash)}{interface_str}", RNS.LOG_DEBUG) destination_exists_on_local_client = False if len(Transport.local_client_interfaces) > 0: @@ -2427,7 +2427,7 @@ class Transport: local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None) if local_destination != None: local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface) - RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", destination is local to this system", RNS.LOG_DEBUG) + RNS.log(f"Answering path request for {RNS.prettyhexrep(destination_hash)}{interface_str}, destination is local to this system", RNS.LOG_DEBUG) elif (RNS.Reticulum.transport_enabled() or is_from_local_client) and (destination_hash in Transport.destination_table): packet = Transport.destination_table[destination_hash][6] @@ -2445,9 +2445,9 @@ class Transport: # inefficient. There is probably a better way. Doing # path invalidation here would decrease the network # convergence time. Maybe just drop it? - RNS.log("Not answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", since next hop is the requestor", RNS.LOG_DEBUG) + RNS.log(f"Not answering path request for {RNS.prettyhexrep(destination_hash)}{interface_str}, since next hop is the requestor", RNS.LOG_DEBUG) else: - RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", path is known", RNS.LOG_DEBUG) + RNS.log(f"Answering path request for {RNS.prettyhexrep(destination_hash)}{interface_str}, path is known", RNS.LOG_DEBUG) now = time.time() retries = Transport.PATHFINDER_R @@ -2459,7 +2459,7 @@ class Transport: retransmit_timeout = now else: if Transport.is_local_client_interface(Transport.next_hop_interface(destination_hash)): - RNS.log("Path request destination "+RNS.prettyhexrep(destination_hash)+" is on a local client interface, rebroadcasting immediately", RNS.LOG_EXTREME) + RNS.log(f"Path request destination {RNS.prettyhexrep(destination_hash)} is on a local client interface, rebroadcasting immediately", RNS.LOG_EXTREME) retransmit_timeout = now else: @@ -2486,7 +2486,7 @@ class Transport: elif is_from_local_client: # Forward path request on all interfaces # except the local client - RNS.log("Forwarding path request from local client for "+RNS.prettyhexrep(destination_hash)+interface_str+" to all other interfaces", RNS.LOG_DEBUG) + RNS.log(f"Forwarding path request from local client for {RNS.prettyhexrep(destination_hash)}{interface_str} to all other interfaces", RNS.LOG_DEBUG) request_tag = RNS.Identity.get_random_hash() for interface in Transport.interfaces: if not interface == attached_interface: @@ -2494,11 +2494,11 @@ class Transport: elif should_search_for_unknown: if destination_hash in Transport.discovery_path_requests: - RNS.log("There is already a waiting path request for "+RNS.prettyhexrep(destination_hash)+" on behalf of path request"+interface_str, RNS.LOG_DEBUG) + RNS.log(f"There is already a waiting path request for {RNS.prettyhexrep(destination_hash)} on behalf of path request{interface_str}", RNS.LOG_DEBUG) else: # Forward path request on all interfaces # except the requestor interface - RNS.log("Attempting to discover unknown path to "+RNS.prettyhexrep(destination_hash)+" on behalf of path request"+interface_str, RNS.LOG_DEBUG) + RNS.log(f"Attempting to discover unknown path to {RNS.prettyhexrep(destination_hash)} on behalf of path request{interface_str}", RNS.LOG_DEBUG) pr_entry = { "destination_hash": destination_hash, "timeout": time.time()+Transport.PATH_REQUEST_TIMEOUT, "requesting_interface": attached_interface } Transport.discovery_path_requests[destination_hash] = pr_entry @@ -2511,12 +2511,12 @@ class Transport: elif not is_from_local_client and len(Transport.local_client_interfaces) > 0: # Forward the path request on all local # client interfaces - RNS.log("Forwarding path request for "+RNS.prettyhexrep(destination_hash)+interface_str+" to local clients", RNS.LOG_DEBUG) + RNS.log(f"Forwarding path request for {RNS.prettyhexrep(destination_hash)}{interface_str} to local clients", RNS.LOG_DEBUG) for interface in Transport.local_client_interfaces: Transport.request_path(destination_hash, on_interface=interface) else: - RNS.log("Ignoring path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", no path known", RNS.LOG_DEBUG) + RNS.log(f"Ignoring path request for {RNS.prettyhexrep(destination_hash)}{interface_str}, no path known", RNS.LOG_DEBUG) @staticmethod def from_local_client(packet): @@ -2568,7 +2568,7 @@ class Transport: try: interface.detach() except Exception as e: - RNS.log("An error occurred while detaching "+str(interface)+". The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error occurred while detaching {interface}. The contained exception was: {e}", RNS.LOG_ERROR) @staticmethod def shared_connection_disappeared(): @@ -2604,10 +2604,10 @@ class Transport: if na == 1: na_str = "1 announce" else: - na_str = str(na)+" announces" + na_str = f"{na} announces" interface.announce_queue = [] - RNS.log("Dropped "+na_str+" on "+str(interface), RNS.LOG_VERBOSE) + RNS.log(f"Dropped {na_str} on {interface}", RNS.LOG_VERBOSE) @staticmethod @@ -2640,20 +2640,20 @@ class Transport: else: RNS.log("Saving packet hashlist to storage...", RNS.LOG_DEBUG) - packet_hashlist_path = RNS.Reticulum.storagepath+"/packet_hashlist" + packet_hashlist_path = f"{RNS.Reticulum.storagepath}/packet_hashlist" file = open(packet_hashlist_path, "wb") file.write(umsgpack.packb(Transport.packet_hashlist)) file.close() save_time = time.time() - save_start if save_time < 1: - time_str = str(round(save_time*1000,2))+"ms" + time_str = f"{round(save_time * 1000, 2)}ms" else: - time_str = str(round(save_time,2))+"s" - RNS.log("Saved packet hashlist in "+time_str, RNS.LOG_DEBUG) + time_str = f"{round(save_time, 2)}s" + RNS.log(f"Saved packet hashlist in {time_str}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Could not save packet hashlist to storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not save packet hashlist to storage, the contained exception was: {e}", RNS.LOG_ERROR) Transport.saving_packet_hashlist = False @@ -2710,20 +2710,20 @@ class Transport: Transport.cache(de[6], force_cache=True) - destination_table_path = RNS.Reticulum.storagepath+"/destination_table" + destination_table_path = f"{RNS.Reticulum.storagepath}/destination_table" file = open(destination_table_path, "wb") file.write(umsgpack.packb(serialised_destinations)) file.close() save_time = time.time() - save_start if save_time < 1: - time_str = str(round(save_time*1000,2))+"ms" + time_str = f"{round(save_time * 1000, 2)}ms" else: - time_str = str(round(save_time,2))+"s" - RNS.log("Saved "+str(len(serialised_destinations))+" path table entries in "+time_str, RNS.LOG_DEBUG) + time_str = f"{round(save_time, 2)}s" + RNS.log(f"Saved {len(serialised_destinations)} path table entries in {time_str}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Could not save path table to storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not save path table to storage, the contained exception was: {e}", RNS.LOG_ERROR) Transport.saving_path_table = False @@ -2788,19 +2788,19 @@ class Transport: serialised_tunnel = [tunnel_id, interface_hash, serialised_paths, expires] serialised_tunnels.append(serialised_tunnel) - tunnels_path = RNS.Reticulum.storagepath+"/tunnels" + tunnels_path = f"{RNS.Reticulum.storagepath}/tunnels" file = open(tunnels_path, "wb") file.write(umsgpack.packb(serialised_tunnels)) file.close() save_time = time.time() - save_start if save_time < 1: - time_str = str(round(save_time*1000,2))+"ms" + time_str = f"{round(save_time * 1000, 2)}ms" else: - time_str = str(round(save_time,2))+"s" - RNS.log("Saved "+str(len(serialised_tunnels))+" tunnel table entries in "+time_str, RNS.LOG_DEBUG) + time_str = f"{round(save_time, 2)}s" + RNS.log(f"Saved {len(serialised_tunnels)} tunnel table entries in {time_str}", RNS.LOG_DEBUG) except Exception as e: - RNS.log("Could not save tunnel table to storage, the contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Could not save tunnel table to storage, the contained exception was: {e}", RNS.LOG_ERROR) Transport.saving_tunnel_table = False diff --git a/RNS/Utilities/__init__.py b/RNS/Utilities/__init__.py index be84862..5fd7259 100644 --- a/RNS/Utilities/__init__.py +++ b/RNS/Utilities/__init__.py @@ -23,5 +23,5 @@ import os import glob -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] diff --git a/RNS/Utilities/rncp.py b/RNS/Utilities/rncp.py index e2056db..6ae0045 100644 --- a/RNS/Utilities/rncp.py +++ b/RNS/Utilities/rncp.py @@ -54,9 +54,9 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi if jail != None: fetch_jail = os.path.abspath(os.path.expanduser(jail)) - RNS.log("Restricting fetch requests to paths under \""+fetch_jail+"\"", RNS.LOG_VERBOSE) + RNS.log(f"Restricting fetch requests to paths under \"{fetch_jail}\"", RNS.LOG_VERBOSE) - identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME + identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): identity = RNS.Identity.from_file(identity_path) @@ -68,8 +68,8 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "receive") if display_identity: - print("Identity : "+str(identity)) - print("Listening on : "+RNS.prettyhexrep(destination.hash)) + print(f"Identity : {identity}") + print(f"Listening on : {RNS.prettyhexrep(destination.hash)}") exit(0) if disable_auth: @@ -79,14 +79,14 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi try: allowed_file_name = "allowed_identities" allowed_file = None - if os.path.isfile(os.path.expanduser("/etc/rncp/"+allowed_file_name)): - allowed_file = os.path.expanduser("/etc/rncp/"+allowed_file_name) - elif os.path.isfile(os.path.expanduser("~/.config/rncp/"+allowed_file_name)): - allowed_file = os.path.expanduser("~/.config/rncp/"+allowed_file_name) - elif os.path.isfile(os.path.expanduser("~/.rncp/"+allowed_file_name)): - allowed_file = os.path.expanduser("~/.rncp/"+allowed_file_name) + if os.path.isfile(os.path.expanduser(f"/etc/rncp/{allowed_file_name}")): + allowed_file = os.path.expanduser(f"/etc/rncp/{allowed_file_name}") + elif os.path.isfile(os.path.expanduser(f"~/.config/rncp/{allowed_file_name}")): + allowed_file = os.path.expanduser(f"~/.config/rncp/{allowed_file_name}") + elif os.path.isfile(os.path.expanduser(f"~/.rncp/{allowed_file_name}")): + allowed_file = os.path.expanduser(f"~/.rncp/{allowed_file_name}") if allowed_file != None: - af = open(allowed_file, "r") + af = open(allowed_file) al = af.read().replace("\r", "").split("\n") ali = [] for a in al: @@ -103,16 +103,16 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi else: ms = "ies" - RNS.log("Loaded "+str(len(ali))+" allowed identit"+ms+" from "+str(allowed_file), RNS.LOG_VERBOSE) + RNS.log(f"Loaded {len(ali)} allowed identit{ms} from {allowed_file}", RNS.LOG_VERBOSE) except Exception as e: - RNS.log("Error while parsing allowed_identities file. The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"Error while parsing allowed_identities file. The contained exception was: {e}", RNS.LOG_ERROR) if allowed != None: for a in allowed: try: if len(a) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(a) allowed_identity_hashes.append(destination_hash) @@ -141,11 +141,11 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi target_link = link if not os.path.isfile(file_path): - RNS.log("Client-requested file not found: "+str(file_path), RNS.LOG_VERBOSE) + RNS.log(f"Client-requested file not found: {file_path}", RNS.LOG_VERBOSE) return False else: if target_link != None: - RNS.log("Sending file "+str(file_path)+" to client", RNS.LOG_VERBOSE) + RNS.log(f"Sending file {file_path} to client", RNS.LOG_VERBOSE) temp_file = TemporaryFile() real_file = open(file_path, "rb") @@ -169,7 +169,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi destination.set_link_established_callback(client_link_established) destination.register_request_handler("fetch_file", response_generator=fetch_request, allow=RNS.Destination.ALLOW_LIST, allowed_list=allowed_identity_hashes) - print("rncp listening on "+RNS.prettyhexrep(destination.hash)) + print(f"rncp listening on {RNS.prettyhexrep(destination.hash)}") if announce >= 0: def job(): @@ -220,15 +220,15 @@ def receive_resource_callback(resource): def receive_resource_started(resource): if resource.link.get_remote_identity(): - id_str = " from "+RNS.prettyhexrep(resource.link.get_remote_identity().hash) + id_str = f" from {RNS.prettyhexrep(resource.link.get_remote_identity().hash)}" else: id_str = "" - print("Starting resource transfer "+RNS.prettyhexrep(resource.hash)+id_str) + print(f"Starting resource transfer {RNS.prettyhexrep(resource.hash)}{id_str}") def receive_resource_concluded(resource): if resource.status == RNS.Resource.COMPLETE: - print(str(resource)+" completed") + print(f"{resource} completed") if resource.total_size > 4: filename_len = int.from_bytes(resource.data.read(2), "big") @@ -238,7 +238,7 @@ def receive_resource_concluded(resource): saved_filename = filename while os.path.isfile(saved_filename): counter += 1 - saved_filename = filename+"."+str(counter) + saved_filename = f"{filename}.{counter}" file = open(saved_filename, "wb") file.write(resource.data.read()) @@ -285,7 +285,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination) except Exception as e: @@ -296,11 +296,11 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel) - identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME + identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): identity = RNS.Identity.from_file(identity_path) if identity == None: - RNS.log("Could not load identity for rncp. The identity file at \""+str(identity_path)+"\" may be corrupt or unreadable.", RNS.LOG_ERROR) + RNS.log(f"Could not load identity for rncp. The identity file at \"{identity_path}\" may be corrupt or unreadable.", RNS.LOG_ERROR) exit(2) else: identity = None @@ -313,9 +313,9 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No if not RNS.Transport.has_path(destination_hash): RNS.Transport.request_path(destination_hash) if silent: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested") else: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=" ") sys.stdout.flush() i = 0 @@ -324,7 +324,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) @@ -336,9 +336,9 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No exit(1) else: if silent: - print("Establishing link with "+RNS.prettyhexrep(destination_hash)) + print(f"Establishing link with {RNS.prettyhexrep(destination_hash)}") else: - print("\r \rEstablishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=" ") + print(f'\r \rEstablishing link with {RNS.prettyhexrep(destination_hash)} ', end=" ") listener_identity = RNS.Identity.recall(destination_hash) listener_destination = RNS.Destination( @@ -353,15 +353,15 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) if not RNS.Transport.has_path(destination_hash): if silent: - print("Could not establish link with "+RNS.prettyhexrep(destination_hash)) + print(f"Could not establish link with {RNS.prettyhexrep(destination_hash)}") else: - print("\r \rCould not establish link with "+RNS.prettyhexrep(destination_hash)) + print(f'\r \rCould not establish link with {RNS.prettyhexrep(destination_hash)}') exit(1) else: if silent: @@ -411,7 +411,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No saved_filename = filename while os.path.isfile(saved_filename): counter += 1 - saved_filename = filename+"."+str(counter) + saved_filename = f"{filename}.{counter}" file = open(saved_filename, "wb") file.write(resource.data.read()) @@ -437,19 +437,19 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No while not request_resolved: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) if request_status == "fetch_not_allowed": if not silent: print("\r \r", end="") - print("Fetch request failed, fetching the file "+str(file)+" was not allowed by the remote") + print(f"Fetch request failed, fetching the file {file} was not allowed by the remote") link.teardown() time.sleep(0.15) exit(0) elif request_status == "not_found": if not silent: print("\r \r", end="") - print("Fetch request failed, the file "+str(file)+" was not found on the remote") + print(f"Fetch request failed, the file {file} was not found on the remote") link.teardown() time.sleep(0.15) exit(0) @@ -474,13 +474,13 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No if current_resource: prg = current_resource.get_progress() percent = round(prg * 100.0, 1) - stat_str = str(percent)+"% - " + size_str(int(prg*current_resource.total_size)) + " of " + size_str(current_resource.total_size) + " - " +size_str(speed, "b")+"ps" + stat_str = f"{percent}% - {size_str(int(prg * current_resource.total_size))} of {size_str(current_resource.total_size)} - {size_str(speed, 'b')}ps" if prg != 1.0: - print("\r \rTransferring file "+syms[i]+" "+stat_str, end=" ") + print(f'\r \rTransferring file {syms[i]} {stat_str}', end=" ") else: - print("\r \rTransfer complete "+stat_str, end=" ") + print(f'\r \rTransfer complete {stat_str}', end=" ") else: - print("\r \rWaiting for transfer to start "+syms[i]+" ", end=" ") + print(f'\r \rWaiting for transfer to start {syms[i]} ', end=" ") sys.stdout.flush() i = (i+1)%len(syms) @@ -492,10 +492,10 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No exit(1) else: if silent: - print(str(file)+" fetched from "+RNS.prettyhexrep(destination_hash)) + print(f"{file} fetched from {RNS.prettyhexrep(destination_hash)}") else: #print("\r \r"+str(file)+" fetched from "+RNS.prettyhexrep(destination_hash)) - print("\n"+str(file)+" fetched from "+RNS.prettyhexrep(destination_hash)) + print(f"\n{file} fetched from {RNS.prettyhexrep(destination_hash)}") link.teardown() time.sleep(0.15) exit(0) @@ -512,7 +512,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination) except Exception as e: @@ -547,11 +547,11 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel) - identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME + identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): identity = RNS.Identity.from_file(identity_path) if identity == None: - RNS.log("Could not load identity for rncp. The identity file at \""+str(identity_path)+"\" may be corrupt or unreadable.", RNS.LOG_ERROR) + RNS.log(f"Could not load identity for rncp. The identity file at \"{identity_path}\" may be corrupt or unreadable.", RNS.LOG_ERROR) exit(2) else: identity = None @@ -564,9 +564,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non if not RNS.Transport.has_path(destination_hash): RNS.Transport.request_path(destination_hash) if silent: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested") else: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=" ") sys.stdout.flush() i = 0 @@ -575,7 +575,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) @@ -587,9 +587,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non exit(1) else: if silent: - print("Establishing link with "+RNS.prettyhexrep(destination_hash)) + print(f"Establishing link with {RNS.prettyhexrep(destination_hash)}") else: - print("\r \rEstablishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=" ") + print(f'\r \rEstablishing link with {RNS.prettyhexrep(destination_hash)} ', end=" ") receiver_identity = RNS.Identity.recall(destination_hash) receiver_destination = RNS.Destination( @@ -604,21 +604,21 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) if time.time() > estab_timeout: if silent: - print("Link establishment with "+RNS.prettyhexrep(destination_hash)+" timed out") + print(f"Link establishment with {RNS.prettyhexrep(destination_hash)} timed out") else: - print("\r \rLink establishment with "+RNS.prettyhexrep(destination_hash)+" timed out") + print(f'\r \rLink establishment with {RNS.prettyhexrep(destination_hash)} timed out') exit(1) elif not RNS.Transport.has_path(destination_hash): if silent: - print("No path found to "+RNS.prettyhexrep(destination_hash)) + print(f"No path found to {RNS.prettyhexrep(destination_hash)}") else: - print("\r \rNo path found to "+RNS.prettyhexrep(destination_hash)) + print(f'\r \rNo path found to {RNS.prettyhexrep(destination_hash)}') exit(1) else: if silent: @@ -633,16 +633,16 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non while resource.status < RNS.Resource.TRANSFERRING: if not silent: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) if resource.status > RNS.Resource.COMPLETE: if silent: - print("File was not accepted by "+RNS.prettyhexrep(destination_hash)) + print(f"File was not accepted by {RNS.prettyhexrep(destination_hash)}") else: - print("\r \rFile was not accepted by "+RNS.prettyhexrep(destination_hash)) + print(f'\r \rFile was not accepted by {RNS.prettyhexrep(destination_hash)}') exit(1) else: if silent: @@ -654,11 +654,11 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non time.sleep(0.1) prg = current_resource.get_progress() percent = round(prg * 100.0, 1) - stat_str = str(percent)+"% - " + size_str(int(prg*current_resource.total_size)) + " of " + size_str(current_resource.total_size) + " - " +size_str(speed, "b")+"ps" + stat_str = f"{percent}% - {size_str(int(prg * current_resource.total_size))} of {size_str(current_resource.total_size)} - {size_str(speed, 'b')}ps" if not done: - print("\r \rTransferring file "+syms[i]+" "+stat_str, end=" ") + print(f'\r \rTransferring file {syms[i]} {stat_str}', end=" ") else: - print("\r \rTransfer complete "+stat_str, end=" ") + print(f'\r \rTransfer complete {stat_str}', end=" ") sys.stdout.flush() i = (i+1)%len(syms) return i @@ -678,10 +678,10 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non exit(1) else: if silent: - print(str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash)) + print(f"{file_path} copied to {RNS.prettyhexrep(destination_hash)}") else: # print("\r \r"+str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash)) - print("\n"+str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash)) + print(f"\n{file_path} copied to {RNS.prettyhexrep(destination_hash)}") link.teardown() time.sleep(0.25) real_file.close() @@ -707,7 +707,7 @@ def main(): parser.add_argument('-p', '--print-identity', action='store_true', default=False, help="print identity and destination info and exit") parser.add_argument("-w", action="store", metavar="seconds", type=float, help="sender timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT) # parser.add_argument("--limit", action="store", metavar="files", type=float, help="maximum number of files to accept", default=None) - parser.add_argument("--version", action="version", version="rncp {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rncp {__version__}") args = parser.parse_args() @@ -777,12 +777,12 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" if __name__ == "__main__": main() diff --git a/RNS/Utilities/rnid.py b/RNS/Utilities/rnid.py index 97de3e0..211f81b 100644 --- a/RNS/Utilities/rnid.py +++ b/RNS/Utilities/rnid.py @@ -43,14 +43,14 @@ def spin(until=None, msg=None, timeout=None): if timeout != None: timeout = time.time()+timeout - print(msg+" ", end=" ") + print(f"{msg} ", end=" ") while (timeout == None or time.time() timeout: return False @@ -92,7 +92,7 @@ def main(): parser.add_argument("-b", "--base64", action="store_true", default=False, help="Use base64-encoded input and output") parser.add_argument("-B", "--base32", action="store_true", default=False, help="Use base32-encoded input and output") - parser.add_argument("--version", action="version", version="rnid {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rnid {__version__}") args = parser.parse_args() @@ -124,30 +124,30 @@ def main(): else: identity_bytes = bytes.fromhex(args.import_str) except Exception as e: - print("Invalid identity data specified for import: "+str(e)) + print(f"Invalid identity data specified for import: {e}") exit(41) try: identity = RNS.Identity.from_bytes(identity_bytes) except Exception as e: - print("Could not create Reticulum identity from specified data: "+str(e)) + print(f"Could not create Reticulum identity from specified data: {e}") exit(42) RNS.log("Identity imported") if args.base64: - RNS.log("Public Key : "+base64.urlsafe_b64encode(identity.get_public_key()).decode("utf-8")) + RNS.log(f"Public Key : {base64.urlsafe_b64encode(identity.get_public_key()).decode('utf-8')}") elif args.base32: - RNS.log("Public Key : "+base64.b32encode(identity.get_public_key()).decode("utf-8")) + RNS.log(f"Public Key : {base64.b32encode(identity.get_public_key()).decode('utf-8')}") else: - RNS.log("Public Key : "+RNS.hexrep(identity.get_public_key(), delimit=False)) + RNS.log(f"Public Key : {RNS.hexrep(identity.get_public_key(), delimit=False)}") if identity.prv: if args.print_private: if args.base64: - RNS.log("Private Key : "+base64.urlsafe_b64encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Private Key : {base64.urlsafe_b64encode(identity.get_private_key()).decode('utf-8')}") elif args.base32: - RNS.log("Private Key : "+base64.b32encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Private Key : {base64.b32encode(identity.get_private_key()).decode('utf-8')}") else: - RNS.log("Private Key : "+RNS.hexrep(identity.get_private_key(), delimit=False)) + RNS.log(f"Private Key : {RNS.hexrep(identity.get_private_key(), delimit=False)}") else: RNS.log("Private Key : Hidden") @@ -156,13 +156,13 @@ def main(): wp = os.path.expanduser(args.write) if not os.path.isfile(wp) or args.force: identity.to_file(wp) - RNS.log("Wrote imported identity to "+str(args.write)) + RNS.log(f"Wrote imported identity to {args.write}") else: - print("File "+str(wp)+" already exists, not overwriting") + print(f"File {wp} already exists, not overwriting") exit(43) except Exception as e: - print("Error while writing imported identity to file: "+str(e)) + print(f"Error while writing imported identity to file: {e}") exit(44) exit(0) @@ -189,16 +189,16 @@ def main(): if args.generate: identity = RNS.Identity() if not args.force and os.path.isfile(args.generate): - RNS.log("Identity file "+str(args.generate)+" already exists. Not overwriting.", RNS.LOG_ERROR) + RNS.log(f"Identity file {args.generate} already exists. Not overwriting.", RNS.LOG_ERROR) exit(3) else: try: identity.to_file(args.generate) - RNS.log("New identity written to "+str(args.generate)) + RNS.log(f"New identity written to {args.generate}") exit(0) except Exception as e: RNS.log("An error ocurred while saving the generated Identity.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(4) identity = None @@ -210,24 +210,24 @@ def main(): if identity == None: if not args.request: - RNS.log("Could not recall Identity for "+RNS.prettyhexrep(destination_hash)+".", RNS.LOG_ERROR) + RNS.log(f"Could not recall Identity for {RNS.prettyhexrep(destination_hash)}.", RNS.LOG_ERROR) RNS.log("You can query the network for unknown Identities with the -R option.", RNS.LOG_ERROR) exit(5) else: RNS.Transport.request_path(destination_hash) def spincheck(): return RNS.Identity.recall(destination_hash) != None - spin(spincheck, "Requesting unknown Identity for "+RNS.prettyhexrep(destination_hash), args.t) + spin(spincheck, f"Requesting unknown Identity for {RNS.prettyhexrep(destination_hash)}", args.t) if not spincheck(): RNS.log("Identity request timed out", RNS.LOG_ERROR) exit(6) else: identity = RNS.Identity.recall(destination_hash) - RNS.log("Received Identity "+str(identity)+" for destination "+RNS.prettyhexrep(destination_hash)+" from the network") + RNS.log(f"Received Identity {identity} for destination {RNS.prettyhexrep(destination_hash)} from the network") else: - RNS.log("Recalled Identity "+str(identity)+" for destination "+RNS.prettyhexrep(destination_hash)) + RNS.log(f"Recalled Identity {identity} for destination {RNS.prettyhexrep(destination_hash)}") except Exception as e: @@ -243,7 +243,7 @@ def main(): else: try: identity = RNS.Identity.from_file(identity_str) - RNS.log("Loaded Identity "+str(identity)+" from "+str(identity_str)) + RNS.log(f"Loaded Identity {identity} from {identity_str}") except Exception as e: RNS.log("Could not decode Identity from specified file") @@ -261,15 +261,15 @@ def main(): aspects = aspects[1:] if identity.pub != None: destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects) - RNS.log("The "+str(args.hash)+" destination for this Identity is "+RNS.prettyhexrep(destination.hash)) - RNS.log("The full destination specifier is "+str(destination)) + RNS.log(f"The {args.hash} destination for this Identity is {RNS.prettyhexrep(destination.hash)}") + RNS.log(f"The full destination specifier is {destination}") time.sleep(0.25) exit(0) else: raise KeyError("No public key known") except Exception as e: RNS.log("An error ocurred while attempting to send the announce.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(0) @@ -284,39 +284,39 @@ def main(): aspects = aspects[1:] if identity.prv != None: destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, app_name, *aspects) - RNS.log("Created destination "+str(destination)) - RNS.log("Announcing destination "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"Created destination {destination}") + RNS.log(f"Announcing destination {RNS.prettyhexrep(destination.hash)}") destination.announce() time.sleep(0.25) exit(0) else: destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects) - RNS.log("The "+str(args.announce)+" destination for this Identity is "+RNS.prettyhexrep(destination.hash)) - RNS.log("The full destination specifier is "+str(destination)) + RNS.log(f"The {args.announce} destination for this Identity is {RNS.prettyhexrep(destination.hash)}") + RNS.log(f"The full destination specifier is {destination}") RNS.log("Cannot announce this destination, since the private key is not held") time.sleep(0.25) exit(33) except Exception as e: RNS.log("An error ocurred while attempting to send the announce.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(0) if args.print_identity: if args.base64: - RNS.log("Public Key : "+base64.urlsafe_b64encode(identity.get_public_key()).decode("utf-8")) + RNS.log(f"Public Key : {base64.urlsafe_b64encode(identity.get_public_key()).decode('utf-8')}") elif args.base32: - RNS.log("Public Key : "+base64.b32encode(identity.get_public_key()).decode("utf-8")) + RNS.log(f"Public Key : {base64.b32encode(identity.get_public_key()).decode('utf-8')}") else: - RNS.log("Public Key : "+RNS.hexrep(identity.get_public_key(), delimit=False)) + RNS.log(f"Public Key : {RNS.hexrep(identity.get_public_key(), delimit=False)}") if identity.prv: if args.print_private: if args.base64: - RNS.log("Private Key : "+base64.urlsafe_b64encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Private Key : {base64.urlsafe_b64encode(identity.get_private_key()).decode('utf-8')}") elif args.base32: - RNS.log("Private Key : "+base64.b32encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Private Key : {base64.b32encode(identity.get_private_key()).decode('utf-8')}") else: - RNS.log("Private Key : "+RNS.hexrep(identity.get_private_key(), delimit=False)) + RNS.log(f"Private Key : {RNS.hexrep(identity.get_private_key(), delimit=False)}") else: RNS.log("Private Key : Hidden") exit(0) @@ -324,11 +324,11 @@ def main(): if args.export: if identity.prv: if args.base64: - RNS.log("Exported Identity : "+base64.urlsafe_b64encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Exported Identity : {base64.urlsafe_b64encode(identity.get_private_key()).decode('utf-8')}") elif args.base32: - RNS.log("Exported Identity : "+base64.b32encode(identity.get_private_key()).decode("utf-8")) + RNS.log(f"Exported Identity : {base64.b32encode(identity.get_private_key()).decode('utf-8')}") else: - RNS.log("Exported Identity : "+RNS.hexrep(identity.get_private_key(), delimit=False)) + RNS.log(f"Exported Identity : {RNS.hexrep(identity.get_private_key(), delimit=False)}") else: RNS.log("Identity doesn't hold a private key, cannot export") exit(50) @@ -336,28 +336,28 @@ def main(): exit(0) if args.validate: - if not args.read and args.validate.lower().endswith("."+SIG_EXT): - args.read = str(args.validate).replace("."+SIG_EXT, "") + if not args.read and args.validate.lower().endswith(f".{SIG_EXT}"): + args.read = str(args.validate).replace(f".{SIG_EXT}", "") if not os.path.isfile(args.validate): - RNS.log("Signature file "+str(args.read)+" not found", RNS.LOG_ERROR) + RNS.log(f"Signature file {args.read} not found", RNS.LOG_ERROR) exit(10) if not os.path.isfile(args.read): - RNS.log("Input file "+str(args.read)+" not found", RNS.LOG_ERROR) + RNS.log(f"Input file {args.read} not found", RNS.LOG_ERROR) exit(11) data_input = None if args.read: if not os.path.isfile(args.read): - RNS.log("Input file "+str(args.read)+" not found", RNS.LOG_ERROR) + RNS.log(f"Input file {args.read} not found", RNS.LOG_ERROR) exit(12) else: try: data_input = open(args.read, "rb") except Exception as e: RNS.log("Could not open input file for reading", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(13) # TODO: Actually expand this to a good solution @@ -368,28 +368,28 @@ def main(): data_output = None if args.encrypt and not args.write and not args.stdout and args.read: - args.write = str(args.read)+"."+ENCRYPT_EXT + args.write = f"{args.read}.{ENCRYPT_EXT}" - if args.decrypt and not args.write and not args.stdout and args.read and args.read.lower().endswith("."+ENCRYPT_EXT): - args.write = str(args.read).replace("."+ENCRYPT_EXT, "") + if args.decrypt and not args.write and not args.stdout and args.read and args.read.lower().endswith(f".{ENCRYPT_EXT}"): + args.write = str(args.read).replace(f".{ENCRYPT_EXT}", "") if args.sign and identity.prv == None: RNS.log("Specified Identity does not hold a private key. Cannot sign.", RNS.LOG_ERROR) exit(14) if args.sign and not args.write and not args.stdout and args.read: - args.write = str(args.read)+"."+SIG_EXT + args.write = f"{args.read}.{SIG_EXT}" if args.write: if not args.force and os.path.isfile(args.write): - RNS.log("Output file "+str(args.write)+" already exists. Not overwriting.", RNS.LOG_ERROR) + RNS.log(f"Output file {args.write} already exists. Not overwriting.", RNS.LOG_ERROR) exit(15) else: try: data_output = open(args.write, "wb") except Exception as e: RNS.log("Could not open output file for writing", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(15) # TODO: Actually expand this to a good solution @@ -414,7 +414,7 @@ def main(): exit(18) if not args.stdout: - RNS.log("Signing "+str(args.read)) + RNS.log(f"Signing {args.read}") try: data_output.write(identity.sign(data_input.read())) @@ -423,13 +423,13 @@ def main(): if not args.stdout: if args.read: - RNS.log("File "+str(args.read)+" signed with "+str(identity)+" to "+str(args.write)) + RNS.log(f"File {args.read} signed with {identity} to {args.write}") exit(0) except Exception as e: if not args.stdout: RNS.log("An error ocurred while encrypting data.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) try: data_output.close() except: @@ -453,8 +453,8 @@ def main(): try: sig_input = open(args.validate, "rb") except Exception as e: - RNS.log("An error ocurred while opening "+str(args.validate)+".", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"An error ocurred while opening {args.validate}.", RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(21) @@ -464,17 +464,17 @@ def main(): if not validated: if not args.stdout: - RNS.log("Signature "+str(args.validate)+" for file "+str(args.read)+" is invalid", RNS.LOG_ERROR) + RNS.log(f"Signature {args.validate} for file {args.read} is invalid", RNS.LOG_ERROR) exit(22) else: if not args.stdout: - RNS.log("Signature "+str(args.validate)+" for file "+str(args.read)+" made by Identity "+str(identity)+" is valid") + RNS.log(f"Signature {args.validate} for file {args.read} made by Identity {identity} is valid") exit(0) except Exception as e: if not args.stdout: RNS.log("An error ocurred while validating signature.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) try: data_output.close() except: @@ -497,7 +497,7 @@ def main(): exit(25) if not args.stdout: - RNS.log("Encrypting "+str(args.read)) + RNS.log(f"Encrypting {args.read}") try: more_data = True @@ -511,13 +511,13 @@ def main(): data_input.close() if not args.stdout: if args.read: - RNS.log("File "+str(args.read)+" encrypted for "+str(identity)+" to "+str(args.write)) + RNS.log(f"File {args.read} encrypted for {identity} to {args.write}") exit(0) except Exception as e: if not args.stdout: RNS.log("An error ocurred while encrypting data.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) try: data_output.close() except: @@ -544,7 +544,7 @@ def main(): exit(29) if not args.stdout: - RNS.log("Decrypting "+str(args.read)+"...") + RNS.log(f"Decrypting {args.read}...") try: more_data = True @@ -564,13 +564,13 @@ def main(): data_input.close() if not args.stdout: if args.read: - RNS.log("File "+str(args.read)+" decrypted with "+str(identity)+" to "+str(args.write)) + RNS.log(f"File {args.read} decrypted with {identity} to {args.write}") exit(0) except Exception as e: if not args.stdout: RNS.log("An error ocurred while decrypting data.", RNS.LOG_ERROR) - RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) + RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) try: data_output.close() except: diff --git a/RNS/Utilities/rnir.py b/RNS/Utilities/rnir.py index 0e4bf9e..01c74da 100644 --- a/RNS/Utilities/rnir.py +++ b/RNS/Utilities/rnir.py @@ -48,7 +48,7 @@ def main(): parser.add_argument('-v', '--verbose', action='count', default=0) parser.add_argument('-q', '--quiet', action='count', default=0) parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit") - parser.add_argument("--version", action="version", version="ir {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"ir {__version__}") args = parser.parse_args() diff --git a/RNS/Utilities/rnodeconf.py b/RNS/Utilities/rnodeconf.py index 7e99c78..fc4601d 100755 --- a/RNS/Utilities/rnodeconf.py +++ b/RNS/Utilities/rnodeconf.py @@ -492,7 +492,7 @@ class RNode(): command_buffer = command_buffer+bytes([byte]) if (len(command_buffer) == 4): self.r_bt_pin = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] - RNS.log("Bluetooth pairing PIN is: {:06d}".format(self.r_bt_pin)) + RNS.log(f"Bluetooth pairing PIN is: {self.r_bt_pin:06d}") elif (command == KISS.CMD_DEV_HASH): if (byte == KISS.FESC): @@ -642,13 +642,13 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND, KISS.CMD_BOARD, 0x00, KISS.FEND, KISS.CMD_DEV_HASH, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x02, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while detecting hardware for "+self(str)) + raise OSError("An IO error occurred while detecting hardware for "+self(str)) def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending host left command to device") + raise OSError("An IO error occurred while sending host left command to device") sleep(1) def set_display_intensity(self, intensity): @@ -656,46 +656,46 @@ class RNode(): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_INT])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending display intensity command to device") + raise OSError("An IO error occurred while sending display intensity command to device") def set_display_blanking(self, blanking_timeout): data = bytes([blanking_timeout & 0xFF]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_BLNK])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending display blanking timeout command to device") + raise OSError("An IO error occurred while sending display blanking timeout command to device") def set_neopixel_intensity(self, intensity): data = bytes([intensity & 0xFF]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_NP_INT])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending NeoPixel intensity command to device") + raise OSError("An IO error occurred while sending NeoPixel intensity command to device") def set_display_address(self, address): data = bytes([address & 0xFF]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_ADR])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending display address command to device") + raise OSError("An IO error occurred while sending display address command to device") def enable_bluetooth(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth enable command to device") + raise OSError("An IO error occurred while sending bluetooth enable command to device") def disable_bluetooth(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth disable command to device") + raise OSError("An IO error occurred while sending bluetooth disable command to device") def bluetooth_pair(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x02, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending bluetooth pair command to device") + raise OSError("An IO error occurred while sending bluetooth pair command to device") def store_signature(self, signature_bytes): data = KISS.escape(signature_bytes) @@ -703,7 +703,7 @@ class RNode(): written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending signature to device") + raise OSError("An IO error occurred while sending signature to device") def set_firmware_hash(self, hash_bytes): data = KISS.escape(hash_bytes) @@ -711,14 +711,14 @@ class RNode(): written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending firmware hash to device") + raise OSError("An IO error occurred while sending firmware hash to device") def indicate_firmware_update(self): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FW_UPD])+bytes([0x01])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while sending firmware update command to device") + raise OSError("An IO error occurred while sending firmware update command to device") def initRadio(self): self.setFrequency() @@ -738,7 +738,7 @@ class RNode(): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring frequency for "+self(str)) + raise OSError("An IO error occurred while configuring frequency for "+self(str)) def setBandwidth(self): c1 = self.bandwidth >> 24 @@ -750,46 +750,46 @@ class RNode(): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring bandwidth for "+self(str)) + raise OSError("An IO error occurred while configuring bandwidth for "+self(str)) def setTXPower(self): txp = bytes([self.txpower]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring TX power for "+self(str)) + raise OSError("An IO error occurred while configuring TX power for "+self(str)) def setSpreadingFactor(self): sf = bytes([self.sf]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring spreading factor for "+self(str)) + raise OSError("An IO error occurred while configuring spreading factor for "+self(str)) def setCodingRate(self): cr = bytes([self.cr]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring coding rate for "+self(str)) + raise OSError("An IO error occurred while configuring coding rate for "+self(str)) def setRadioState(self, state): kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state for "+self(str)) + raise OSError("An IO error occurred while configuring radio state for "+self(str)) def setNormalMode(self): kiss_command = bytes([KISS.FEND, KISS.CMD_CONF_DELETE, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring device mode") + raise OSError("An IO error occurred while configuring device mode") def setTNCMode(self): kiss_command = bytes([KISS.FEND, KISS.CMD_CONF_SAVE, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring device mode") + raise OSError("An IO error occurred while configuring device mode") if self.platform == ROM.PLATFORM_ESP32: self.hard_reset() @@ -798,7 +798,7 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_ROM_WIPE, 0xf8, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while wiping EEPROM") + raise OSError("An IO error occurred while wiping EEPROM") sleep(13); # Due to the current janky emulated EEPROM implementation for the # RAK4631, extra time must be given to allow for writing. @@ -809,7 +809,7 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while restarting device") + raise OSError("An IO error occurred while restarting device") sleep(2); def write_eeprom(self, addr, byte): @@ -818,7 +818,7 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_ROM_WRITE]) + write_payload + bytes([KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while writing EEPROM") + raise OSError("An IO error occurred while writing EEPROM") def download_eeprom(self): @@ -826,7 +826,7 @@ class RNode(): kiss_command = bytes([KISS.FEND, KISS.CMD_ROM_READ, 0x00, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): - raise IOError("An IO error occurred while configuring radio state") + raise OSError("An IO error occurred while configuring radio state") sleep(0.6) if self.eeprom == None: @@ -1031,7 +1031,7 @@ class RNode(): RNS.log("Current firmware version: "+self.version) return True else: - raise IOError("Got invalid response while detecting device") + raise OSError("Got invalid response while detecting device") selected_version = None selected_hash = None @@ -3436,7 +3436,7 @@ def main(): txp_mw = round(pow(10, (rnode.conf_txpower/10)), 3) RNS.log(""); RNS.log("\tDevice mode : TNC") - RNS.log("\t Frequency : "+str((rnode.conf_frequency/1000000.0))+" MHz") + RNS.log("\t Frequency : "+str(rnode.conf_frequency/1000000.0)+" MHz") RNS.log("\t Bandwidth : "+str(rnode.conf_bandwidth/1000.0)+" KHz") RNS.log("\t TX power : "+str(rnode.conf_txpower)+" dBm ("+str(txp_mw)+" mW)") RNS.log("\t Spreading factor : "+str(rnode.conf_sf)) @@ -3500,7 +3500,7 @@ def main(): counter_path = FWD_DIR+"/serial.counter" try: if os.path.isfile(counter_path): - file = open(counter_path, "r") + file = open(counter_path) counter_str = file.read() counter = int(counter_str) file.close() @@ -3933,7 +3933,7 @@ def extract_recovery_esptool(): import base64, gzip recovery_esptool = "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" out = open(RT_PATH, "wb") - out.write("#!/usr/bin/env python3\n\n".encode("utf-8")+gzip.decompress(base64.b64decode(recovery_esptool))) + out.write(b"#!/usr/bin/env python3\n\n"+gzip.decompress(base64.b64decode(recovery_esptool))) out.close() except Exception as e: RNS.log("Error: Could not extract recovery ESP-Tool. The contained exception was:") diff --git a/RNS/Utilities/rnpath.py b/RNS/Utilities/rnpath.py index 5578c70..353d020 100644 --- a/RNS/Utilities/rnpath.py +++ b/RNS/Utilities/rnpath.py @@ -35,7 +35,7 @@ def connect_remote(destination_hash, auth_identity, timeout, no_output = False): global remote_link, reticulum if not RNS.Transport.has_path(destination_hash): if not no_output: - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested", end=" ") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested", end=" ") sys.stdout.flush() RNS.Transport.request_path(destination_hash) pr_time = time.time() @@ -88,7 +88,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(remote) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: identity_hash = bytes.fromhex(remote) remote_hash = RNS.Destination.hash_from_name_and_identity("rnstransport.remote.management", identity_hash) @@ -97,7 +97,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, identity = RNS.Identity.from_file(os.path.expanduser(management_identity)) if identity == None: - raise ValueError("Could not load management identity from "+str(management_identity)) + raise ValueError(f"Could not load management identity from {management_identity}") try: connect_remote(remote_hash, identity, remote_timeout, no_output) @@ -118,7 +118,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -166,7 +166,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, m_str = " " else: m_str = "s" - print(RNS.prettyhexrep(path["hash"])+" is "+str(path["hops"])+" hop"+m_str+" away via "+RNS.prettyhexrep(path["via"])+" on "+path["interface"]+" expires "+RNS.timestamp_str(path["expires"])) + print(f"{RNS.prettyhexrep(path['hash'])} is {path['hops']} hop{m_str} away via {RNS.prettyhexrep(path['via'])} on {path['interface']} expires {RNS.timestamp_str(path['expires'])}") if destination_hash != None and displayed == 0: print("No path known") @@ -178,7 +178,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -242,21 +242,21 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, else: s_str = "s" - rv_str = ", "+str(entry["rate_violations"])+" active rate violation"+s_str + rv_str = f", {entry['rate_violations']} active rate violation{s_str}" else: rv_str = "" if entry["blocked_until"] > time.time(): bli = time.time()-(int(entry["blocked_until"])-time.time()) - bl_str = ", new announces allowed in "+pretty_date(int(bli)) + bl_str = f", new announces allowed in {pretty_date(int(bli))}" else: bl_str = "" - print(RNS.prettyhexrep(entry["hash"])+" last heard "+last_str+" ago, "+str(hour_rate)+" announces/hour in the last "+span_str+rv_str+bl_str) + print(f"{RNS.prettyhexrep(entry['hash'])} last heard {last_str} ago, {hour_rate} announces/hour in the last {span_str}{rv_str}{bl_str}") except Exception as e: - print("Error while processing entry for "+RNS.prettyhexrep(entry["hash"])) + print(f"Error while processing entry for {RNS.prettyhexrep(entry['hash'])}") print(str(e)) if destination_hash != None and displayed == 0: @@ -283,7 +283,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -293,9 +293,9 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, sys.exit(1) if reticulum.drop_path(destination_hash): - print("Dropped path to "+RNS.prettyhexrep(destination_hash)) + print(f"Dropped path to {RNS.prettyhexrep(destination_hash)}") else: - print("Unable to drop path to "+RNS.prettyhexrep(destination_hash)+". Does it exist?") + print(f"Unable to drop path to {RNS.prettyhexrep(destination_hash)}. Does it exist?") sys.exit(1) elif drop_via: @@ -308,7 +308,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -318,9 +318,9 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, sys.exit(1) if reticulum.drop_all_via(destination_hash): - print("Dropped all paths via "+RNS.prettyhexrep(destination_hash)) + print(f"Dropped all paths via {RNS.prettyhexrep(destination_hash)}") else: - print("Unable to drop paths via "+RNS.prettyhexrep(destination_hash)+". Does the transport instance exist?") + print(f"Unable to drop paths via {RNS.prettyhexrep(destination_hash)}. Does the transport instance exist?") sys.exit(1) else: @@ -333,7 +333,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination_hexhash) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination_hexhash) except Exception as e: @@ -344,7 +344,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, if not RNS.Transport.has_path(destination_hash): RNS.Transport.request_path(destination_hash) - print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ") + print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=" ") sys.stdout.flush() i = 0 @@ -352,7 +352,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, limit = time.time()+timeout while not RNS.Transport.has_path(destination_hash) and time.time() _timeout: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) @@ -107,7 +107,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v probe = RNS.Packet(request_destination, os.urandom(size)) probe.pack() except OSError: - print("Error: Probe packet size of "+str(len(probe.raw))+" bytes exceed MTU of "+str(RNS.Reticulum.MTU)+" bytes") + print(f"Error: Probe packet size of {len(probe.raw)} bytes exceed MTU of {RNS.Reticulum.MTU} bytes") exit(3) receipt = probe.send() @@ -115,19 +115,19 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v if more_output: nhd = reticulum.get_next_hop(destination_hash) - via_str = " via "+RNS.prettyhexrep(nhd) if nhd != None else "" - if_str = " on "+str(reticulum.get_next_hop_if_name(destination_hash)) if reticulum.get_next_hop_if_name(destination_hash) != "None" else "" + via_str = f" via {RNS.prettyhexrep(nhd)}" if nhd != None else "" + if_str = f" on {reticulum.get_next_hop_if_name(destination_hash)}" if reticulum.get_next_hop_if_name(destination_hash) != "None" else "" more = via_str+if_str else: more = "" - print("\rSent probe "+str(sent)+" ("+str(size)+" bytes) to "+RNS.prettyhexrep(destination_hash)+more+" ", end=" ") + print(f'\rSent probe {sent} ({size} bytes) to {RNS.prettyhexrep(destination_hash)}{more} ', end=" ") _timeout = time.time() + (timeout or DEFAULT_TIMEOUT+reticulum.get_first_hop_timeout(destination_hash)) i = 0 while receipt.status == RNS.PacketReceipt.SENT and not time.time() > _timeout: time.sleep(0.1) - print(("\b\b"+syms[i]+" "), end="") + print(f"\b\b{syms[i]} ", end="") sys.stdout.flush() i = (i+1)%len(syms) @@ -149,10 +149,10 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v rtt = receipt.get_rtt() if (rtt >= 1): rtt = round(rtt, 3) - rttstring = str(rtt)+" seconds" + rttstring = f"{rtt} seconds" else: rtt = round(rtt*1000, 3) - rttstring = str(rtt)+" milliseconds" + rttstring = f"{rtt} milliseconds" reception_stats = "" if reticulum.is_connected_to_shared_instance: @@ -161,28 +161,24 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v reception_q = reticulum.get_packet_q(receipt.proof_packet.packet_hash) if reception_rssi != None: - reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" + reception_stats += f" [RSSI {reception_rssi} dBm]" if reception_snr != None: - reception_stats += " [SNR "+str(reception_snr)+" dB]" + reception_stats += f" [SNR {reception_snr} dB]" if reception_q != None: - reception_stats += " [Link Quality "+str(reception_q)+"%]" + reception_stats += f" [Link Quality {reception_q}%]" else: if receipt.proof_packet != None: if receipt.proof_packet.rssi != None: - reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]" + reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" if receipt.proof_packet.snr != None: - reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dB]" + reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" print( - "Valid reply from "+ - RNS.prettyhexrep(receipt.destination.hash)+ - "\nRound-trip time is "+rttstring+ - " over "+str(hops)+" hop"+ms+ - reception_stats+"\n" + f"Valid reply from {RNS.prettyhexrep(receipt.destination.hash)}\nRound-trip time is {rttstring} over {hops} hop{ms}{reception_stats}\n" ) else: @@ -207,7 +203,7 @@ def main(): parser.add_argument("-n", "--probes", action="store", default=1, help="number of probes to send", type=int) parser.add_argument("-t", "--timeout", metavar="seconds", action="store", default=None, help="timeout before giving up", type=float) parser.add_argument("-w", "--wait", metavar="seconds", action="store", default=0, help="time between each probe", type=float) - parser.add_argument("--version", action="version", version="rnprobe {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rnprobe {__version__}") parser.add_argument("full_name", nargs="?", default=None, help="full destination name in dotted notation", type=str) parser.add_argument("destination_hash", nargs="?", default=None, help="hexadecimal hash of the destination", type=str) diff --git a/RNS/Utilities/rnsd.py b/RNS/Utilities/rnsd.py index 6a46e1c..6c75e41 100755 --- a/RNS/Utilities/rnsd.py +++ b/RNS/Utilities/rnsd.py @@ -40,9 +40,9 @@ def program_setup(configdir, verbosity = 0, quietness = 0, service = False): reticulum = RNS.Reticulum(configdir=configdir, verbosity=targetverbosity, logdest=targetlogdest) if reticulum.is_connected_to_shared_instance: - RNS.log("Started rnsd version {version} connected to another shared local instance, this is probably NOT what you want!".format(version=__version__), RNS.LOG_WARNING) + RNS.log(f"Started rnsd version {__version__} connected to another shared local instance, this is probably NOT what you want!", RNS.LOG_WARNING) else: - RNS.log("Started rnsd version {version}".format(version=__version__), RNS.LOG_NOTICE) + RNS.log(f"Started rnsd version {__version__}", RNS.LOG_NOTICE) while True: time.sleep(1) @@ -55,7 +55,7 @@ def main(): parser.add_argument('-q', '--quiet', action='count', default=0) parser.add_argument('-s', '--service', action='store_true', default=False, help="rnsd is running as a service and should log to file") parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit") - parser.add_argument("--version", action="version", version="rnsd {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rnsd {__version__}") args = parser.parse_args() diff --git a/RNS/Utilities/rnstatus.py b/RNS/Utilities/rnstatus.py index 8a8d10b..a65fba8 100644 --- a/RNS/Utilities/rnstatus.py +++ b/RNS/Utilities/rnstatus.py @@ -42,12 +42,12 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" request_result = None request_concluded = False @@ -144,7 +144,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(remote) != dest_len: - raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: identity_hash = bytes.fromhex(remote) destination_hash = RNS.Destination.hash_from_name_and_identity("rnstransport.remote.management", identity_hash) @@ -281,13 +281,13 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= if "ifac_netname" in ifstat and ifstat["ifac_netname"] != None: print(" Network : {nn}".format(nn=ifstat["ifac_netname"])) - print(" Status : {ss}".format(ss=ss)) + print(f" Status : {ss}") if clients != None and clients_string != "": print(" "+clients_string) if not (name.startswith("Shared Instance[") or name.startswith("TCPInterface[Client") or name.startswith("LocalInterface[")): - print(" Mode : {mode}".format(mode=modestr)) + print(f" Mode : {modestr}") if "bitrate" in ifstat and ifstat["bitrate"] != None: print(" Rate : {ss}".format(ss=speed_str(ifstat["bitrate"]))) @@ -295,7 +295,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= if "battery_percent" in ifstat and ifstat["battery_percent"] != None: try: bpi = int(ifstat["battery_percent"]) - print(" Battery : {bp}%".format(bp=bpi)) + print(f" Battery : {bpi}%") except: pass @@ -488,10 +488,10 @@ def speed_str(num, suffix='bps'): for unit in units: if abs(num) < 1000.0: - return "%3.2f %s%s" % (num, unit, suffix) + return f"{num:3.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f %s%s" % (num, last_unit, suffix) + return f"{num:.2f} {last_unit}{suffix}" if __name__ == "__main__": main() diff --git a/RNS/Utilities/rnx.py b/RNS/Utilities/rnx.py index 77e823d..5a78d2c 100644 --- a/RNS/Utilities/rnx.py +++ b/RNS/Utilities/rnx.py @@ -42,7 +42,7 @@ allowed_identity_hashes = [] def prepare_identity(identity_path): global identity if identity_path == None: - identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME + identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): identity = RNS.Identity.from_file(identity_path) @@ -62,8 +62,8 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "execute") if print_identity: - print("Identity : "+str(identity)) - print("Listening on : "+RNS.prettyhexrep(destination.hash)) + print(f"Identity : {identity}") + print(f"Listening on : {RNS.prettyhexrep(destination.hash)}") exit(0) if disable_auth: @@ -74,7 +74,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(a) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(a) allowed_identity_hashes.append(destination_hash) @@ -103,7 +103,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed allow = RNS.Destination.ALLOW_ALL, ) - RNS.log("rnx listening for commands on "+RNS.prettyhexrep(destination.hash)) + RNS.log(f"rnx listening for commands on {RNS.prettyhexrep(destination.hash)}") if not disable_announce: destination.announce() @@ -114,16 +114,16 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed def command_link_established(link): link.set_remote_identified_callback(initiator_identified) link.set_link_closed_callback(command_link_closed) - RNS.log("Command link "+str(link)+" established") + RNS.log(f"Command link {link} established") def command_link_closed(link): - RNS.log("Command link "+str(link)+" closed") + RNS.log(f"Command link {link} closed") def initiator_identified(link, identity): global allow_all - RNS.log("Initiator of link "+str(link)+" identified as "+RNS.prettyhexrep(identity.hash)) + RNS.log(f"Initiator of link {link} identified as {RNS.prettyhexrep(identity.hash)}") if not allow_all and not identity.hash in allowed_identity_hashes: - RNS.log("Identity "+RNS.prettyhexrep(identity.hash)+" not allowed, tearing down link") + RNS.log(f"Identity {RNS.prettyhexrep(identity.hash)} not allowed, tearing down link") link.teardown() def execute_received_command(path, data, request_id, remote_identity, requested_at): @@ -134,9 +134,9 @@ def execute_received_command(path, data, request_id, remote_identity, requested_ stdin = data[4] # Data passed to stdin if remote_identity != None: - RNS.log("Executing command ["+command+"] for "+RNS.prettyhexrep(remote_identity.hash)) + RNS.log(f"Executing command [{command}] for {RNS.prettyhexrep(remote_identity.hash)}") else: - RNS.log("Executing command ["+command+"] for unknown requestor") + RNS.log(f"Executing command [{command}] for unknown requestor") result = [ False, # 0: Command was executed @@ -178,7 +178,7 @@ def execute_received_command(path, data, request_id, remote_identity, requested_ pass if timeout != None and time.time() > result[6]+timeout: - RNS.log("Command ["+command+"] timed out and is being killed...") + RNS.log(f"Command [{command}] timed out and is being killed...") process.terminate() process.wait() if process.poll() != None: @@ -219,9 +219,9 @@ def execute_received_command(path, data, request_id, remote_identity, requested_ return result if remote_identity != None: - RNS.log("Delivering result of command ["+str(command)+"] to "+RNS.prettyhexrep(remote_identity.hash)) + RNS.log(f"Delivering result of command [{command}] to {RNS.prettyhexrep(remote_identity.hash)}") else: - RNS.log("Delivering result of command ["+str(command)+"] to unknown requestor") + RNS.log(f"Delivering result of command [{command}] to unknown requestor") return result @@ -231,14 +231,14 @@ def spin(until=None, msg=None, timeout=None): if timeout != None: timeout = time.time()+timeout - print(msg+" ", end=" ") + print(f"{msg} ", end=" ") while (timeout == None or time.time() timeout: return False @@ -259,8 +259,8 @@ def spin_stat(until=None, timeout=None): time.sleep(0.1) prg = current_progress percent = round(prg * 100.0, 1) - stat_str = str(percent)+"% - " + size_str(int(prg*response_transfer_size)) + " of " + size_str(response_transfer_size) + " - " +size_str(speed, "b")+"ps" - print("\r \rReceiving result "+syms[i]+" "+stat_str, end=" ") + stat_str = f"{percent}% - {size_str(int(prg * response_transfer_size))} of {size_str(response_transfer_size)} - {size_str(speed, 'b')}ps" + print(f'\r \rReceiving result {syms[i]} {stat_str}', end=" ") sys.stdout.flush() i = (i+1)%len(syms) @@ -303,7 +303,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail try: dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 if len(destination) != dest_len: - raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2)) + raise ValueError(f"Allowed destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes).") try: destination_hash = bytes.fromhex(destination) except Exception as e: @@ -321,7 +321,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail if not RNS.Transport.has_path(destination_hash): RNS.Transport.request_path(destination_hash) - if not spin(until=lambda: RNS.Transport.has_path(destination_hash), msg="Path to "+RNS.prettyhexrep(destination_hash)+" requested", timeout=timeout): + if not spin(until=lambda: RNS.Transport.has_path(destination_hash), msg=f"Path to {RNS.prettyhexrep(destination_hash)} requested", timeout=timeout): print("Path not found") exit(242) @@ -339,8 +339,8 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail link = RNS.Link(listener_destination) link.did_identify = False - if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg="Establishing link with "+RNS.prettyhexrep(destination_hash), timeout=timeout): - print("Could not establish link with "+RNS.prettyhexrep(destination_hash)) + if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg=f"Establishing link with {RNS.prettyhexrep(destination_hash)}", timeout=timeout): + print(f"Could not establish link with {RNS.prettyhexrep(destination_hash)}") exit(243) if not noid and not link.did_identify: @@ -443,7 +443,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail print("\n--- End of remote output, rnx done ---") if started != None and concluded != None: cmd_duration = round(concluded - started, 3) - print("Remote command execution took "+str(cmd_duration)+" seconds") + print(f"Remote command execution took {cmd_duration} seconds") total_size = request_receipt.response_size if request_receipt.request_size != None: @@ -453,27 +453,27 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail if transfer_duration == 1: tdstr = " in 1 second" elif transfer_duration < 10: - tdstr = " in "+str(transfer_duration)+" seconds" + tdstr = f" in {transfer_duration} seconds" else: - tdstr = " in "+pretty_time(transfer_duration) + tdstr = f" in {pretty_time(transfer_duration)}" - spdstr = ", effective rate "+size_str(total_size/transfer_duration, "b")+"ps" + spdstr = f", effective rate {size_str(total_size / transfer_duration, 'b')}ps" - print("Transferred "+size_str(total_size)+tdstr+spdstr) + print(f"Transferred {size_str(total_size)}{tdstr}{spdstr}") if outlen != None and stdout != None: if len(stdout) < outlen: - tstr = ", "+str(len(stdout))+" bytes displayed" + tstr = f", {len(stdout)} bytes displayed" else: tstr = "" - print("Remote wrote "+str(outlen)+" bytes to stdout"+tstr) + print(f"Remote wrote {outlen} bytes to stdout{tstr}") if errlen != None and stderr != None: if len(stderr) < errlen: - tstr = ", "+str(len(stderr))+" bytes displayed" + tstr = f", {len(stderr)} bytes displayed" else: tstr = "" - print("Remote wrote "+str(errlen)+" bytes to stderr"+tstr) + print(f"Remote wrote {errlen} bytes to stderr{tstr}") else: if stdout != None and len(stdout) > 0: @@ -487,9 +487,9 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail sys.stderr.flush() print("\nOutput truncated before being returned:") if len(stdout) != 0 and len(stdout) < outlen: - print(" stdout truncated to "+str(len(stdout))+" bytes") + print(f" stdout truncated to {len(stdout)} bytes") if len(stderr) != 0 and len(stderr) < errlen: - print(" stderr truncated to "+str(len(stderr))+" bytes") + print(f" stderr truncated to {len(stderr)} bytes") else: print("Remote could not execute command") if interactive: @@ -547,7 +547,7 @@ def main(): parser.add_argument("--stdin", action='store', default=None, help="pass input to stdin", type=str) parser.add_argument("--stdout", action='store', default=None, help="max size in bytes of returned stdout", type=int) parser.add_argument("--stderr", action='store', default=None, help="max size in bytes of returned stderr", type=int) - parser.add_argument("--version", action="version", version="rnx {version}".format(version=__version__)) + parser.add_argument("--version", action="version", version=f"rnx {__version__}") args = parser.parse_args() @@ -593,7 +593,7 @@ def main(): while True: try: cstr = str(code) if code and code != 0 else "" - prompt = cstr+"> " + prompt = f"{cstr}> " print(prompt,end="") # cmdbuf = b"" @@ -661,12 +661,12 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" def pretty_time(time, verbose=False): days = int(time // (24 * 3600)) @@ -684,16 +684,16 @@ def pretty_time(time, verbose=False): components = [] if days > 0: - components.append(str(days)+" day"+sd if verbose else str(days)+"d") + components.append(f"{days} day{sd}" if verbose else f"{days}d") if hours > 0: - components.append(str(hours)+" hour"+sh if verbose else str(hours)+"h") + components.append(f"{hours} hour{sh}" if verbose else f"{hours}h") if minutes > 0: - components.append(str(minutes)+" minute"+sm if verbose else str(minutes)+"m") + components.append(f"{minutes} minute{sm}" if verbose else f"{minutes}m") if seconds > 0: - components.append(str(seconds)+" second"+ss if verbose else str(seconds)+"s") + components.append(f"{seconds} second{ss}" if verbose else f"{seconds}s") i = 0 tstr = "" diff --git a/RNS/__init__.py b/RNS/__init__.py index 8828e48..04ee64e 100755 --- a/RNS/__init__.py +++ b/RNS/__init__.py @@ -147,7 +147,7 @@ def rand(): def trace_exception(e): import traceback exception_info = "".join(traceback.TracebackException.from_exception(e).format()) - log(f"An unhandled {str(type(e))} exception occurred: {str(e)}", LOG_ERROR) + log(f"An unhandled {type(e)} exception occurred: {e}", LOG_ERROR) log(exception_info, LOG_ERROR) def hexrep(data, delimit=True): @@ -159,12 +159,12 @@ def hexrep(data, delimit=True): delimiter = ":" if not delimit: delimiter = "" - hexrep = delimiter.join("{:02x}".format(c) for c in data) + hexrep = delimiter.join(f"{c:02x}" for c in data) return hexrep def prettyhexrep(data): delimiter = "" - hexrep = "<"+delimiter.join("{:02x}".format(c) for c in data)+">" + hexrep = "<"+delimiter.join(f"{c:02x}" for c in data)+">" return hexrep def prettyspeed(num, suffix="b"): @@ -182,12 +182,12 @@ def prettysize(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" def prettyfrequency(hz, suffix="Hz"): num = hz*1e6 @@ -196,10 +196,10 @@ def prettyfrequency(hz, suffix="Hz"): for unit in units: if abs(num) < 1000.0: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" def prettydistance(m, suffix="m"): num = m*1e6 @@ -212,10 +212,10 @@ def prettydistance(m, suffix="m"): if unit == "c": divisor = 100 if abs(num) < divisor: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= divisor - return "%.2f %s%s" % (num, last_unit, suffix) + return f"{num:.2f} {last_unit}{suffix}" def prettytime(time, verbose=False, compact=False): days = int(time // (24 * 3600)) diff --git a/RNS/vendor/__init__.py b/RNS/vendor/__init__.py index e3164b0..4fa9d93 100755 --- a/RNS/vendor/__init__.py +++ b/RNS/vendor/__init__.py @@ -1,5 +1,5 @@ import os import glob -modules = glob.glob(os.path.dirname(__file__)+"/*.py") +modules = glob.glob(f"{os.path.dirname(__file__)}/*.py") __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')] diff --git a/RNS/vendor/configobj.py b/RNS/vendor/configobj.py index e0c01b6..e84fde5 100755 --- a/RNS/vendor/configobj.py +++ b/RNS/vendor/configobj.py @@ -129,7 +129,7 @@ def getObj(s): global compiler if compiler is None: import compiler - s = "a=" + s + s = f"a={s}" p = compiler.parse(s) return p.getChildren()[1].getChildren()[0].getChildren()[1] @@ -138,7 +138,7 @@ class UnknownType(Exception): pass -class Builder(object): +class Builder: def build(self, o): if m is None: @@ -261,7 +261,7 @@ class InterpolationLoopError(InterpolationError): def __init__(self, option): InterpolationError.__init__( self, - 'interpolation loop detected in value "%s".' % option) + f'interpolation loop detected in value "{option}".') class RepeatSectionError(ConfigObjError): @@ -274,7 +274,7 @@ class RepeatSectionError(ConfigObjError): class MissingInterpolationOption(InterpolationError): """A value specified for interpolation was missing.""" def __init__(self, option): - msg = 'missing option "%s" in interpolation.' % option + msg = f'missing option "{option}" in interpolation.' InterpolationError.__init__(self, msg) @@ -283,7 +283,7 @@ class UnreprError(ConfigObjError): -class InterpolationEngine(object): +class InterpolationEngine: """ A helper class to help perform string interpolation. @@ -336,7 +336,7 @@ class InterpolationEngine(object): replacement = recursive_interpolate(k, v, s, backtrail) # Replace the matched string with its final value start, end = match.span() - value = ''.join((value[:start], replacement, value[end:])) + value = f"{value[:start]}{replacement}{value[end:]}" new_search_start = start + len(replacement) # Pick up the next interpolation key, if any, for next time # through the while loop @@ -553,11 +553,11 @@ class Section(dict): """Fetch the item and do string interpolation.""" val = dict.__getitem__(self, key) if self.main.interpolation: - if isinstance(val, six.string_types): + if isinstance(val, str): return self._interpolate(key, val) if isinstance(val, list): def _check(entry): - if isinstance(entry, six.string_types): + if isinstance(entry, str): return self._interpolate(key, entry) return entry new = [_check(entry) for entry in val] @@ -580,8 +580,8 @@ class Section(dict): ``unrepr`` must be set when setting a value to a dictionary, without creating a new sub-section. """ - if not isinstance(key, six.string_types): - raise ValueError('The key "%s" is not a string.' % key) + if not isinstance(key, str): + raise ValueError(f'The key "{key}" is not a string.') # add the comment if key not in self.comments: @@ -614,14 +614,14 @@ class Section(dict): if key not in self: self.scalars.append(key) if not self.main.stringify: - if isinstance(value, six.string_types): + if isinstance(value, str): pass elif isinstance(value, (list, tuple)): for entry in value: - if not isinstance(entry, six.string_types): - raise TypeError('Value is not a string "%s".' % entry) + if not isinstance(entry, str): + raise TypeError(f'Value is not a string "{entry}".') else: - raise TypeError('Value is not a string "%s".' % value) + raise TypeError(f'Value is not a string "{value}".') dict.__setitem__(self, key, value) @@ -728,7 +728,7 @@ class Section(dict): def iterkeys(self): """D.iterkeys() -> an iterator over the keys of D""" - return iter((self.scalars + self.sections)) + return iter(self.scalars + self.sections) __iter__ = iterkeys @@ -745,7 +745,7 @@ class Section(dict): return self[key] except MissingInterpolationOption: return dict.__getitem__(self, key) - return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(_getval(key)))) + return '{%s}' % ', '.join([f'{key!r}: {_getval(key)!r}' for key in (self.scalars + self.sections)]) __str__ = __repr__ @@ -823,7 +823,7 @@ class Section(dict): elif oldkey in self.sections: the_list = self.sections else: - raise KeyError('Key "%s" not found.' % oldkey) + raise KeyError(f'Key "{oldkey}" not found.') pos = the_list.index(oldkey) # val = self[oldkey] @@ -959,13 +959,13 @@ class Section(dict): return False else: try: - if not isinstance(val, six.string_types): + if not isinstance(val, str): # TODO: Why do we raise a KeyError here? raise KeyError() else: return self.main._bools[val.lower()] except KeyError: - raise ValueError('Value "%s" is neither True nor False' % val) + raise ValueError(f'Value "{val}" is neither True nor False') def as_int(self, key): @@ -1210,7 +1210,7 @@ class ConfigObj(Section): # TODO: check the values too. for entry in options: if entry not in OPTION_DEFAULTS: - raise TypeError('Unrecognised option "%s".' % entry) + raise TypeError(f'Unrecognised option "{entry}".') for entry, value in list(OPTION_DEFAULTS.items()): if entry not in options: options[entry] = value @@ -1230,14 +1230,14 @@ class ConfigObj(Section): def _load(self, infile, configspec): - if isinstance(infile, six.string_types): + if isinstance(infile, str): self.filename = infile if os.path.isfile(infile): with open(infile, 'rb') as h: content = h.readlines() or [] elif self.file_error: # raise an error if the file doesn't exist - raise IOError('Config file not found: "%s".' % self.filename) + raise OSError(f'Config file not found: "{self.filename}".') else: # file doesn't already exist if self.create_empty: @@ -1298,15 +1298,15 @@ class ConfigObj(Section): break break - assert all(isinstance(line, six.string_types) for line in content), repr(content) + assert all(isinstance(line, str) for line in content), repr(content) content = [line.rstrip('\r\n') for line in content] self._parse(content) # if we had any errors, now is the time to raise them if self._errors: - info = "at line %s." % self._errors[0].line_number + info = f"at line {self._errors[0].line_number}." if len(self._errors) > 1: - msg = "Parsing failed with several errors.\nFirst error %s" % info + msg = f"Parsing failed with several errors.\nFirst error {info}" error = ConfigObjError(msg) else: error = self._errors[0] @@ -1363,9 +1363,7 @@ class ConfigObj(Section): return self[key] except MissingInterpolationOption: return dict.__getitem__(self, key) - return ('ConfigObj({%s})' % - ', '.join([('%s: %s' % (repr(key), repr(_getval(key)))) - for key in (self.scalars + self.sections)])) + return ('ConfigObj({%s})' % ', '.join([f'{key!r}: {_getval(key)!r}' for key in (self.scalars + self.sections)])) def _handle_bom(self, infile): @@ -1403,7 +1401,7 @@ class ConfigObj(Section): else: line = infile - if isinstance(line, six.text_type): + if isinstance(line, str): # it's already decoded and there's no need to do anything # else, just use the _decode utility method to handle # listifying appropriately @@ -1448,7 +1446,7 @@ class ConfigObj(Section): # No encoding specified - so we need to check for UTF8/UTF16 for BOM, (encoding, final_encoding) in list(BOMS.items()): - if not isinstance(line, six.binary_type) or not line.startswith(BOM): + if not isinstance(line, bytes) or not line.startswith(BOM): # didn't specify a BOM, or it's not a bytestring continue else: @@ -1464,9 +1462,9 @@ class ConfigObj(Section): else: infile = newline # UTF-8 - if isinstance(infile, six.text_type): + if isinstance(infile, str): return infile.splitlines(True) - elif isinstance(infile, six.binary_type): + elif isinstance(infile, bytes): return infile.decode('utf-8').splitlines(True) else: return self._decode(infile, 'utf-8') @@ -1479,7 +1477,7 @@ class ConfigObj(Section): # returning a bytestring is fine return self._decode(infile, None) # No BOM discovered and no encoding specified, default to UTF-8 - if isinstance(infile, six.binary_type): + if isinstance(infile, bytes): return infile.decode('utf-8').splitlines(True) else: return self._decode(infile, 'utf-8') @@ -1487,7 +1485,7 @@ class ConfigObj(Section): def _a_to_u(self, aString): """Decode ASCII strings to unicode if a self.encoding is specified.""" - if isinstance(aString, six.binary_type) and self.encoding: + if isinstance(aString, bytes) and self.encoding: return aString.decode(self.encoding) else: return aString @@ -1499,9 +1497,9 @@ class ConfigObj(Section): if is a string, it also needs converting to a list. """ - if isinstance(infile, six.string_types): + if isinstance(infile, str): return infile.splitlines(True) - if isinstance(infile, six.binary_type): + if isinstance(infile, bytes): # NOTE: Could raise a ``UnicodeDecodeError`` if encoding: return infile.decode(encoding).splitlines(True) @@ -1510,7 +1508,7 @@ class ConfigObj(Section): if encoding: for i, line in enumerate(infile): - if isinstance(line, six.binary_type): + if isinstance(line, bytes): # NOTE: The isinstance test here handles mixed lists of unicode/string # NOTE: But the decode will break on any non-string values # NOTE: Or could raise a ``UnicodeDecodeError`` @@ -1520,7 +1518,7 @@ class ConfigObj(Section): def _decode_element(self, line): """Decode element to unicode if necessary.""" - if isinstance(line, six.binary_type) and self.default_encoding: + if isinstance(line, bytes) and self.default_encoding: return line.decode(self.default_encoding) else: return line @@ -1532,7 +1530,7 @@ class ConfigObj(Section): Used by ``stringify`` within validate, to turn non-string values into strings. """ - if not isinstance(value, six.string_types): + if not isinstance(value, str): # intentially 'str' because it's just whatever the "normal" # string type is for the python version we're dealing with return str(value) @@ -1627,7 +1625,7 @@ class ConfigObj(Section): mat = self._keyword.match(line) if mat is None: self._handle_error( - 'Invalid line ({0!r}) (matched as neither section nor keyword)'.format(line), + f'Invalid line ({line!r}) (matched as neither section nor keyword)', ParseError, infile, cur_index) else: # is a keyword value @@ -1735,7 +1733,7 @@ class ConfigObj(Section): """ line = infile[cur_index] cur_index += 1 - message = '{0} at line {1}.'.format(text, cur_index) + message = f'{text} at line {cur_index}.' error = ErrorClass(message, cur_index, line) if self.raise_errors: # raise the error - parsing stops here @@ -1783,16 +1781,16 @@ class ConfigObj(Section): if not value: return ',' elif len(value) == 1: - return self._quote(value[0], multiline=False) + ',' + return f"{self._quote(value[0], multiline=False)}," return ', '.join([self._quote(val, multiline=False) for val in value]) - if not isinstance(value, six.string_types): + if not isinstance(value, str): if self.stringify: # intentially 'str' because it's just whatever the "normal" # string type is for the python version we're dealing with value = str(value) else: - raise TypeError('Value "%s" is not a string.' % value) + raise TypeError(f'Value "{value}" is not a string.') if not value: return '""' @@ -1809,7 +1807,7 @@ class ConfigObj(Section): # for normal values either single or double quotes will do elif '\n' in value: # will only happen if multiline is off - e.g. '\n' in key - raise ConfigObjError('Value "%s" cannot be safely quoted.' % value) + raise ConfigObjError(f'Value "{value}" cannot be safely quoted.') elif ((value[0] not in wspace_plus) and (value[-1] not in wspace_plus) and (',' not in value)): @@ -1828,7 +1826,7 @@ class ConfigObj(Section): def _get_single_quote(self, value): if ("'" in value) and ('"' in value): - raise ConfigObjError('Value "%s" cannot be safely quoted.' % value) + raise ConfigObjError(f'Value "{value}" cannot be safely quoted.') elif '"' in value: quot = squot else: @@ -1838,7 +1836,7 @@ class ConfigObj(Section): def _get_triple_quote(self, value): if (value.find('"""') != -1) and (value.find("'''") != -1): - raise ConfigObjError('Value "%s" cannot be safely quoted.' % value) + raise ConfigObjError(f'Value "{value}" cannot be safely quoted.') if value.find('"""') == -1: quot = tdquot else: @@ -1943,9 +1941,9 @@ class ConfigObj(Section): except ConfigObjError as e: # FIXME: Should these errors have a reference # to the already parsed ConfigObj ? - raise ConfigspecError('Parsing configspec failed: %s' % e) - except IOError as e: - raise IOError('Reading configspec failed: %s' % e) + raise ConfigspecError(f'Parsing configspec failed: {e}') + except OSError as e: + raise OSError(f'Reading configspec failed: {e}') self.configspec = configspec @@ -1986,20 +1984,12 @@ class ConfigObj(Section): val = self._decode_element(self._quote(this_entry)) else: val = repr(this_entry) - return '%s%s%s%s%s' % (indent_string, - self._decode_element(self._quote(entry, multiline=False)), - self._a_to_u(' = '), - val, - self._decode_element(comment)) + return f"{indent_string}{self._decode_element(self._quote(entry, multiline=False))}{self._a_to_u(' = ')}{val}{self._decode_element(comment)}" def _write_marker(self, indent_string, depth, entry, comment): """Write a section marker line""" - return '%s%s%s%s%s' % (indent_string, - self._a_to_u('[' * depth), - self._quote(self._decode_element(entry), multiline=False), - self._a_to_u(']' * depth), - self._decode_element(comment)) + return f"{indent_string}{self._a_to_u('[' * depth)}{self._quote(self._decode_element(entry), multiline=False)}{self._a_to_u(']' * depth)}{self._decode_element(comment)}" def _handle_comment(self, comment): @@ -2111,7 +2101,7 @@ class ConfigObj(Section): if not output.endswith(newline): output += newline - if isinstance(output, six.binary_type): + if isinstance(output, bytes): output_bytes = output else: output_bytes = output.encode(self.encoding or @@ -2284,7 +2274,7 @@ class ConfigObj(Section): out[entry] = False else: ret_false = False - msg = 'Value %r was provided as a section' % entry + msg = f'Value {entry!r} was provided as a section' out[entry] = validator.baseErrorClass(msg) for entry in incorrect_sections: ret_true = False @@ -2292,7 +2282,7 @@ class ConfigObj(Section): out[entry] = False else: ret_false = False - msg = 'Section %r was provided as a single value' % entry + msg = f'Section {entry!r} was provided as a single value' out[entry] = validator.baseErrorClass(msg) # Missing sections will have been created as empty ones when the @@ -2353,7 +2343,7 @@ class ConfigObj(Section): This method raises a ``ReloadError`` if the ConfigObj doesn't have a filename attribute pointing to a file. """ - if not isinstance(self.filename, six.string_types): + if not isinstance(self.filename, str): raise ReloadError() filename = self.filename @@ -2372,7 +2362,7 @@ class ConfigObj(Section): -class SimpleVal(object): +class SimpleVal: """ A simple validator. Can be used to check that all members expected are present. diff --git a/RNS/vendor/i2plib/aiosam.py b/RNS/vendor/i2plib/aiosam.py index bbb2c4a..eccff10 100644 --- a/RNS/vendor/i2plib/aiosam.py +++ b/RNS/vendor/i2plib/aiosam.py @@ -11,7 +11,7 @@ def parse_reply(data): try: msg = sam.Message(data.decode().strip()) - logger.debug("SAM reply: "+str(msg)) + logger.debug(f"SAM reply: {msg}") except: raise ConnectionAbortedError("Invalid SAM response") @@ -89,7 +89,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, :param options: (optional) A dict object with i2cp options :return: A (reader, writer) pair """ - logger.debug("Creating session {}".format(session_name)) + logger.debug(f"Creating session {session_name}") if destination: if type(destination) == sam.Destination: destination = destination @@ -101,7 +101,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, else: dest_string = sam.TRANSIENT_DESTINATION - options = " ".join(["{}={}".format(k, v) for k, v in options.items()]) + options = " ".join([f"{k}={v}" for k, v in options.items()]) reader, writer = await get_sam_socket(sam_address, loop) writer.write(sam.session_create( @@ -113,7 +113,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, destination = sam.Destination( reply["DESTINATION"], has_private_key=True) logger.debug(destination.base32) - logger.debug("Session created {}".format(session_name)) + logger.debug(f"Session created {session_name}") return (reader, writer) else: writer.close() @@ -129,7 +129,7 @@ async def stream_connect(session_name, destination, :param loop: (optional) Event loop instance :return: A (reader, writer) pair """ - logger.debug("Connecting stream {}".format(session_name)) + logger.debug(f"Connecting stream {session_name}") if isinstance(destination, str) and not destination.endswith(".i2p"): destination = sam.Destination(destination) elif isinstance(destination, str): @@ -140,7 +140,7 @@ async def stream_connect(session_name, destination, silent="false")) reply = parse_reply(await reader.readline()) if reply.ok: - logger.debug("Stream connected {}".format(session_name)) + logger.debug(f"Stream connected {session_name}") return (reader, writer) else: writer.close() diff --git a/RNS/vendor/i2plib/sam.py b/RNS/vendor/i2plib/sam.py index 1bad75d..dad8b76 100644 --- a/RNS/vendor/i2plib/sam.py +++ b/RNS/vendor/i2plib/sam.py @@ -23,7 +23,7 @@ TRANSIENT_DESTINATION = "TRANSIENT" VALID_BASE32_ADDRESS = re.compile(r"^([a-zA-Z0-9]{52}).b32.i2p$") VALID_BASE64_ADDRESS = re.compile(r"^([a-zA-Z0-9-~=]{516,528})$") -class Message(object): +class Message: """Parse SAM message to an object""" def __init__(self, s): self.opts = {} @@ -51,34 +51,30 @@ class Message(object): # SAM request messages def hello(min_version, max_version): - return "HELLO VERSION MIN={} MAX={}\n".format(min_version, - max_version).encode() + return f"HELLO VERSION MIN={min_version} MAX={max_version}\n".encode() def session_create(style, session_id, destination, options=""): - return "SESSION CREATE STYLE={} ID={} DESTINATION={} {}\n".format( - style, session_id, destination, options).encode() + return f"SESSION CREATE STYLE={style} ID={session_id} DESTINATION={destination} {options}\n".encode() def stream_connect(session_id, destination, silent="false"): - return "STREAM CONNECT ID={} DESTINATION={} SILENT={}\n".format( - session_id, destination, silent).encode() + return f"STREAM CONNECT ID={session_id} DESTINATION={destination} SILENT={silent}\n".encode() def stream_accept(session_id, silent="false"): - return "STREAM ACCEPT ID={} SILENT={}\n".format(session_id, silent).encode() + return f"STREAM ACCEPT ID={session_id} SILENT={silent}\n".encode() def stream_forward(session_id, port, options=""): - return "STREAM FORWARD ID={} PORT={} {}\n".format( - session_id, port, options).encode() + return f"STREAM FORWARD ID={session_id} PORT={port} {options}\n".encode() def naming_lookup(name): - return "NAMING LOOKUP NAME={}\n".format(name).encode() + return f"NAMING LOOKUP NAME={name}\n".encode() def dest_generate(signature_type): - return "DEST GENERATE SIGNATURE_TYPE={}\n".format(signature_type).encode() + return f"DEST GENERATE SIGNATURE_TYPE={signature_type}\n".encode() -class Destination(object): +class Destination: """I2P destination https://geti2p.net/spec/common-structures#destination @@ -101,7 +97,7 @@ class Destination(object): def __init__(self, data=None, path=None, has_private_key=False): #: Binary destination - self.data = bytes() + self.data = b'' #: Base64 encoded destination self.base64 = "" #: :class:`RNS.vendor.i2plib.PrivateKey` instance or None @@ -123,7 +119,7 @@ class Destination(object): self.base64 = data if type(data) == str else i2p_b64encode(data) def __repr__(self): - return "".format(self.base32) + return f"" @property def base32(self): @@ -131,7 +127,7 @@ class Destination(object): desthash = sha256(self.data).digest() return b32encode(desthash).decode()[:52].lower() -class PrivateKey(object): +class PrivateKey: """I2P private key https://geti2p.net/spec/common-structures#keysandcert diff --git a/RNS/vendor/i2plib/tunnel.py b/RNS/vendor/i2plib/tunnel.py index 9418dbe..aeb0f63 100644 --- a/RNS/vendor/i2plib/tunnel.py +++ b/RNS/vendor/i2plib/tunnel.py @@ -18,7 +18,7 @@ async def proxy_data(reader, writer): break writer.write(data) except Exception as e: - logger.debug('proxy_data_task exception {}'.format(e)) + logger.debug(f'proxy_data_task exception {e}') finally: try: writer.close() @@ -26,7 +26,7 @@ async def proxy_data(reader, writer): pass logger.debug('close connection') -class I2PTunnel(object): +class I2PTunnel: """Base I2P Tunnel object, not to be used directly :param local_address: A local address to use for a tunnel. @@ -141,9 +141,8 @@ class ServerTunnel(I2PTunnel): # data and dest may come in one chunk dest, data = incoming.split(b"\n", 1) remote_destination = sam.Destination(dest.decode()) - logger.debug("{} client connected: {}.b32.i2p".format( - self.session_name, remote_destination.base32)) - + logger.debug(f"{self.session_name} client connected: {remote_destination.base32}.b32.i2p") + except Exception as e: self.status["exception"] = e self.status["setup_failed"] = True diff --git a/RNS/vendor/i2plib/utils.py b/RNS/vendor/i2plib/utils.py index 3c59846..15c5c43 100644 --- a/RNS/vendor/i2plib/utils.py +++ b/RNS/vendor/i2plib/utils.py @@ -38,5 +38,5 @@ def generate_session_id(length=6): """Generate random session id""" rand = random.SystemRandom() sid = [rand.choice(string.ascii_letters) for _ in range(length)] - return "reticulum-" + "".join(sid) + return f"reticulum-{''.join(sid)}" diff --git a/RNS/vendor/ifaddr/__init__.py b/RNS/vendor/ifaddr/__init__.py index 7b10423..8ddd028 100644 --- a/RNS/vendor/ifaddr/__init__.py +++ b/RNS/vendor/ifaddr/__init__.py @@ -28,6 +28,6 @@ if os.name == "nt": elif os.name == "posix": from RNS.vendor.ifaddr._posix import get_adapters else: - raise RuntimeError("Unsupported Operating System: %s" % os.name) + raise RuntimeError(f"Unsupported Operating System: {os.name}") __all__ = ['Adapter', 'IP', 'get_adapters'] diff --git a/RNS/vendor/ifaddr/_posix.py b/RNS/vendor/ifaddr/_posix.py index 60ab3f8..bcf2223 100644 --- a/RNS/vendor/ifaddr/_posix.py +++ b/RNS/vendor/ifaddr/_posix.py @@ -79,7 +79,7 @@ def get_adapters(include_unconfigured: bool = False) -> Iterable[shared.Adapter] prefixlen = shared.ipv6_prefixlength(ipaddress.IPv6Address(netmaskStr)) else: assert netmask is not None, f'sockaddr_to_ip({addr[0].ifa_netmask}) returned None' - netmaskStr = str('0.0.0.0/' + netmask) + netmaskStr = str(f"0.0.0.0/{netmask}") prefixlen = ipaddress.IPv4Network(netmaskStr).prefixlen ip = shared.IP(ip_addr, prefixlen, name) add_ip(name, ip) diff --git a/RNS/vendor/ifaddr/_shared.py b/RNS/vendor/ifaddr/_shared.py index 42939d3..53dfc95 100644 --- a/RNS/vendor/ifaddr/_shared.py +++ b/RNS/vendor/ifaddr/_shared.py @@ -26,7 +26,7 @@ import platform from typing import List, Optional, Tuple, Union -class Adapter(object): +class Adapter: """ Represents a network interface device controller (NIC), such as a network card. An adapter can have multiple IPs. @@ -58,9 +58,7 @@ class Adapter(object): self.index = index def __repr__(self) -> str: - return "Adapter(name={name}, nice_name={nice_name}, ips={ips}, index={index})".format( - name=repr(self.name), nice_name=repr(self.nice_name), ips=repr(self.ips), index=repr(self.index) - ) + return f"Adapter(name={self.name!r}, nice_name={self.nice_name!r}, ips={self.ips!r}, index={self.index!r})" # Type of an IPv4 address (a string in "xxx.xxx.xxx.xxx" format) @@ -70,7 +68,7 @@ _IPv4Address = str _IPv6Address = Tuple[str, int, int] -class IP(object): +class IP: """ Represents an IP address of an adapter. """ @@ -112,9 +110,7 @@ class IP(object): return isinstance(self.ip, tuple) def __repr__(self) -> str: - return "IP(ip={ip}, network_prefix={network_prefix}, nice_name={nice_name})".format( - ip=repr(self.ip), network_prefix=repr(self.network_prefix), nice_name=repr(self.nice_name) - ) + return f"IP(ip={self.ip!r}, network_prefix={self.network_prefix!r}, nice_name={self.nice_name!r})" if platform.system() == "Darwin" or "BSD" in platform.system(): diff --git a/RNS/vendor/ifaddr/niwrapper.py b/RNS/vendor/ifaddr/niwrapper.py index 8167dc4..b7fc946 100644 --- a/RNS/vendor/ifaddr/niwrapper.py +++ b/RNS/vendor/ifaddr/niwrapper.py @@ -40,7 +40,7 @@ def ifaddresses(ifname) -> dict: for ip in a.ips: t = {} if ip.is_IPv4: - net = ipaddress.ip_network(str(ip.ip)+"/"+str(ip.network_prefix), strict=False) + net = ipaddress.ip_network(f"{ip.ip}/{ip.network_prefix}", strict=False) t["addr"] = ip.ip t["prefix"] = ip.network_prefix t["broadcast"] = str(net.broadcast_address) diff --git a/RNS/vendor/six.py b/RNS/vendor/six.py index 4e15675..5802034 100644 --- a/RNS/vendor/six.py +++ b/RNS/vendor/six.py @@ -20,7 +20,6 @@ """Utilities for writing code that runs on Python 2 and 3""" -from __future__ import absolute_import import functools import itertools @@ -57,7 +56,7 @@ else: MAXSIZE = int((1 << 31) - 1) else: # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): + class X: def __len__(self): return 1 << 31 @@ -88,7 +87,7 @@ def _import_module(name): return sys.modules[name] -class _LazyDescr(object): +class _LazyDescr: def __init__(self, name): self.name = name @@ -108,7 +107,7 @@ class _LazyDescr(object): class MovedModule(_LazyDescr): def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) + super().__init__(name) if PY3: if new is None: new = name @@ -129,7 +128,7 @@ class MovedModule(_LazyDescr): class _LazyModule(types.ModuleType): def __init__(self, name): - super(_LazyModule, self).__init__(name) + super().__init__(name) self.__doc__ = self.__class__.__doc__ def __dir__(self): @@ -144,7 +143,7 @@ class _LazyModule(types.ModuleType): class MovedAttribute(_LazyDescr): def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) + super().__init__(name) if PY3: if new_mod is None: new_mod = name @@ -166,7 +165,7 @@ class MovedAttribute(_LazyDescr): return getattr(module, self.attr) -class _SixMetaPathImporter(object): +class _SixMetaPathImporter: """ A meta path importer to import six.moves and its submodules. @@ -181,10 +180,10 @@ class _SixMetaPathImporter(object): def _add_module(self, mod, *fullnames): for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod + self.known_modules[f"{self.name}.{fullname}"] = mod def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] + return self.known_modules[f"{self.name}.{fullname}"] def find_module(self, fullname, path=None): if fullname in self.known_modules: @@ -200,7 +199,7 @@ class _SixMetaPathImporter(object): try: return self.known_modules[fullname] except KeyError: - raise ImportError("This loader does not know module " + fullname) + raise ImportError(f"This loader does not know module {fullname}") def load_module(self, fullname): try: @@ -312,9 +311,9 @@ _moved_attributes = [ MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_parse", f"{__name__}.moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", f"{__name__}.moves.urllib_error", "urllib.error"), + MovedModule("urllib", f"{__name__}.moves.urllib", f"{__name__}.moves.urllib"), MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), @@ -328,12 +327,12 @@ if sys.platform == "win32": for attr in _moved_attributes: setattr(_MovedItems, attr.name, attr) if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) + _importer._add_module(attr, f"moves.{attr.name}") del attr _MovedItems._moved_attributes = _moved_attributes -moves = _MovedItems(__name__ + ".moves") +moves = _MovedItems(f"{__name__}.moves") _importer._add_module(moves, "moves") @@ -375,7 +374,7 @@ del attr Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes -_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), +_importer._add_module(Module_six_moves_urllib_parse(f"{__name__}.moves.urllib_parse"), "moves.urllib_parse", "moves.urllib.parse") @@ -395,7 +394,7 @@ del attr Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes -_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), +_importer._add_module(Module_six_moves_urllib_error(f"{__name__}.moves.urllib.error"), "moves.urllib_error", "moves.urllib.error") @@ -447,7 +446,7 @@ del attr Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes -_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), +_importer._add_module(Module_six_moves_urllib_request(f"{__name__}.moves.urllib.request"), "moves.urllib_request", "moves.urllib.request") @@ -468,7 +467,7 @@ del attr Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes -_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), +_importer._add_module(Module_six_moves_urllib_response(f"{__name__}.moves.urllib.response"), "moves.urllib_response", "moves.urllib.response") @@ -486,7 +485,7 @@ del attr Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes -_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), +_importer._add_module(Module_six_moves_urllib_robotparser(f"{__name__}.moves.urllib.robotparser"), "moves.urllib_robotparser", "moves.urllib.robotparser") @@ -503,7 +502,7 @@ class Module_six_moves_urllib(types.ModuleType): def __dir__(self): return ['parse', 'error', 'request', 'response', 'robotparser'] -_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), +_importer._add_module(Module_six_moves_urllib(f"{__name__}.moves.urllib"), "moves.urllib") @@ -520,7 +519,7 @@ def remove_move(name): try: del moves.__dict__[name] except KeyError: - raise AttributeError("no such move, %r" % (name,)) + raise AttributeError(f"no such move, {name!r}") if PY3: @@ -576,7 +575,7 @@ else: def create_unbound_method(func, cls): return types.MethodType(func, None, cls) - class Iterator(object): + class Iterator: def next(self): return type(self).__next__(self) @@ -910,7 +909,7 @@ def ensure_binary(s, encoding='utf-8', errors='strict'): return s if isinstance(s, text_type): return s.encode(encoding, errors) - raise TypeError("not expecting type '%s'" % type(s)) + raise TypeError(f"not expecting type '{type(s)}'") def ensure_str(s, encoding='utf-8', errors='strict'): @@ -932,7 +931,7 @@ def ensure_str(s, encoding='utf-8', errors='strict'): elif PY3 and isinstance(s, binary_type): return s.decode(encoding, errors) elif not isinstance(s, (text_type, binary_type)): - raise TypeError("not expecting type '%s'" % type(s)) + raise TypeError(f"not expecting type '{type(s)}'") return s @@ -952,7 +951,7 @@ def ensure_text(s, encoding='utf-8', errors='strict'): elif isinstance(s, text_type): return s else: - raise TypeError("not expecting type '%s'" % type(s)) + raise TypeError(f"not expecting type '{type(s)}'") def python_2_unicode_compatible(klass): @@ -965,9 +964,7 @@ def python_2_unicode_compatible(klass): """ if PY2: if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) + raise ValueError(f"@python_2_unicode_compatible cannot be applied to {klass.__name__} because it doesn't define __str__().") klass.__unicode__ = klass.__str__ klass.__str__ = lambda self: self.__unicode__().encode('utf-8') return klass diff --git a/RNS/vendor/umsgpack.py b/RNS/vendor/umsgpack.py index c6fa1e7..939a6eb 100644 --- a/RNS/vendor/umsgpack.py +++ b/RNS/vendor/umsgpack.py @@ -52,7 +52,7 @@ import io if sys.version_info[0:2] >= (3, 3): from collections.abc import Hashable else: - from collections import Hashable + from collections.abc import Hashable __version__ = "2.7.1" "Module version string" @@ -66,7 +66,7 @@ version = (2, 7, 1) ############################################################################## # Extension type for application-defined types and data -class Ext(object): +class Ext: """ The Ext class facilitates creating a serializable extension object to store an application-defined type and data byte array. @@ -100,7 +100,7 @@ class Ext(object): if not isinstance(type, int): raise TypeError("ext type is not type integer") elif not (-2**7 <= type <= 2**7 - 1): - raise ValueError("ext type value {:d} is out of range (-128 to 127)".format(type)) + raise ValueError(f"ext type value {type} is out of range (-128 to 127)") # Check data is type bytes or str elif sys.version_info[0] == 3 and not isinstance(data, bytes): raise TypeError("ext data is not type \'bytes\'") @@ -127,8 +127,8 @@ class Ext(object): """ String representation of this Ext object. """ - s = "Ext Object (Type: {:d}, Data: ".format(self.type) - s += " ".join(["0x{:02}".format(ord(self.data[i:i + 1])) + s = f"Ext Object (Type: {self.type}, Data: " + s += " ".join([f"0x{ord(self.data[i:i + 1]):02}" for i in xrange(min(len(self.data), 8))]) if len(self.data) > 8: s += " ..." @@ -177,11 +177,11 @@ def ext_serializable(ext_type): if not isinstance(ext_type, int): raise TypeError("Ext type is not type integer") elif not (-2**7 <= ext_type <= 2**7 - 1): - raise ValueError("Ext type value {:d} is out of range of -128 to 127".format(ext_type)) + raise ValueError(f"Ext type value {ext_type} is out of range of -128 to 127") elif ext_type in _ext_type_to_class: - raise ValueError("Ext type {:d} already registered with class {:s}".format(ext_type, repr(_ext_type_to_class[ext_type]))) + raise ValueError(f"Ext type {ext_type} already registered with class {_ext_type_to_class[ext_type]!r}") elif cls in _ext_class_to_type: - raise ValueError("Class {:s} already registered with Ext type {:d}".format(repr(cls), ext_type)) + raise ValueError(f"Class {cls!r} already registered with Ext type {ext_type}") _ext_type_to_class[ext_type] = cls _ext_class_to_type[cls] = ext_type @@ -495,7 +495,7 @@ def _pack2(obj, fp, **options): try: _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) + raise NotImplementedError(f"Ext serializable class {obj.__class__!r} is missing implementation of packb()") elif isinstance(obj, bool): _pack_boolean(obj, fp, options) elif isinstance(obj, (int, long)): @@ -525,7 +525,7 @@ def _pack2(obj, fp, **options): _pack_ext(ext_handlers[t](obj), fp, options) else: raise UnsupportedTypeException( - "unsupported type: {:s}".format(str(type(obj)))) + f"unsupported type: {type(obj)}") elif _ext_class_to_type: # Linear search for superclass t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) @@ -533,11 +533,11 @@ def _pack2(obj, fp, **options): try: _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + raise NotImplementedError(f"Ext serializable class {t!r} is missing implementation of packb()") else: - raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + raise UnsupportedTypeException(f"unsupported type: {type(obj)}") else: - raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + raise UnsupportedTypeException(f"unsupported type: {type(obj)}") # Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type @@ -582,7 +582,7 @@ def _pack3(obj, fp, **options): try: _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(obj.__class__))) + raise NotImplementedError(f"Ext serializable class {obj.__class__!r} is missing implementation of packb()") elif isinstance(obj, bool): _pack_boolean(obj, fp, options) elif isinstance(obj, int): @@ -612,7 +612,7 @@ def _pack3(obj, fp, **options): _pack_ext(ext_handlers[t](obj), fp, options) else: raise UnsupportedTypeException( - "unsupported type: {:s}".format(str(type(obj)))) + f"unsupported type: {type(obj)}") elif _ext_class_to_type: # Linear search for superclass t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) @@ -620,12 +620,12 @@ def _pack3(obj, fp, **options): try: _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of packb()".format(repr(t))) + raise NotImplementedError(f"Ext serializable class {t!r} is missing implementation of packb()") else: - raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) + raise UnsupportedTypeException(f"unsupported type: {type(obj)}") else: raise UnsupportedTypeException( - "unsupported type: {:s}".format(str(type(obj)))) + f"unsupported type: {type(obj)}") def _packb2(obj, **options): @@ -737,21 +737,21 @@ def _unpack_integer(code, fp, options): return struct.unpack(">I", _read_except(fp, 4))[0] elif code == b'\xcf': return struct.unpack(">Q", _read_except(fp, 8))[0] - raise Exception("logic error, not int: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not int: 0x{ord(code):02x}") def _unpack_reserved(code, fp, options): if code == b'\xc1': raise ReservedCodeException( - "encountered reserved code: 0x{:02x}".format(ord(code))) + f"encountered reserved code: 0x{ord(code):02x}") raise Exception( - "logic error, not reserved code: 0x{:02x}".format(ord(code))) + f"logic error, not reserved code: 0x{ord(code):02x}") def _unpack_nil(code, fp, options): if code == b'\xc0': return None - raise Exception("logic error, not nil: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not nil: 0x{ord(code):02x}") def _unpack_boolean(code, fp, options): @@ -759,7 +759,7 @@ def _unpack_boolean(code, fp, options): return False elif code == b'\xc3': return True - raise Exception("logic error, not boolean: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not boolean: 0x{ord(code):02x}") def _unpack_float(code, fp, options): @@ -767,7 +767,7 @@ def _unpack_float(code, fp, options): return struct.unpack(">f", _read_except(fp, 4))[0] elif code == b'\xcb': return struct.unpack(">d", _read_except(fp, 8))[0] - raise Exception("logic error, not float: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not float: 0x{ord(code):02x}") def _unpack_string(code, fp, options): @@ -780,7 +780,7 @@ def _unpack_string(code, fp, options): elif code == b'\xdb': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not string: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not string: 0x{ord(code):02x}") # Always return raw bytes in compatibility mode global compatibility @@ -804,7 +804,7 @@ def _unpack_binary(code, fp, options): elif code == b'\xc6': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not binary: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not binary: 0x{ord(code):02x}") return _read_except(fp, length) @@ -827,7 +827,7 @@ def _unpack_ext(code, fp, options): elif code == b'\xc9': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not ext: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not ext: 0x{ord(code):02x}") ext_type = struct.unpack("b", _read_except(fp, 1))[0] ext_data = _read_except(fp, length) @@ -842,7 +842,7 @@ def _unpack_ext(code, fp, options): try: return _ext_type_to_class[ext_type].unpackb(ext_data) except AttributeError: - raise NotImplementedError("Ext serializable class {:s} is missing implementation of unpackb()".format(repr(_ext_type_to_class[ext_type]))) + raise NotImplementedError(f"Ext serializable class {_ext_type_to_class[ext_type]!r} is missing implementation of unpackb()") # Timestamp extension if ext_type == -1: @@ -868,7 +868,7 @@ def _unpack_ext_timestamp(ext_data, options): microseconds = struct.unpack(">I", ext_data[0:4])[0] // 1000 else: raise UnsupportedTimestampException( - "unsupported timestamp with data length {:d}".format(len(ext_data))) + f"unsupported timestamp with data length {len(ext_data)}") return _epoch + datetime.timedelta(seconds=seconds, microseconds=microseconds) @@ -882,10 +882,10 @@ def _unpack_array(code, fp, options): elif code == b'\xdd': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not array: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not array: 0x{ord(code):02x}") if options.get('use_tuple'): - return tuple((_unpack(fp, options) for i in xrange(length))) + return tuple(_unpack(fp, options) for i in xrange(length)) return [_unpack(fp, options) for i in xrange(length)] @@ -904,7 +904,7 @@ def _unpack_map(code, fp, options): elif code == b'\xdf': length = struct.unpack(">I", _read_except(fp, 4))[0] else: - raise Exception("logic error, not map: 0x{:02x}".format(ord(code))) + raise Exception(f"logic error, not map: 0x{ord(code):02x}") d = {} if not options.get('use_ordered_dict') else collections.OrderedDict() for _ in xrange(length): @@ -916,10 +916,10 @@ def _unpack_map(code, fp, options): k = _deep_list_to_tuple(k) elif not isinstance(k, Hashable): raise UnhashableKeyException( - "encountered unhashable key: \"{:s}\" ({:s})".format(str(k), str(type(k)))) + f"encountered unhashable key: \"{k}\" ({type(k)})") elif k in d: raise DuplicateKeyException( - "encountered duplicate key: \"{:s}\" ({:s})".format(str(k), str(type(k)))) + f"encountered duplicate key: \"{k}\" ({type(k)})") # Unpack value v = _unpack(fp, options) @@ -928,7 +928,7 @@ def _unpack_map(code, fp, options): d[k] = v except TypeError: raise UnhashableKeyException( - "encountered unhashable key: \"{:s}\"".format(str(k))) + f"encountered unhashable key: \"{k}\"") return d diff --git a/docs/source/conf.py b/docs/source/conf.py index 00bff97..3b0d583 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,12 +13,12 @@ project = 'Reticulum Network Stack' copyright = '2023, Mark Qvist' author = 'Mark Qvist' -exec(open("../../RNS/_version.py", "r").read()) +exec(open("../../RNS/_version.py").read()) version = __version__ # The full version, including alpha/beta/rc tags import RNS -release = RNS._version.__version__+" beta" +release = f"{RNS._version.__version__} beta" # -- General configuration --------------------------------------------------- extensions = [ diff --git a/setup.py b/setup.py index 7fca04f..f3c1a5c 100644 --- a/setup.py +++ b/setup.py @@ -9,14 +9,14 @@ if '--pure' in sys.argv: sys.argv.remove('--pure') print("Building pure-python wheel") -exec(open("RNS/_version.py", "r").read()) -with open("README.md", "r") as fh: +exec(open("RNS/_version.py").read()) +with open("README.md") as fh: long_description = fh.read() if pure_python: pkg_name = "rnspure" requirements = [] - long_description = long_description.replace("

", "

"+pure_notice) + long_description = long_description.replace("

", f"

{pure_notice}") else: pkg_name = "rns" requirements = ['cryptography>=3.4.7', 'pyserial>=3.5'] diff --git a/tests/channel.py b/tests/channel.py index d74434e..85e7217 100644 --- a/tests/channel.py +++ b/tests/channel.py @@ -145,7 +145,7 @@ class SystemMessage(MessageBase): MSGTYPE = 0xf000 def pack(self) -> bytes: - return bytes() + return b'' def unpack(self, raw): pass @@ -160,7 +160,7 @@ class ProtocolHarness(contextlib.AbstractContextManager): def cleanup(self): self.channel._shutdown() - def __exit__(self, __exc_type: typing.Type[BaseException], __exc_value: BaseException, + def __exit__(self, __exc_type: type[BaseException], __exc_value: BaseException, __traceback: types.TracebackType) -> bool: # self._log.debug(f"__exit__({__exc_type}, {__exc_value}, {__traceback})") self.cleanup() @@ -431,7 +431,7 @@ class TestChannel(unittest.TestCase): self.assertEqual(len(data), count) read_finished = False - result = bytes() + result = b'' def read_thread(): nonlocal read_finished, result diff --git a/tests/hashes.py b/tests/hashes.py index eb9f2e2..0ef349a 100644 --- a/tests/hashes.py +++ b/tests/hashes.py @@ -11,22 +11,22 @@ class TestSHA256(unittest.TestCase): def test_empty(self): self.assertEqual( - self.f(''.encode("utf-8")), + self.f(b''), bytes.fromhex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")) def test_less_than_block_length(self): self.assertEqual( - self.f('abc'.encode("utf-8")), + self.f(b'abc'), bytes.fromhex("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")) def test_block_length(self): self.assertEqual( - self.f('a'.encode("utf-8")*64), + self.f(b'a'*64), bytes.fromhex("ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb")) def test_several_blocks(self): self.assertEqual( - self.f('a'.encode("utf-8")*1000000), + self.f(b'a'*1000000), bytes.fromhex("cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")) def test_random_blocks(self): @@ -49,10 +49,10 @@ class TestSHA256(unittest.TestCase): if (i%1000 == 0): gbytes = round(b/1000000000,3) mbps = round((b*8/1000000)/(time.time()-start), 2) - print(str(i)+" rounds OK, total data: "+str(gbytes)+"GB, "+str(mbps)+"mbps") + print(f"{i} rounds OK, total data: {gbytes}GB, {mbps}mbps") if not ok: - print("Failed at round "+str(i)) + print(f"Failed at round {i}") else: print("SHA-256 test OK") @@ -65,25 +65,25 @@ class TestSHA512(unittest.TestCase): def test_empty(self): self.assertEqual( - self.f(''.encode("utf-8")), + self.f(b''), bytes.fromhex( 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce'+ '47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e')) def test_less_than_block_length(self): - self.assertEqual(self.f('abc'.encode("utf-8")), + self.assertEqual(self.f(b'abc'), bytes.fromhex( 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a'+ '2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')) def test_block_length(self): - self.assertEqual(self.f('a'.encode("utf-8")*128), + self.assertEqual(self.f(b'a'*128), bytes.fromhex( 'b73d1929aa615934e61a871596b3f3b33359f42b8175602e89f7e06e5f658a24'+ '3667807ed300314b95cacdd579f3e33abdfbe351909519a846d465c59582f321')) def test_several_blocks(self): - self.assertEqual(self.f('a'.encode("utf-8")*1000000), + self.assertEqual(self.f(b'a'*1000000), bytes.fromhex( 'e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb'+ 'de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b')) @@ -108,10 +108,10 @@ class TestSHA512(unittest.TestCase): if (i%1000 == 0): gbytes = round(b/1000000000,3) mbps = round((b*8/1000000)/(time.time()-start), 2) - print(str(i)+" rounds OK, total data: "+str(gbytes)+"GB, "+str(mbps)+"mbps") + print(f"{i} rounds OK, total data: {gbytes}GB, {mbps}mbps") if not ok: - print("Failed at round "+str(i)) + print(f"Failed at round {i}") else: print("SHA-512 test OK") diff --git a/tests/identity.py b/tests/identity.py index af9230e..9f66a10 100644 --- a/tests/identity.py +++ b/tests/identity.py @@ -62,8 +62,8 @@ class TestIdentity(unittest.TestCase): tmdev = tmax - tmin mpct = (tmax/tmed)*100 print("Random messages:") - print(" Signature timing min/avg/med/max/mdev: "+str(round(tmin, 3))+"/"+str(round(tmean, 3))+"/"+str(round(tmed, 3))+"/"+str(round(tmax, 3))+"/"+str(round(tmdev, 3))) - print(" Max deviation from median: "+str(round(mpct, 1))+"%") + print(f" Signature timing min/avg/med/max/mdev: {round(tmin, 3)}/{round(tmean, 3)}/{round(tmed, 3)}/{round(tmax, 3)}/{round(tmdev, 3)}") + print(f" Max deviation from median: {round(mpct, 1)}%") print() id1 = RNS.Identity() @@ -85,8 +85,8 @@ class TestIdentity(unittest.TestCase): tmdev = tmax - tmin mpct = (tmax/tmed)*100 print("All 0xff messages:") - print(" Signature timing min/avg/med/max/mdev: "+str(round(tmin, 3))+"/"+str(round(tmean, 3))+"/"+str(round(tmed, 3))+"/"+str(round(tmax, 3))+"/"+str(round(tmdev, 3))) - print(" Max deviation from median: "+str(round(mpct, 1))+"%") + print(f" Signature timing min/avg/med/max/mdev: {round(tmin, 3)}/{round(tmean, 3)}/{round(tmed, 3)}/{round(tmax, 3)}/{round(tmdev, 3)}") + print(f" Max deviation from median: {round(mpct, 1)}%") print() id1 = RNS.Identity() @@ -108,8 +108,8 @@ class TestIdentity(unittest.TestCase): tmdev = tmax - tmin mpct = (tmax/tmed)*100 print("All 0x00 messages:") - print(" Signature timing min/avg/med/max/mdev: "+str(round(tmin, 3))+"/"+str(round(tmean, 3))+"/"+str(round(tmed, 3))+"/"+str(round(tmax, 3))+"/"+str(round(tmdev, 3))) - print(" Max deviation from median: "+str(round(mpct, 1))+"%") + print(f" Signature timing min/avg/med/max/mdev: {round(tmin, 3)}/{round(tmean, 3)}/{round(tmed, 3)}/{round(tmax, 3)}/{round(tmdev, 3)}") + print(f" Max deviation from median: {round(mpct, 1)}%") print() b = 0 @@ -127,7 +127,7 @@ class TestIdentity(unittest.TestCase): self.assertEqual(True, id2.validate(signature, msg)) t += time.time() - start - print("Sign/validate chunks < MTU: "+self.size_str(b/t, "b")+"ps") + print(f"Sign/validate chunks < MTU: {self.size_str(b / t, 'b')}ps") for i in range(1, 500): mlen = 16*1024 @@ -142,7 +142,7 @@ class TestIdentity(unittest.TestCase): self.assertEqual(True, id2.validate(signature, msg)) t += time.time() - start - print("Sign/validate 16KB chunks: "+self.size_str(b/t, "b")+"ps") + print(f"Sign/validate 16KB chunks: {self.size_str(b / t, 'b')}ps") def test_2_encrypt(self): @@ -176,8 +176,8 @@ class TestIdentity(unittest.TestCase): self.assertEqual(msg, decrypted) d_t += time.time() - d_start - print("Encrypt chunks < MTU: "+self.size_str(b/e_t, "b")+"ps") - print("Decrypt chunks < MTU: "+self.size_str(b/d_t, "b")+"ps") + print(f"Encrypt chunks < MTU: {self.size_str(b / e_t, 'b')}ps") + print(f"Decrypt chunks < MTU: {self.size_str(b / d_t, 'b')}ps") print("") # Test encrypt and decrypt of large chunks @@ -203,8 +203,8 @@ class TestIdentity(unittest.TestCase): self.assertEqual(msg, id1.decrypt(token)) d_t += time.time() - d_start - print("Encrypt "+self.size_str(mlen)+" chunks: "+self.size_str(b/e_t, "b")+"ps") - print("Decrypt "+self.size_str(mlen)+" chunks: "+self.size_str(b/d_t, "b")+"ps") + print(f"Encrypt {self.size_str(mlen)} chunks: {self.size_str(b / e_t, 'b')}ps") + print(f"Decrypt {self.size_str(mlen)} chunks: {self.size_str(b / d_t, 'b')}ps") def size_str(self, num, suffix='B'): units = ['','K','M','G','T','P','E','Z'] @@ -218,12 +218,12 @@ class TestIdentity(unittest.TestCase): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/tests/link.py b/tests/link.py index 5cc8ca3..1713df7 100644 --- a/tests/link.py +++ b/tests/link.py @@ -28,7 +28,7 @@ BUFFER_TEST_TARGET = 32000 def targets_job(caller): cmd = "python -c \"from tests.link import targets; targets()\"" - print("Opening subprocess for "+str(cmd)+"...", RNS.LOG_VERBOSE) + print(f"Opening subprocess for {cmd}...", RNS.LOG_VERBOSE) ppath = os.getcwd() try: @@ -144,7 +144,7 @@ class TestLink(unittest.TestCase): packet_size = RNS.Link.MDU pstart = time.time() - print("Sending "+str(num_packets)+" link packets of "+str(packet_size)+" bytes...") + print(f"Sending {num_packets} link packets of {packet_size} bytes...") for i in range(0, num_packets): time.sleep(0.003) b += packet_size @@ -154,7 +154,7 @@ class TestLink(unittest.TestCase): receipts.append(p.send()) pr_t += time.time() - start - print("Sent "+self.size_str(b)+", "+self.size_str(b/pr_t, "b")+"ps") + print(f"Sent {self.size_str(b)}, {self.size_str(b / pr_t, 'b')}ps") print("Checking receipts...", end=" ") all_ok = False @@ -175,11 +175,11 @@ class TestLink(unittest.TestCase): if n_failed > 0: ns = "s" if n_failed != 1 else "" - print("Failed to receive proof for "+str(n_failed)+" packet"+ns) + print(f"Failed to receive proof for {n_failed} packet{ns}") self.assertEqual(all_ok, True) print("OK!") - print("Single packet and proof round-trip throughput is "+self.size_str(b/pduration, "b")+"ps") + print(f"Single packet and proof round-trip throughput is {self.size_str(b / pduration, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -209,7 +209,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 128 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout) start = time.time() @@ -219,7 +219,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(resource.status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -249,7 +249,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 256*1000 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout) start = time.time() @@ -259,7 +259,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(resource.status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -288,7 +288,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 1000*1000 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout) start = time.time() @@ -298,7 +298,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(resource.status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -332,7 +332,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 5*1000*1000 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout) start = time.time() @@ -342,7 +342,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(resource.status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -379,7 +379,7 @@ class TestLink(unittest.TestCase): resource_timeout = 120 resource_size = 50*1000*1000 data = os.urandom(resource_size) - print("Sending "+self.size_str(resource_size)+" resource...") + print(f"Sending {self.size_str(resource_size)} resource...") resource = RNS.Resource(data, l1, timeout=resource_timeout, callback=self.lr_callback) start = time.time() @@ -389,7 +389,7 @@ class TestLink(unittest.TestCase): t = time.time() - start self.assertEqual(TestLink.large_resource_status, RNS.Resource.COMPLETE) - print("Resource completed at "+self.size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {self.size_str(resource_size / t, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -478,7 +478,7 @@ class TestLink(unittest.TestCase): channel = l1.get_channel() buffer = RNS.Buffer.create_bidirectional_buffer(0, 0, channel, handle_data) - buffer.write("Hi there".encode("utf-8")) + buffer.write(b"Hi there") buffer.flush() time.sleep(0.5) @@ -508,7 +508,7 @@ class TestLink(unittest.TestCase): if local_bitrate is not None: local_interface.bitrate = local_bitrate local_interface._force_bitrate = True - print("Forcing local bitrate of " + str(local_bitrate) + " bps (" + str(round(local_bitrate/8, 0)) + " B/s)") + print(f"Forcing local bitrate of {local_bitrate} bps ({round(local_bitrate / 8, 0)} B/s)") # TODO: Load this from public bytes only id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0])) @@ -525,7 +525,7 @@ class TestLink(unittest.TestCase): # delay a reasonable time for link to come up at current bitrate link_sleep = max(RNS.Link.MDU * 3 / local_interface.bitrate * 8, 2) timeout_at = time.time() + link_sleep - print("Waiting " + str(round(link_sleep, 1)) + " sec for link to come up") + print(f"Waiting {round(link_sleep, 1)} sec for link to come up") while l1.status != RNS.Link.ACTIVE and time.time() < timeout_at: time.sleep(0.01) @@ -564,14 +564,14 @@ class TestLink(unittest.TestCase): expected_rx_message = b"" for i in range(0, len(message)): if i > 0 and (i % StreamDataMessage.MAX_DATA_LEN) == 0: - expected_rx_message += " back at you".encode("utf-8") + expected_rx_message += b" back at you" expected_rx_message += bytes([message[i]]) - expected_rx_message += " back at you".encode("utf-8") + expected_rx_message += b" back at you" # since the segments will be received at max length for a # StreamDataMessage, the appended text will end up in a # separate packet. - print("Sending " + str(len(message)) + " bytes, receiving " + str(len(expected_rx_message)) + " bytes, ") + print(f"Sending {len(message)} bytes, receiving {len(expected_rx_message)} bytes, ") buffer.write(message) buffer.flush() @@ -621,12 +621,12 @@ class TestLink(unittest.TestCase): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) + return f"{num:.2f}{last_unit}{suffix}" if __name__ == '__main__': unittest.main(verbosity=1) @@ -650,16 +650,16 @@ def targets(yp=False): threads = yappi.get_thread_stats() for thread in threads: print( - "Function stats for (%s) (%d)" % (thread.name, thread.id) + f"Function stats for ({thread.name}) ({int(thread.id)})" ) # it is the Thread.__class__.__name__ - yappi.get_func_stats(ctx_id=thread.id).save("receiver_thread_"+str(thread.id)+".data", type="pstat") + yappi.get_func_stats(ctx_id=thread.id).save(f"receiver_thread_{thread.id}.data", type="pstat") except Exception as e: - print("Error: "+str(e)) + print(f"Error: {e}") if hasattr(resource.link.attached_interface, "rxptime"): rx_pr = (resource.link.attached_interface.rxb*8)/resource.link.attached_interface.rxptime - print("Average RX proccessing rate: "+size_str(rx_pr, "b")+"ps") + print(f"Average RX proccessing rate: {size_str(rx_pr, 'b')}ps") def link_established(link): print("Link established") @@ -670,7 +670,7 @@ def targets(yp=False): def handle_message(message): if isinstance(message, MessageTest): - message.data = message.data + " back" + message.data = f"{message.data} back" channel.send(message) channel.register_message_type(MessageTest) @@ -685,17 +685,17 @@ def targets(yp=False): buffer_read_len += len(data) response_data.append(data) - if data == "Hi there".encode("utf-8"): + if data == b"Hi there": RNS.log("Sending response") for data in response_data: - buffer.write(data + " back at you".encode("utf-8")) + buffer.write(data + b" back at you") buffer.flush() buffer_read_len = 0 if buffer_read_len == BUFFER_TEST_TARGET: RNS.log("Sending response") for data in response_data: - buffer.write(data + " back at you".encode("utf-8")) + buffer.write(data + b" back at you") buffer.flush() buffer_read_len = 0 @@ -745,7 +745,7 @@ def resource_profiling(): resource_timeout = 120 resource_size = 5*1000*1000 data = os.urandom(resource_size) - print("Sending "+size_str(resource_size)+" resource...") + print(f"Sending {size_str(resource_size)} resource...") import yappi yappi.start() @@ -759,22 +759,22 @@ def resource_profiling(): time.sleep(0.01) t = time.time() - start - print("Resource completed at "+size_str(resource_size/t, "b")+"ps") + print(f"Resource completed at {size_str(resource_size / t, 'b')}ps") yappi.get_func_stats().save("sender_main_calls.data", type="pstat") threads = yappi.get_thread_stats() for thread in threads: print( - "Function stats for (%s) (%d)" % (thread.name, thread.id) + f"Function stats for ({thread.name}) ({int(thread.id)})" ) # it is the Thread.__class__.__name__ - yappi.get_func_stats(ctx_id=thread.id).save("sender_thread_"+str(thread.id)+".data", type="pstat") + yappi.get_func_stats(ctx_id=thread.id).save(f"sender_thread_{thread.id}.data", type="pstat") # t_pstats = yappi.convert2pstats(tstats) # t_pstats.save("resource_tstat.data", type="pstat") if hasattr(resource.link.attached_interface, "rxptime"): rx_pr = (resource.link.attached_interface.rxb*8)/resource.link.attached_interface.rxptime - print("Average RX proccessing rate: "+size_str(rx_pr, "b")+"ps") + print(f"Average RX proccessing rate: {size_str(rx_pr, 'b')}ps") l1.teardown() time.sleep(0.5) @@ -791,9 +791,9 @@ def size_str(num, suffix='B'): for unit in units: if abs(num) < 1000.0: if unit == "": - return "%.0f %s%s" % (num, unit, suffix) + return f"{num:.0f} {unit}{suffix}" else: - return "%.2f %s%s" % (num, unit, suffix) + return f"{num:.2f} {unit}{suffix}" num /= 1000.0 - return "%.2f%s%s" % (num, last_unit, suffix) \ No newline at end of file + return f"{num:.2f}{last_unit}{suffix}" \ No newline at end of file From 86d4028dc465cbfd7c9e67d531dcdb3a352742bd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Oct 2024 10:52:43 +0200 Subject: [PATCH 2/2] remove dangling spaces --- Changelog.md | 2 +- Examples/Announce.py | 6 +- Examples/Broadcast.py | 4 +- Examples/Buffer.py | 6 +- Examples/Channel.py | 6 +- Examples/Echo.py | 20 +- Examples/Filetransfer.py | 20 +- Examples/Identify.py | 6 +- Examples/Link.py | 8 +- Examples/Minimal.py | 4 +- Examples/Ratchets.py | 20 +- Examples/Request.py | 6 +- Examples/Speedtest.py | 12 +- README.md | 18 +- RNS/Buffer.py | 2 +- RNS/Channel.py | 24 +- RNS/Cryptography/AES.py | 4 +- RNS/Cryptography/Fernet.py | 2 +- RNS/Cryptography/SHA256.py | 38 +-- RNS/Cryptography/X25519.py | 6 +- RNS/Cryptography/aes/aes.py | 10 +- RNS/Destination.py | 8 +- RNS/Identity.py | 24 +- RNS/Interfaces/AX25KISSInterface.py | 4 +- RNS/Interfaces/Android/KISSInterface.py | 12 +- RNS/Interfaces/Android/RNodeInterface.py | 54 +-- RNS/Interfaces/Android/SerialInterface.py | 14 +- RNS/Interfaces/AutoInterface.py | 16 +- RNS/Interfaces/I2PInterface.py | 50 +-- RNS/Interfaces/Interface.py | 6 +- RNS/Interfaces/KISSInterface.py | 8 +- RNS/Interfaces/LocalInterface.py | 18 +- RNS/Interfaces/PipeInterface.py | 14 +- RNS/Interfaces/RNodeInterface.py | 36 +- RNS/Interfaces/RNodeMultiInterface.py | 30 +- RNS/Interfaces/SerialInterface.py | 12 +- RNS/Interfaces/TCPInterface.py | 30 +- RNS/Interfaces/UDPInterface.py | 2 +- RNS/Link.py | 32 +- RNS/Packet.py | 18 +- RNS/Resolver.py | 2 +- RNS/Resource.py | 42 +-- RNS/Reticulum.py | 50 +-- RNS/Transport.py | 82 ++--- RNS/Utilities/rncp.py | 18 +- RNS/Utilities/rnid.py | 22 +- RNS/Utilities/rnir.py | 2 +- RNS/Utilities/rnodeconf.py | 56 ++-- RNS/Utilities/rnpath.py | 16 +- RNS/Utilities/rnprobe.py | 12 +- RNS/Utilities/rnsd.py | 26 +- RNS/Utilities/rnstatus.py | 28 +- RNS/Utilities/rnx.py | 18 +- RNS/__init__.py | 20 +- RNS/vendor/configobj.py | 382 +++++++++++----------- RNS/vendor/i2plib/__init__.py | 4 +- RNS/vendor/i2plib/aiosam.py | 42 +-- RNS/vendor/i2plib/sam.py | 20 +- RNS/vendor/i2plib/tunnel.py | 40 +-- tests/channel.py | 2 +- tests/identity.py | 2 +- tests/link.py | 28 +- 62 files changed, 763 insertions(+), 763 deletions(-) diff --git a/Changelog.md b/Changelog.md index d36671f..5d3bc78 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1214,7 +1214,7 @@ This beta release brings a range of improvements and bugfixes. - Improved documentation. - Improved request timeouts and handling. - Improved link establishment. - - Improved resource transfer timing. + - Improved resource transfer timing. **Fixed bugs** - Fixed a race condition in inbound proof handling. diff --git a/Examples/Announce.py b/Examples/Announce.py index 5b0a3af..c5a2e3c 100644 --- a/Examples/Announce.py +++ b/Examples/Announce.py @@ -22,7 +22,7 @@ noble_gases = ["Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon", "Oganesso def program_setup(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our example identity = RNS.Identity() @@ -70,7 +70,7 @@ def program_setup(configpath): # We register the announce handler with Reticulum RNS.Transport.register_announce_handler(announce_handler) - + # Everything's ready! # Let's hand over control to the announce loop announceLoop(destination_1, destination_2) @@ -86,7 +86,7 @@ def announceLoop(destination_1, destination_2): # know how to create messages directed towards it. while True: entered = input() - + # Randomly select a fruit fruit = fruits[random.randint(0,len(fruits)-1)] diff --git a/Examples/Broadcast.py b/Examples/Broadcast.py index 423d759..1d752d3 100644 --- a/Examples/Broadcast.py +++ b/Examples/Broadcast.py @@ -17,7 +17,7 @@ APP_NAME = "example_utilities" def program_setup(configpath, channel=None): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # If the user did not select a "channel" we use # a default one called "public_information". # This "channel" is added to the destination name- @@ -40,7 +40,7 @@ def program_setup(configpath, channel=None): # We specify a callback that will get called every time # the destination receives data. broadcast_destination.set_packet_callback(packet_callback) - + # Everything's ready! # Let's hand over control to the main loop broadcastLoop(broadcast_destination) diff --git a/Examples/Buffer.py b/Examples/Buffer.py index 7d26ce1..edf0615 100644 --- a/Examples/Buffer.py +++ b/Examples/Buffer.py @@ -35,7 +35,7 @@ latest_buffer = None def server(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our example server_identity = RNS.Identity() @@ -151,7 +151,7 @@ def client(destination_hexhash, configpath): raise ValueError( f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) - + destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") @@ -251,7 +251,7 @@ def link_closed(link): RNS.log("The link was closed by the server, exiting now") else: RNS.log("Link closed, exiting now") - + RNS.Reticulum.exit_handler() time.sleep(1.5) os._exit(0) diff --git a/Examples/Channel.py b/Examples/Channel.py index b1c6b39..6f475d2 100644 --- a/Examples/Channel.py +++ b/Examples/Channel.py @@ -98,7 +98,7 @@ latest_client_link = None def server(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our link example server_identity = RNS.Identity() @@ -206,7 +206,7 @@ def client(destination_hexhash, configpath): raise ValueError( f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) - + destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") @@ -315,7 +315,7 @@ def link_closed(link): RNS.log("The link was closed by the server, exiting now") else: RNS.log("Link closed, exiting now") - + RNS.Reticulum.exit_handler() time.sleep(1.5) os._exit(0) diff --git a/Examples/Echo.py b/Examples/Echo.py index ed377b2..0d020dc 100644 --- a/Examples/Echo.py +++ b/Examples/Echo.py @@ -26,7 +26,7 @@ def server(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our echo server server_identity = RNS.Identity() @@ -35,7 +35,7 @@ def server(configpath): # create a "single" destination that can receive encrypted # messages. This way the client can send a request and be # certain that no-one else than this destination was able - # to read it. + # to read it. echo_destination = RNS.Destination( server_identity, RNS.Destination.IN, @@ -50,7 +50,7 @@ def server(configpath): # generate a proof for each incoming packet and transmit it # back to the sender of that packet. echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) - + # Tell the destination which function in our program to # run when a packet is received. We do this so we can # print a log message when the server receives a request @@ -79,7 +79,7 @@ def announceLoop(destination): def server_callback(message, packet): global reticulum - + # Tell the user that we received an echo request, and # that we are going to send a reply to the requester. # Sending the proof is handled automatically, since we @@ -92,14 +92,14 @@ def server_callback(message, packet): if reception_rssi != None: reception_stats += f" [RSSI {reception_rssi} dBm]" - + if reception_snr != None: reception_stats += f" [SNR {reception_snr} dBm]" else: if packet.rssi != None: reception_stats += f" [RSSI {packet.rssi} dBm]" - + if packet.snr != None: reception_stats += f" [SNR {packet.snr} dB]" @@ -114,7 +114,7 @@ def server_callback(message, packet): # to run as a client def client(destination_hexhash, configpath, timeout=None): global reticulum - + # We need a binary representation of the destination # hash that was entered on the command line try: @@ -149,7 +149,7 @@ def client(destination_hexhash, configpath, timeout=None): # command line. while True: input() - + # Let's first check if RNS knows a path to the destination. # If it does, we'll load the server identity and create a packet if RNS.Transport.has_path(destination_hash): @@ -230,7 +230,7 @@ def packet_delivered(receipt): if reception_rssi != None: reception_stats += f" [RSSI {reception_rssi} dBm]" - + if reception_snr != None: reception_stats += f" [SNR {reception_snr} dB]" @@ -238,7 +238,7 @@ def packet_delivered(receipt): if receipt.proof_packet != None: if receipt.proof_packet.rssi != None: reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" - + if receipt.proof_packet.snr != None: reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" diff --git a/Examples/Filetransfer.py b/Examples/Filetransfer.py index 79081d1..f58eac1 100644 --- a/Examples/Filetransfer.py +++ b/Examples/Filetransfer.py @@ -44,7 +44,7 @@ serve_path = None def server(configpath, path): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our file server server_identity = RNS.Identity() @@ -120,7 +120,7 @@ def client_connected(link): RNS.log("Too many files in served directory!", RNS.LOG_ERROR) RNS.log("You should implement a function to split the filelist over multiple packets.", RNS.LOG_ERROR) RNS.log("Hint: The client already supports it :)", RNS.LOG_ERROR) - + # After this, we're just going to keep the link # open until the client requests a file. We'll # configure a function that get's called when @@ -147,7 +147,7 @@ def client_request(message, packet): # read it and pack it as a resource RNS.log(f"Client requested \"{filename}\"") file = open(os.path.join(serve_path, filename), "rb") - + file_resource = RNS.Resource( file, packet.link, @@ -220,7 +220,7 @@ def client(destination_hexhash, configpath): raise ValueError( f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) - + destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") @@ -291,7 +291,7 @@ def download(filename): # packet receipt. request_packet = RNS.Packet(server_link, filename.encode("utf-8"), create_receipt=False) request_packet.send() - + print("") print(f"Requested \"{filename}\" from server, waiting for download to begin...") menu_mode = "download_started" @@ -474,7 +474,7 @@ def link_closed(link): RNS.log("The link was closed by the server, exiting now") else: RNS.log("Link closed, exiting now") - + RNS.Reticulum.exit_handler() time.sleep(1.5) os._exit(0) @@ -486,17 +486,17 @@ def link_closed(link): def download_began(resource): global menu_mode, current_download, download_started, transfer_size, file_size current_download = resource - + if download_started == 0: download_started = time.time() - + transfer_size += resource.size file_size = resource.total_size - + menu_mode = "downloading" # When the download concludes, successfully -# or not, we'll update our menu state and +# or not, we'll update our menu state and # inform the user about how it all went. def download_concluded(resource): global menu_mode, current_filename, download_started, download_finished, download_time diff --git a/Examples/Identify.py b/Examples/Identify.py index 6bfa49d..deddc0a 100644 --- a/Examples/Identify.py +++ b/Examples/Identify.py @@ -27,7 +27,7 @@ latest_client_link = None def server(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our link example server_identity = RNS.Identity() @@ -99,7 +99,7 @@ def server_packet_received(message, packet): text = message.decode("utf-8") RNS.log(f"Received data from {remote_peer}: {text}") - + reply_text = f"I received \"{text}\" over the link from {remote_peer}" reply_data = reply_text.encode("utf-8") RNS.Packet(latest_client_link, reply_data).send() @@ -239,7 +239,7 @@ def link_closed(link): RNS.log("The link was closed by the server, exiting now") else: RNS.log("Link closed, exiting now") - + RNS.Reticulum.exit_handler() time.sleep(1.5) os._exit(0) diff --git a/Examples/Link.py b/Examples/Link.py index 6df8f3e..b3e5966 100644 --- a/Examples/Link.py +++ b/Examples/Link.py @@ -27,7 +27,7 @@ latest_client_link = None def server(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our link example server_identity = RNS.Identity() @@ -89,7 +89,7 @@ def server_packet_received(message, packet): # that connected. text = message.decode("utf-8") RNS.log(f"Received data on the link: {text}") - + reply_text = f"I received \"{text}\" over the link" reply_data = reply_text.encode("utf-8") RNS.Packet(latest_client_link, reply_data).send() @@ -113,7 +113,7 @@ def client(destination_hexhash, configpath): raise ValueError( f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) - + destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") @@ -217,7 +217,7 @@ def link_closed(link): RNS.log("The link was closed by the server, exiting now") else: RNS.log("Link closed, exiting now") - + RNS.Reticulum.exit_handler() time.sleep(1.5) os._exit(0) diff --git a/Examples/Minimal.py b/Examples/Minimal.py index 6f33893..3f7558f 100644 --- a/Examples/Minimal.py +++ b/Examples/Minimal.py @@ -17,7 +17,7 @@ APP_NAME = "example_utilities" def program_setup(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our example identity = RNS.Identity() @@ -42,7 +42,7 @@ def program_setup(configpath): # tries to communicate with the destination know whether their # communication was received correctly. destination.set_proof_strategy(RNS.Destination.PROVE_ALL) - + # Everything's ready! # Let's hand over control to the announce loop announceLoop(destination) diff --git a/Examples/Ratchets.py b/Examples/Ratchets.py index b690de4..1623990 100644 --- a/Examples/Ratchets.py +++ b/Examples/Ratchets.py @@ -28,7 +28,7 @@ def server(configpath): # TODO: Remove RNS.loglevel = RNS.LOG_DEBUG - + # Randomly create a new identity for our echo server server_identity = RNS.Identity() @@ -37,7 +37,7 @@ def server(configpath): # create a "single" destination that can receive encrypted # messages. This way the client can send a request and be # certain that no-one else than this destination was able - # to read it. + # to read it. echo_destination = RNS.Destination( server_identity, RNS.Destination.IN, @@ -61,7 +61,7 @@ def server(configpath): # generate a proof for each incoming packet and transmit it # back to the sender of that packet. echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) - + # Tell the destination which function in our program to # run when a packet is received. We do this so we can # print a log message when the server receives a request @@ -90,7 +90,7 @@ def announceLoop(destination): def server_callback(message, packet): global reticulum - + # Tell the user that we received an echo request, and # that we are going to send a reply to the requester. # Sending the proof is handled automatically, since we @@ -103,14 +103,14 @@ def server_callback(message, packet): if reception_rssi != None: reception_stats += f" [RSSI {reception_rssi} dBm]" - + if reception_snr != None: reception_stats += f" [SNR {reception_snr} dBm]" else: if packet.rssi != None: reception_stats += f" [RSSI {packet.rssi} dBm]" - + if packet.snr != None: reception_stats += f" [SNR {packet.snr} dB]" @@ -125,7 +125,7 @@ def server_callback(message, packet): # to run as a client def client(destination_hexhash, configpath, timeout=None): global reticulum - + # We need a binary representation of the destination # hash that was entered on the command line try: @@ -160,7 +160,7 @@ def client(destination_hexhash, configpath, timeout=None): # command line. while True: input() - + # Let's first check if RNS knows a path to the destination. # If it does, we'll load the server identity and create a packet if RNS.Transport.has_path(destination_hash): @@ -242,7 +242,7 @@ def packet_delivered(receipt): if reception_rssi != None: reception_stats += f" [RSSI {reception_rssi} dBm]" - + if reception_snr != None: reception_stats += f" [SNR {reception_snr} dB]" @@ -250,7 +250,7 @@ def packet_delivered(receipt): if receipt.proof_packet != None: if receipt.proof_packet.rssi != None: reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" - + if receipt.proof_packet.snr != None: reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" diff --git a/Examples/Request.py b/Examples/Request.py index 774fe2e..acd016a 100644 --- a/Examples/Request.py +++ b/Examples/Request.py @@ -33,7 +33,7 @@ def random_text_generator(path, data, request_id, link_id, remote_identity, requ def server(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our link example server_identity = RNS.Identity() @@ -113,7 +113,7 @@ def client(destination_hexhash, configpath): raise ValueError( f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) - + destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") @@ -223,7 +223,7 @@ def link_closed(link): RNS.log("The link was closed by the server, exiting now") else: RNS.log("Link closed, exiting now") - + RNS.Reticulum.exit_handler() time.sleep(1.5) os._exit(0) diff --git a/Examples/Speedtest.py b/Examples/Speedtest.py index 4e564f0..be7650c 100644 --- a/Examples/Speedtest.py +++ b/Examples/Speedtest.py @@ -36,7 +36,7 @@ printed = False def server(configpath): # We must first initialise Reticulum reticulum = RNS.Reticulum(configpath) - + # Randomly create a new identity for our link example server_identity = RNS.Identity() @@ -113,9 +113,9 @@ def size_str(num, suffix='B'): def server_packet_received(message, packet): global latest_client_link, first_packet_at, last_packet_at, received_data, rc, data_cap - + received_data += len(packet.data) - + rc += 1 if rc >= 50: RNS.log(size_str(received_data)) @@ -127,7 +127,7 @@ def server_packet_received(message, packet): rc = 0 last_packet_at = time.time() - + # Print statistics download_time = last_packet_at-first_packet_at hours, rem = divmod(download_time, 3600) @@ -169,7 +169,7 @@ def client(destination_hexhash, configpath): raise ValueError( f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." ) - + destination_hash = bytes.fromhex(destination_hexhash) except: RNS.log("Invalid destination entered. Check your input!\n") @@ -280,7 +280,7 @@ def link_closed(link): RNS.log("The link was closed by the server, exiting now") else: RNS.log("Link closed, exiting now") - + RNS.Reticulum.exit_handler() time.sleep(1.5) diff --git a/README.md b/README.md index 0c55bcc..6866f3e 100755 --- a/README.md +++ b/README.md @@ -109,8 +109,8 @@ network, and vice versa. ## How do I get started? The best way to get started with the Reticulum Network Stack depends on what -you want to do. For full details and examples, have a look at the -[Getting Started Fast](https://markqvist.github.io/Reticulum/manual/gettingstartedfast.html) +you want to do. For full details and examples, have a look at the +[Getting Started Fast](https://markqvist.github.io/Reticulum/manual/gettingstartedfast.html) section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/). To simply install Reticulum and related utilities on your system, the easiest way is via `pip`. @@ -143,15 +143,15 @@ creating a more complex configuration. If you have an old version of `pip` on your system, you may need to upgrade it first with `pip install pip --upgrade`. If you no not already have `pip` installed, you can install it using the package manager of your system with `sudo apt install python3-pip` or similar. -For more detailed examples on how to expand communication over many mediums such -as packet radio or LoRa, serial ports, or over fast IP links and the Internet using -the UDP and TCP interfaces, take a look at the [Supported Interfaces](https://markqvist.github.io/Reticulum/manual/interfaces.html) +For more detailed examples on how to expand communication over many mediums such +as packet radio or LoRa, serial ports, or over fast IP links and the Internet using +the UDP and TCP interfaces, take a look at the [Supported Interfaces](https://markqvist.github.io/Reticulum/manual/interfaces.html) section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/). ## Included Utilities -Reticulum includes a range of useful utilities for managing your networks, -viewing status and information, and other tasks. You can read more about these -programs in the [Included Utility Programs](https://markqvist.github.io/Reticulum/manual/using.html#included-utility-programs) +Reticulum includes a range of useful utilities for managing your networks, +viewing status and information, and other tasks. You can read more about these +programs in the [Included Utility Programs](https://markqvist.github.io/Reticulum/manual/using.html#included-utility-programs) section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/). - The system daemon `rnsd` for running Reticulum as an always-available service @@ -242,7 +242,7 @@ The testnet is just that, an informal network for testing and experimenting. It will be up most of the time, and anyone can join, but it also means that there's no guarantees for service availability. -It probably goes without saying, but *don't use the testnet entry-points as +It probably goes without saying, but *don't use the testnet entry-points as hardcoded or default interfaces in any applications you ship to users*. When shipping applications, the best practice is to provide your own default connectivity solutions, if needed and applicable, or in most cases, simply diff --git a/RNS/Buffer.py b/RNS/Buffer.py index f260c16..eb0b0e9 100644 --- a/RNS/Buffer.py +++ b/RNS/Buffer.py @@ -244,7 +244,7 @@ class RawChannelWriter(RawIOBase, AbstractContextManager): processed_length = len(chunk) message = StreamDataMessage(self._stream_id, chunk, self._eof, comp_success) - + self._channel.send(message) return processed_length diff --git a/RNS/Channel.py b/RNS/Channel.py index 5634471..d2a81fe 100644 --- a/RNS/Channel.py +++ b/RNS/Channel.py @@ -136,7 +136,7 @@ class MessageBase(abc.ABC): MSGTYPE = None """ Defines a unique identifier for a message class. - + * Must be unique within all classes registered with a ``Channel`` * Must be less than ``0xf000``. Values greater than or equal to ``0xf000`` are reserved. """ @@ -247,11 +247,11 @@ class Channel(contextlib.AbstractContextManager): # The maximum window size for transfers on fast links WINDOW_MAX_FAST = 48 - + # For calculating maps and guard segments, this # must be set to the global maximum window. WINDOW_MAX = WINDOW_MAX_FAST - + # If the fast rate is sustained for this many request # rounds, the fast link window size will be allowed. FAST_RATE_THRESHOLD = 10 @@ -380,21 +380,21 @@ class Channel(contextlib.AbstractContextManager): def _emplace_envelope(self, envelope: Envelope, ring: collections.deque[Envelope]) -> bool: with self._lock: i = 0 - + for existing in ring: if envelope.sequence == existing.sequence: RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence {envelope.sequence}", RNS.LOG_EXTREME) return False - + if envelope.sequence < existing.sequence and not (self._next_rx_sequence - envelope.sequence) > (Channel.SEQ_MAX//2): ring.insert(i, envelope) envelope.tracked = True return True - + i += 1 - + envelope.tracked = True ring.append(envelope) @@ -449,7 +449,7 @@ class Channel(contextlib.AbstractContextManager): m = e.unpack(self._message_factories) else: m = e.message - + self._rx_ring.remove(e) self._run_callbacks(m) @@ -468,7 +468,7 @@ class Channel(contextlib.AbstractContextManager): with self._lock: outstanding = 0 for envelope in self._tx_ring: - if envelope.outlet == self._outlet: + if envelope.outlet == self._outlet: if not envelope.packet or not self._outlet.get_packet_state(envelope.packet) == MessageState.MSGSTATE_DELIVERED: outstanding += 1 @@ -508,7 +508,7 @@ class Channel(contextlib.AbstractContextManager): # TODO: Remove at some point # RNS.log("Increased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_DEBUG) # RNS.log("Increased "+str(self)+" min window to "+str(self.window_min), RNS.LOG_DEBUG) - + else: self.fast_rate_rounds += 1 if self.window_max < Channel.WINDOW_MAX_FAST and self.fast_rate_rounds == Channel.FAST_RATE_THRESHOLD: @@ -581,7 +581,7 @@ class Channel(contextlib.AbstractContextManager): with self._lock: if not self.is_ready_to_send(): raise ChannelException(CEType.ME_LINK_NOT_READY, f"Link is not ready") - + envelope = Envelope(self._outlet, message=message, sequence=self._next_sequence) self._next_sequence = (self._next_sequence + 1) % Channel.SEQ_MODULUS self._emplace_envelope(envelope, self._tx_ring) @@ -592,7 +592,7 @@ class Channel(contextlib.AbstractContextManager): envelope.pack() if len(envelope.raw) > self._outlet.mdu: raise ChannelException(CEType.ME_TOO_BIG, f"Packed message too big for packet: {len(envelope.raw)} > {self._outlet.mdu}") - + envelope.packet = self._outlet.send(envelope.raw) envelope.tries += 1 self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered) diff --git a/RNS/Cryptography/AES.py b/RNS/Cryptography/AES.py index caca7d6..9e934ad 100644 --- a/RNS/Cryptography/AES.py +++ b/RNS/Cryptography/AES.py @@ -25,7 +25,7 @@ import RNS.vendor.platformutils as pu if cp.PROVIDER == cp.PROVIDER_INTERNAL: from .aes import AES - + elif cp.PROVIDER == cp.PROVIDER_PYCA: from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes @@ -46,7 +46,7 @@ class AES_128_CBC: cipher = Cipher(algorithms.AES(key), modes.CBC(iv)) else: cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) - + encryptor = cipher.encryptor() ciphertext = encryptor.update(plaintext) + encryptor.finalize() return ciphertext diff --git a/RNS/Cryptography/Fernet.py b/RNS/Cryptography/Fernet.py index 0ce843c..818a406 100644 --- a/RNS/Cryptography/Fernet.py +++ b/RNS/Cryptography/Fernet.py @@ -49,7 +49,7 @@ class Fernet(): if len(key) != 32: raise ValueError(f"Token key must be 32 bytes, not {len(key)}") - + self._signing_key = key[:16] self._encryption_key = key[16:] diff --git a/RNS/Cryptography/SHA256.py b/RNS/Cryptography/SHA256.py index 03f22a4..304d67d 100644 --- a/RNS/Cryptography/SHA256.py +++ b/RNS/Cryptography/SHA256.py @@ -48,34 +48,34 @@ class sha256: _h = (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19) _output_size = 8 - + blocksize = 1 block_size = 64 digest_size = 32 - - def __init__(self, m=None): + + def __init__(self, m=None): self._buffer = b"" self._counter = 0 - + if m is not None: if type(m) is not bytes: raise TypeError(f'{self.__class__.__name__}() argument 1 must be bytes, not {type(m).__name__}') self.update(m) - + def _rotr(self, x, y): return ((x >> y) | (x << (32-y))) & 0xFFFFFFFF - + def _sha256_process(self, c): w = [0]*64 w[0:16] = struct.unpack('!16L', c) - + for i in range(16, 64): s0 = self._rotr(w[i-15], 7) ^ self._rotr(w[i-15], 18) ^ (w[i-15] >> 3) s1 = self._rotr(w[i-2], 17) ^ self._rotr(w[i-2], 19) ^ (w[i-2] >> 10) w[i] = (w[i-16] + s0 + w[i-7] + s1) & 0xFFFFFFFF - + a,b,c,d,e,f,g,h = self._h - + for i in range(64): s0 = self._rotr(a, 2) ^ self._rotr(a, 13) ^ self._rotr(a, 22) maj = (a & b) ^ (a & c) ^ (b & c) @@ -83,7 +83,7 @@ class sha256: s1 = self._rotr(e, 6) ^ self._rotr(e, 11) ^ self._rotr(e, 25) ch = (e & f) ^ ((~e) & g) t1 = h + s1 + ch + self._k[i] + w[i] - + h = g g = f f = e @@ -92,38 +92,38 @@ class sha256: c = b b = a a = (t1 + t2) & 0xFFFFFFFF - + self._h = [(x+y) & 0xFFFFFFFF for x,y in zip(self._h, [a,b,c,d,e,f,g,h])] - + def update(self, m): if not m: return if type(m) is not bytes: raise TypeError(f'{sys._getframe().f_code.co_name}() argument 1 must be bytes, not {type(m).__name__}') - + self._buffer += m self._counter += len(m) - + while len(self._buffer) >= 64: self._sha256_process(self._buffer[:64]) self._buffer = self._buffer[64:] - + def digest(self): mdi = self._counter & 0x3F length = struct.pack('!Q', self._counter<<3) - + if mdi < 56: padlen = 55-mdi else: padlen = 119-mdi - + r = self.copy() r.update(b'\x80'+(b'\x00'*padlen)+length) return b''.join([struct.pack('!L', i) for i in r._h[:self._output_size]]) - + def hexdigest(self): return self.digest().encode('hex') - + def copy(self): return copy.deepcopy(self) diff --git a/RNS/Cryptography/X25519.py b/RNS/Cryptography/X25519.py index 813f258..58022a7 100644 --- a/RNS/Cryptography/X25519.py +++ b/RNS/Cryptography/X25519.py @@ -138,9 +138,9 @@ class X25519PrivateKey: peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key) start = time.time() - + shared = _pack_number(_raw_curve25519(peer_public_key.x, self.a)) - + end = time.time() duration = end-start @@ -150,7 +150,7 @@ class X25519PrivateKey: if end > X25519PrivateKey.T_CLEAR: X25519PrivateKey.T_CLEAR = end + X25519PrivateKey.DELAY_WINDOW X25519PrivateKey.T_MAX = 0 - + if duration < X25519PrivateKey.T_MAX or duration < X25519PrivateKey.MIN_EXEC_TIME: target = start+X25519PrivateKey.T_MAX diff --git a/RNS/Cryptography/aes/aes.py b/RNS/Cryptography/aes/aes.py index 4b8e45e..bc15959 100644 --- a/RNS/Cryptography/aes/aes.py +++ b/RNS/Cryptography/aes/aes.py @@ -144,7 +144,7 @@ class AES: return matrix2bytes(state) - # will encrypt the entire data + # will encrypt the entire data def encrypt(self, plaintext, iv): """ Encrypts `plaintext` using CBC mode and PKCS#7 padding, with the given @@ -173,7 +173,7 @@ class AES: return b''.join(ciphertext_blocks) - # will decrypt the entire data + # will decrypt the entire data def decrypt(self, ciphertext, iv): """ Decrypts `ciphertext` using CBC mode and PKCS#7 padding, with the given @@ -188,7 +188,7 @@ class AES: for ciphertext_block in split_blocks(ciphertext): # in CBC mode every block is XOR'd with the previous block xorred = xor_bytes(previous, self._decrypt_block(ciphertext_block)) - + # append plaintext plaintext_blocks.append(xorred) previous = ciphertext_block @@ -223,7 +223,7 @@ def test(): print("Single Block Tests") print("------------------") print(f"iv: {iv.hex()}") - + print(f"plain text: '{single_block_text.decode()}'") ciphertext_block = _aes._encrypt_block(single_block_text) plaintext_block = _aes._decrypt_block(ciphertext_block) @@ -268,4 +268,4 @@ def test(): if __name__ == "__main__": # test AES class - test() + test() diff --git a/RNS/Destination.py b/RNS/Destination.py index 68d854c..3904039 100755 --- a/RNS/Destination.py +++ b/RNS/Destination.py @@ -140,7 +140,7 @@ class Destination: def __init__(self, identity, direction, type, app_name, *aspects): # Check input values and build name string - if "." in app_name: raise ValueError("Dots can't be used in app names") + if "." in app_name: raise ValueError("Dots can't be used in app names") if not type in Destination.types: raise ValueError("Unknown destination type") if not direction in Destination.directions: raise ValueError("Unknown destination direction") @@ -241,7 +241,7 @@ class Destination: if self.direction != Destination.IN: raise TypeError("Only IN destination types can be announced") - + ratchet = b"" now = time.time() stale_responses = [] @@ -264,7 +264,7 @@ class Destination: # multiple available paths, and to choose the best one. RNS.log(f"Using cached announce data for answering path request with tag {RNS.prettyhexrep(tag)}", RNS.LOG_EXTREME) announce_data = self.path_responses[tag][1] - + else: destination_hash = self.hash random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big") @@ -281,7 +281,7 @@ class Destination: returned_app_data = self.default_app_data() if isinstance(returned_app_data, bytes): app_data = returned_app_data - + signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash+ratchet if app_data != None: signed_data += app_data diff --git a/RNS/Identity.py b/RNS/Identity.py index a1cc638..3cc520b 100644 --- a/RNS/Identity.py +++ b/RNS/Identity.py @@ -137,7 +137,7 @@ class Identity: # save, but the only changes. It might be possible to # simply overwrite on exit now that every local client # disconnect triggers a data persist. - + try: if hasattr(Identity, "saving_known_destinations"): wait_interval = 0.2 @@ -279,7 +279,7 @@ class Identity: ratchet_data = {"ratchet": ratchet, "received": time.time()} ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets" - + if not os.path.isdir(ratchetdir): os.makedirs(ratchetdir) @@ -290,7 +290,7 @@ class Identity: ratchet_file.close() os.replace(outpath, finalpath) - + threading.Thread(target=persist_job, daemon=True).start() except Exception as e: @@ -337,7 +337,7 @@ class Identity: Identity.known_ratchets[destination_hash] = ratchet_data["ratchet"] else: return None - + except Exception as e: RNS.log(f"An error occurred while loading ratchet data for {RNS.prettyhexrep(destination_hash)} from storage.", RNS.LOG_ERROR) RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) @@ -444,7 +444,7 @@ class Identity: RNS.log(f"Received invalid announce for {RNS.prettyhexrep(destination_hash)}: Invalid signature.", RNS.LOG_DEBUG) del announced_identity return False - + except Exception as e: RNS.log(f"Error occurred while validating announce. The contained exception was: {e}", RNS.LOG_ERROR) return False @@ -567,7 +567,7 @@ class Identity: self.prv = X25519PrivateKey.from_private_bytes(self.prv_bytes) self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:] self.sig_prv = Ed25519PrivateKey.from_private_bytes(self.sig_prv_bytes) - + self.pub = self.prv.public_key() self.pub_bytes = self.pub.public_bytes() @@ -640,7 +640,7 @@ class Identity: target_public_key = self.pub shared_key = ephemeral_key.exchange(target_public_key) - + derived_key = RNS.Cryptography.hkdf( length=32, derive_from=shared_key, @@ -690,9 +690,9 @@ class Identity: plaintext = fernet.decrypt(ciphertext) if ratchet_id_receiver: ratchet_id_receiver.latest_ratchet_id = ratchet_id - + break - + except Exception as e: pass @@ -720,7 +720,7 @@ class Identity: RNS.log(f"Decryption by {RNS.prettyhexrep(self.hash)} failed: {e}", RNS.LOG_DEBUG) if ratchet_id_receiver: ratchet_id_receiver.latest_ratchet_id = None - + return plaintext; else: RNS.log("Decryption failed because the token size was invalid.", RNS.LOG_DEBUG) @@ -739,7 +739,7 @@ class Identity: """ if self.sig_prv != None: try: - return self.sig_prv.sign(message) + return self.sig_prv.sign(message) except Exception as e: RNS.log(f"The identity {self} could not sign the requested message. The contained exception was: {e}", RNS.LOG_ERROR) raise e @@ -770,7 +770,7 @@ class Identity: proof_data = signature else: proof_data = packet.packet_hash + signature - + if destination == None: destination = packet.generate_proof_destination() diff --git a/RNS/Interfaces/AX25KISSInterface.py b/RNS/Interfaces/AX25KISSInterface.py index cf99a0b..3f4bba1 100644 --- a/RNS/Interfaces/AX25KISSInterface.py +++ b/RNS/Interfaces/AX25KISSInterface.py @@ -80,7 +80,7 @@ class AX25KISSInterface(Interface): super().__init__() self.HW_MTU = 564 - + self.pyserial = serial self.serial = None self.owner = owner @@ -343,7 +343,7 @@ class AX25KISSInterface(Interface): self.online = False RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) - + if RNS.Reticulum.panic_on_interface_error: RNS.panic() diff --git a/RNS/Interfaces/Android/KISSInterface.py b/RNS/Interfaces/Android/KISSInterface.py index 4c3c8cb..c732dc9 100644 --- a/RNS/Interfaces/Android/KISSInterface.py +++ b/RNS/Interfaces/Android/KISSInterface.py @@ -74,7 +74,7 @@ class KISSInterface(Interface): from usbserial4a import serial4a as serial self.parity = "N" - + else: RNS.log("Could not load USB serial module for Android, KISS interface cannot be created.", RNS.LOG_CRITICAL) RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL) @@ -83,9 +83,9 @@ class KISSInterface(Interface): raise SystemError("Android-specific interface was used on non-Android OS") super().__init__() - + self.HW_MTU = 564 - + if beacon_data == None: beacon_data = "" @@ -172,7 +172,7 @@ class KISSInterface(Interface): self.serial.timeout = 0.1 elif vid == 0x10C4: # Hardware parameters for SiLabs CP210x @ 115200 baud - self.serial.DEFAULT_READ_BUFFER_SIZE = 64 + self.serial.DEFAULT_READ_BUFFER_SIZE = 64 self.serial.USB_READ_TIMEOUT_MILLIS = 12 self.serial.timeout = 0.012 elif vid == 0x1A86 and pid == 0x55D4: @@ -352,7 +352,7 @@ class KISSInterface(Interface): data_buffer = data_buffer+bytes([byte]) elif (command == KISS.CMD_READY): self.process_queue() - + if got == 0: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: @@ -379,7 +379,7 @@ class KISSInterface(Interface): self.online = False RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) - + if RNS.Reticulum.panic_on_interface_error: RNS.panic() diff --git a/RNS/Interfaces/Android/RNodeInterface.py b/RNS/Interfaces/Android/RNodeInterface.py index d600bd5..4a1aa35 100644 --- a/RNS/Interfaces/Android/RNodeInterface.py +++ b/RNS/Interfaces/Android/RNodeInterface.py @@ -42,7 +42,7 @@ class KISS(): FESC = 0xDB TFEND = 0xDC TFESC = 0xDD - + CMD_UNKNOWN = 0xFE CMD_DATA = 0x00 CMD_FREQUENCY = 0x01 @@ -78,11 +78,11 @@ class KISS(): DETECT_REQ = 0x73 DETECT_RESP = 0x46 - + RADIO_STATE_OFF = 0x00 RADIO_STATE_ON = 0x01 RADIO_STATE_ASK = 0xFF - + CMD_ERROR = 0x90 ERROR_INITRADIO = 0x01 ERROR_TXFAILED = 0x02 @@ -194,7 +194,7 @@ class AndroidBluetoothManager(): if self.rfcomm_reader != None: self.rfcomm_reader.close() self.rfcomm_reader = None - + if self.rfcomm_writer != None: self.rfcomm_writer.close() self.rfcomm_writer = None @@ -371,7 +371,7 @@ class RNodeInterface(Interface): else: self.bt_manager = None - + else: RNS.log("Could not load USB serial module for Android, RNode interface cannot be created.", RNS.LOG_CRITICAL) RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL) @@ -382,7 +382,7 @@ class RNodeInterface(Interface): super().__init__() self.HW_MTU = 508 - + self.pyserial = serial self.serial = None self.owner = owner @@ -561,7 +561,7 @@ class RNodeInterface(Interface): # self.ble = BLEConnection(owner=self, target_name=self.ble_name, target_bt_addr=self.ble_addr) # self.serial = self.ble # RNS.log(f"New connection instance: "+str(self.ble)) - + def open_port(self): if not self.use_ble: if self.port != None: @@ -602,7 +602,7 @@ class RNodeInterface(Interface): self.serial.timeout = 0.1 elif vid == 0x10C4: # Hardware parameters for SiLabs CP210x @ 115200 baud - self.serial.DEFAULT_READ_BUFFER_SIZE = 64 + self.serial.DEFAULT_READ_BUFFER_SIZE = 64 self.serial.USB_READ_TIMEOUT_MILLIS = 12 self.serial.timeout = 0.012 elif vid == 0x1A86 and pid == 0x55D4: @@ -687,14 +687,14 @@ class RNodeInterface(Interface): RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR) - + if self.serial != None: self.serial.close() if self.bt_manager != None: self.bt_manager.close() raise OSError("RNode interface did not pass configuration validation") - + def initRadio(self): self.setFrequency() @@ -702,22 +702,22 @@ class RNodeInterface(Interface): self.setBandwidth() time.sleep(0.15) - + self.setTXPower() time.sleep(0.15) - + self.setSpreadingFactor() time.sleep(0.15) - + self.setCodingRate() time.sleep(0.15) self.setSTALock() time.sleep(0.15) - + self.setLTALock() time.sleep(0.15) - + self.setRadioState(KISS.RADIO_STATE_ON) time.sleep(0.15) @@ -735,7 +735,7 @@ class RNodeInterface(Interface): written = self.write_mux(kiss_command) if written != len(kiss_command): raise OSError("An IO error occurred while sending host left command to device") - + def enable_bluetooth(self): kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND]) written = self.write_mux(kiss_command) @@ -788,7 +788,7 @@ class RNodeInterface(Interface): data = line_byte+line_data escaped_data = KISS.escape(data) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND]) - + written = self.write_mux(kiss_command) if written != len(kiss_command): raise OSError("An IO error occurred while writing framebuffer data device") @@ -883,7 +883,7 @@ class RNodeInterface(Interface): if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ): if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN): self.firmware_ok = True - + if self.firmware_ok: return @@ -1188,7 +1188,7 @@ class RNodeInterface(Interface): atl = command_buffer[2] << 8 | command_buffer[3] cus = command_buffer[4] << 8 | command_buffer[5] cul = command_buffer[6] << 8 | command_buffer[7] - + self.r_airtime_short = ats/100.0 self.r_airtime_long = atl/100.0 self.r_channel_load_short = cus/100.0 @@ -1289,10 +1289,10 @@ class RNodeInterface(Interface): if time.time() > self.first_tx + self.id_interval: RNS.log(f"Interface {self} is transmitting beacon data: {self.id_callsign.decode('utf-8')}", RNS.LOG_DEBUG) self.processOutgoing(self.id_callsign) - + if (time.time() - self.last_port_io > self.port_io_timeout): self.detect() - + if (time.time() - self.last_port_io > self.port_io_timeout*3): raise OSError(f"Connected port for {self} became unresponsive") @@ -1343,7 +1343,7 @@ class RNodeInterface(Interface): if self.last_imagedata != None: self.display_image(self.last_imagedata) self.enable_external_framebuffer() - + elif hasattr(self, "bt_manager") and self.bt_manager != None and self.bt_manager.connected: self.configure_device() if self.online: @@ -1504,7 +1504,7 @@ class BLEConnection(BluetoothDispatcher): self.write_characteristic(self.rx_char, data) else: time.sleep(0.1) - + except Exception as e: RNS.log("An error occurred in {self} write loop: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) @@ -1552,7 +1552,7 @@ class BLEConnection(BluetoothDispatcher): self.owner.hw_errors.append({"error": KISS.ERROR_INVALID_BLE_MTU, "description": "The Bluetooth Low Energy transfer MTU could not be configured for the connected device, and communication has failed. Restart Reticulum and any connected applications to retry connecting."}) self.close() self.should_run = False - + self.close_gatt() self.connect_job_running = False @@ -1599,14 +1599,14 @@ class BLEConnection(BluetoothDispatcher): def on_services(self, status, services): if status == GATT_SUCCESS: self.rx_char = services.search(BLEConnection.UART_RX_CHAR_UUID) - + if self.rx_char is not None: self.tx_char = services.search(BLEConnection.UART_TX_CHAR_UUID) - if self.tx_char is not None: + if self.tx_char is not None: if self.enable_notifications(self.tx_char): RNS.log("Enabled notifications for BLE TX characteristic", RNS.LOG_DEBUG) - + RNS.log(f"Requesting BLE connection MTU update to {self.target_mtu}", RNS.LOG_DEBUG) self.mtu_requested_time = time.time() self.request_mtu(self.target_mtu) diff --git a/RNS/Interfaces/Android/SerialInterface.py b/RNS/Interfaces/Android/SerialInterface.py index db7d47a..4b62b28 100644 --- a/RNS/Interfaces/Android/SerialInterface.py +++ b/RNS/Interfaces/Android/SerialInterface.py @@ -64,7 +64,7 @@ class SerialInterface(Interface): from usbserial4a import serial4a as serial self.parity = "N" - + else: RNS.log("Could not load USB serial module for Android, Serial interface cannot be created.", RNS.LOG_CRITICAL) RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL) @@ -75,7 +75,7 @@ class SerialInterface(Interface): super().__init__() self.HW_MTU = 564 - + self.pyserial = serial self.serial = None self.owner = owner @@ -145,7 +145,7 @@ class SerialInterface(Interface): self.serial.timeout = 0.1 elif vid == 0x10C4: # Hardware parameters for SiLabs CP210x @ 115200 baud - self.serial.DEFAULT_READ_BUFFER_SIZE = 64 + self.serial.DEFAULT_READ_BUFFER_SIZE = 64 self.serial.USB_READ_TIMEOUT_MILLIS = 12 self.serial.timeout = 0.012 elif vid == 0x1A86 and pid == 0x55D4: @@ -182,7 +182,7 @@ class SerialInterface(Interface): if self.online: data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG]) written = self.serial.write(data) - self.txb += len(data) + self.txb += len(data) if written != len(data): raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") @@ -217,7 +217,7 @@ class SerialInterface(Interface): byte = HDLC.ESC escape = False data_buffer = data_buffer+bytes([byte]) - + if got == 0: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: @@ -225,12 +225,12 @@ class SerialInterface(Interface): in_frame = False escape = False # sleep(0.08) - + except Exception as e: self.online = False RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) - + if RNS.Reticulum.panic_on_interface_error: RNS.panic() diff --git a/RNS/Interfaces/AutoInterface.py b/RNS/Interfaces/AutoInterface.py index 06ed77c..7737415 100644 --- a/RNS/Interfaces/AutoInterface.py +++ b/RNS/Interfaces/AutoInterface.py @@ -289,7 +289,7 @@ class AutoInterface(Interface): udp_server = socketserver.UDPServer(address, self.handler_factory(self.processIncoming)) self.interface_servers[ifname] = udp_server - + thread = threading.Thread(target=udp_server.serve_forever) thread.daemon = True thread.start() @@ -306,11 +306,11 @@ class AutoInterface(Interface): def discovery_handler(self, socket, ifname): def announce_loop(): self.announce_handler(ifname) - + thread = threading.Thread(target=announce_loop) thread.daemon = True thread.start() - + while True: data, ipv6_src = socket.recvfrom(1024) expected_hash = RNS.Identity.full_hash(self.group_id+ipv6_src[0].encode("utf-8")) @@ -396,13 +396,13 @@ class AutoInterface(Interface): self.carrier_changed = True RNS.log(f"{self} Carrier recovered on {ifname}", RNS.LOG_WARNING) self.timed_out_interfaces[ifname] = False - + def announce_handler(self, ifname): while True: self.peer_announce(ifname) time.sleep(self.announce_interval) - + def peer_announce(self, ifname): try: link_local_address = self.adopted_interfaces[ifname] @@ -414,7 +414,7 @@ class AutoInterface(Interface): announce_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis) announce_socket.sendto(discovery_token, addr_info[0][4]) announce_socket.close() - + except Exception as e: if (ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == False) or not ifname in self.timed_out_interfaces: RNS.log(f"{self} Detected possible carrier loss on {ifname}: {e}", RNS.LOG_WARNING) @@ -471,9 +471,9 @@ class AutoInterface(Interface): except Exception as e: RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR) - + self.txb += len(data) - + # Until per-device sub-interfacing is implemented, # ingress limiting should be disabled on AutoInterface diff --git a/RNS/Interfaces/I2PInterface.py b/RNS/Interfaces/I2PInterface.py index 7448bfa..626ba11 100644 --- a/RNS/Interfaces/I2PInterface.py +++ b/RNS/Interfaces/I2PInterface.py @@ -143,11 +143,11 @@ class I2PController: self.loop.ext_owner = self result = asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result() - + if not i2p_destination in self.i2plib_tunnels: raise OSError("No tunnel control instance was created") - else: + else: tn = self.i2plib_tunnels[i2p_destination] if tn != None and hasattr(tn, "status"): @@ -183,7 +183,7 @@ class I2PController: except ConnectionRefusedError as e: raise e - + except ConnectionAbortedError as e: raise e @@ -222,13 +222,13 @@ class I2PController: elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.KeyNotFound): RNS.log(f"The I2P daemon could not find the key for {i2p_destination}", RNS.LOG_ERROR) - + elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.PeerNotFound): RNS.log(f"The I2P daemon mould not find the peer {i2p_destination}", RNS.LOG_ERROR) - + elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError): RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) - + elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): RNS.log(f"I2P daemon timed out while setting up client tunnel to {i2p_destination}", RNS.LOG_ERROR) @@ -320,7 +320,7 @@ class I2PController: elif i2p_exception != None: RNS.log("An error ocurred while setting up I2P tunnel", RNS.LOG_ERROR) - + if isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.CantReachPeer): RNS.log(f"The I2P daemon can't reach peer {i2p_destination}", RNS.LOG_ERROR) @@ -338,13 +338,13 @@ class I2PController: elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.KeyNotFound): RNS.log(f"The I2P daemon could not find the key for {i2p_destination}", RNS.LOG_ERROR) - + elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.PeerNotFound): RNS.log(f"The I2P daemon mould not find the peer {i2p_destination}", RNS.LOG_ERROR) - + elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError): RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) - + elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): RNS.log(f"I2P daemon timed out while setting up client tunnel to {i2p_destination}", RNS.LOG_ERROR) @@ -393,7 +393,7 @@ class I2PInterfacePeer(Interface): super().__init__() self.HW_MTU = 1064 - + self.IN = True self.OUT = False self.socket = None @@ -492,7 +492,7 @@ class I2PInterfacePeer(Interface): while self.awaiting_i2p_tunnel: time.sleep(0.25) time.sleep(2) - + if not self.kiss_framing: self.wants_tunnel = True @@ -525,7 +525,7 @@ class I2PInterfacePeer(Interface): self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(I2PInterfacePeer.I2P_PROBE_AFTER)) - + def shutdown_socket(self, target_socket): if callable(target_socket.close): try: @@ -538,15 +538,15 @@ class I2PInterfacePeer(Interface): if socket != None: target_socket.close() except Exception as e: - RNS.log(f"Error while closing socket for {self}: {e}") - + RNS.log(f"Error while closing socket for {self}: {e}") + def detach(self): RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) if self.socket != None: if hasattr(self.socket, "close"): if callable(self.socket.close): self.detached = True - + try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: @@ -564,7 +564,7 @@ class I2PInterfacePeer(Interface): self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.connect((self.target_ip, self.target_port)) self.online = True - + except Exception as e: if initial: if not self.awaiting_i2p_tunnel: @@ -572,7 +572,7 @@ class I2PInterfacePeer(Interface): RNS.log(f"Leaving unconnected and retrying connection in {I2PInterfacePeer.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR) return False - + else: raise e @@ -580,7 +580,7 @@ class I2PInterfacePeer(Interface): self.set_timeouts_linux() elif platform.system() == "Darwin": self.set_timeouts_osx() - + self.online = True self.writing = False self.never_connected = False @@ -631,7 +631,7 @@ class I2PInterfacePeer(Interface): self.rxb += len(data) if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count: self.parent_interface.rxb += len(data) - + self.owner.inbound(data, self) def processOutgoing(self, data): @@ -651,7 +651,7 @@ class I2PInterfacePeer(Interface): self.writing = False self.txb += len(data) self.last_write = time.time() - + if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count: self.parent_interface.txb += len(data) @@ -686,7 +686,7 @@ class I2PInterfacePeer(Interface): RNS.log(f"An error ocurred while sending I2P keepalive. The contained exception was: {e}", RNS.LOG_ERROR) self.shutdown_socket(self.socket) should_run = False - + if (time.time()-self.last_read > I2PInterfacePeer.I2P_READ_TIMEOUT): RNS.log("I2P socket is unresponsive, restarting...", RNS.LOG_WARNING) if self.socket != None: @@ -790,7 +790,7 @@ class I2PInterfacePeer(Interface): break - + except Exception as e: self.online = False RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING) @@ -832,7 +832,7 @@ class I2PInterface(Interface): def __init__(self, owner, name, rns_storagepath, peers, connectable = False, ifac_size = 16, ifac_netname = None, ifac_netkey = None): super().__init__() - + self.HW_MTU = 1064 self.online = False @@ -882,7 +882,7 @@ class I2PInterface(Interface): def createHandler(*args, **keys): return I2PInterfaceHandler(callback, *args, **keys) return createHandler - + ThreadingI2PServer.allow_reuse_address = True self.server = ThreadingI2PServer(self.address, handlerFactory(self.incoming_connection)) diff --git a/RNS/Interfaces/Interface.py b/RNS/Interfaces/Interface.py index e72e9c8..01d5c5f 100755 --- a/RNS/Interfaces/Interface.py +++ b/RNS/Interfaces/Interface.py @@ -146,7 +146,7 @@ class Interface: def release(): RNS.Transport.inbound(selected_announce_packet.raw, selected_announce_packet.receiving_interface) threading.Thread(target=release, daemon=True).start() - + except Exception as e: RNS.log(f"An error occurred while processing held announces for {self}", RNS.LOG_ERROR) RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) @@ -170,7 +170,7 @@ class Interface: for i in range(1,dq_len): delta_sum += self.ia_freq_deque[i]-self.ia_freq_deque[i-1] delta_sum += time.time() - self.ia_freq_deque[dq_len-1] - + if delta_sum == 0: avg = 0 else: @@ -187,7 +187,7 @@ class Interface: for i in range(1,dq_len): delta_sum += self.oa_freq_deque[i]-self.oa_freq_deque[i-1] delta_sum += time.time() - self.oa_freq_deque[dq_len-1] - + if delta_sum == 0: avg = 0 else: diff --git a/RNS/Interfaces/KISSInterface.py b/RNS/Interfaces/KISSInterface.py index 13c9197..a37e0bb 100644 --- a/RNS/Interfaces/KISSInterface.py +++ b/RNS/Interfaces/KISSInterface.py @@ -71,9 +71,9 @@ class KISSInterface(Interface): RNS.panic() super().__init__() - + self.HW_MTU = 564 - + if beacon_data == None: beacon_data = "" @@ -218,7 +218,7 @@ class KISSInterface(Interface): def processIncoming(self, data): - self.rxb += len(data) + self.rxb += len(data) self.owner.inbound(data, self) @@ -325,7 +325,7 @@ class KISSInterface(Interface): self.online = False RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) - + if RNS.Reticulum.panic_on_interface_error: RNS.panic() diff --git a/RNS/Interfaces/LocalInterface.py b/RNS/Interfaces/LocalInterface.py index 1fedf00..3c197be 100644 --- a/RNS/Interfaces/LocalInterface.py +++ b/RNS/Interfaces/LocalInterface.py @@ -58,11 +58,11 @@ class LocalClientInterface(Interface): # TODO: Remove at some point # self.rxptime = 0 - + self.HW_MTU = 1064 self.online = False - + self.IN = True self.OUT = False self.socket = None @@ -146,7 +146,7 @@ class LocalClientInterface(Interface): time.sleep(LocalClientInterface.RECONNECT_WAIT+2) RNS.Transport.shared_connection_reappeared() threading.Thread(target=job, daemon=True).start() - + else: RNS.log("Attempt to reconnect on a non-initiator shared local interface. This should not happen.", RNS.LOG_ERROR) raise OSError("Attempt to reconnect on a non-initiator local interface") @@ -156,10 +156,10 @@ class LocalClientInterface(Interface): self.rxb += len(data) if hasattr(self, "parent_interface") and self.parent_interface != None: self.parent_interface.rxb += len(data) - + # TODO: Remove at some point # processing_start = time.time() - + self.owner.inbound(data, self) # TODO: Remove at some point @@ -234,7 +234,7 @@ class LocalClientInterface(Interface): break - + except Exception as e: self.online = False RNS.log(f"An interface error occurred, the contained exception was: {e}", RNS.LOG_ERROR) @@ -247,7 +247,7 @@ class LocalClientInterface(Interface): if callable(self.socket.close): RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.detached = True - + try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: @@ -283,7 +283,7 @@ class LocalClientInterface(Interface): if self.is_connected_to_shared_instance: if nowarning == False: RNS.log("Permanently lost connection to local shared RNS instance. Exiting now.", RNS.LOG_CRITICAL) - + RNS.exit() @@ -297,7 +297,7 @@ class LocalServerInterface(Interface): super().__init__() self.online = False self.clients = 0 - + self.IN = True self.OUT = False self.name = "Reticulum" diff --git a/RNS/Interfaces/PipeInterface.py b/RNS/Interfaces/PipeInterface.py index 87c67f2..5004a74 100644 --- a/RNS/Interfaces/PipeInterface.py +++ b/RNS/Interfaces/PipeInterface.py @@ -49,7 +49,7 @@ class PipeInterface(Interface): owner = None command = None - + def __init__(self, owner, name, command, respawn_delay): if respawn_delay == None: respawn_delay = 5 @@ -57,7 +57,7 @@ class PipeInterface(Interface): super().__init__() self.HW_MTU = 1064 - + self.owner = owner self.name = name self.command = command @@ -83,7 +83,7 @@ class PipeInterface(Interface): def open_pipe(self): RNS.log(f"Connecting subprocess pipe for {self}...", RNS.LOG_VERBOSE) - + try: self.process = subprocess.Popen(shlex.split(self.command), stdin=subprocess.PIPE, stdout=subprocess.PIPE) self.pipe_is_open = True @@ -102,7 +102,7 @@ class PipeInterface(Interface): def processIncoming(self, data): - self.rxb += len(data) + self.rxb += len(data) self.owner.inbound(data, self) @@ -111,7 +111,7 @@ class PipeInterface(Interface): data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG]) written = self.process.stdin.write(data) self.process.stdin.flush() - self.txb += len(data) + self.txb += len(data) if written != len(data): raise OSError(f"Pipe interface only wrote {written} bytes of {len(data)}") @@ -152,7 +152,7 @@ class PipeInterface(Interface): RNS.log(f"Subprocess terminated on {self}") self.process.kill() - + except Exception as e: self.online = False try: @@ -162,7 +162,7 @@ class PipeInterface(Interface): RNS.log(f"A pipe error occurred, the contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) - + if RNS.Reticulum.panic_on_interface_error: RNS.panic() diff --git a/RNS/Interfaces/RNodeInterface.py b/RNS/Interfaces/RNodeInterface.py index 9d955d5..83b241c 100644 --- a/RNS/Interfaces/RNodeInterface.py +++ b/RNS/Interfaces/RNodeInterface.py @@ -33,7 +33,7 @@ class KISS(): FESC = 0xDB TFEND = 0xDC TFESC = 0xDD - + CMD_UNKNOWN = 0xFE CMD_DATA = 0x00 CMD_FREQUENCY = 0x01 @@ -69,11 +69,11 @@ class KISS(): DETECT_REQ = 0x73 DETECT_RESP = 0x46 - + RADIO_STATE_OFF = 0x00 RADIO_STATE_ON = 0x01 RADIO_STATE_ASK = 0xFF - + CMD_ERROR = 0x90 ERROR_INITRADIO = 0x01 ERROR_TXFAILED = 0x02 @@ -91,7 +91,7 @@ class KISS(): data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd])) data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc])) return data - + class RNodeInterface(Interface): MAX_CHUNK = 32768 @@ -132,7 +132,7 @@ class RNodeInterface(Interface): super().__init__() self.HW_MTU = 508 - + self.pyserial = serial self.serial = None self.owner = owner @@ -287,7 +287,7 @@ class RNodeInterface(Interface): write_timeout = None, dsrdtr = False, ) - + else: RNS.log(f"Opening BLE connection for {self}...") if self.ble == None: @@ -325,7 +325,7 @@ class RNodeInterface(Interface): detect_time = RNS.prettytime(time.time()-detect_time) else: RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR) - + if not self.detected: RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR) self.serial.close() @@ -346,7 +346,7 @@ class RNodeInterface(Interface): RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR) self.serial.close() - + def initRadio(self): self.setFrequency() @@ -366,13 +366,13 @@ class RNodeInterface(Interface): written = self.serial.write(kiss_command) if written != len(kiss_command): raise OSError(f"An IO error occurred while detecting hardware for {self}") - + def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): raise OSError("An IO error occurred while sending host left command to device") - + def enable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) @@ -406,7 +406,7 @@ class RNodeInterface(Interface): data = line_byte+line_data escaped_data = KISS.escape(data) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND]) - + written = self.serial.write(kiss_command) if written != len(kiss_command): raise OSError("An IO error occurred while writing framebuffer data device") @@ -501,7 +501,7 @@ class RNodeInterface(Interface): if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ): if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN): self.firmware_ok = True - + if self.firmware_ok: return @@ -784,7 +784,7 @@ class RNodeInterface(Interface): atl = command_buffer[2] << 8 | command_buffer[3] cus = command_buffer[4] << 8 | command_buffer[5] cul = command_buffer[6] << 8 | command_buffer[7] - + self.r_airtime_short = ats/100.0 self.r_airtime_long = atl/100.0 self.r_channel_load_short = cus/100.0 @@ -870,7 +870,7 @@ class RNodeInterface(Interface): self.detected = True else: self.detected = False - + else: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: @@ -928,7 +928,7 @@ class RNodeInterface(Interface): self.disable_external_framebuffer() self.setRadioState(KISS.RADIO_STATE_OFF) self.leave() - + if self.use_ble: self.ble.close() @@ -1021,7 +1021,7 @@ class BLEConnection(): if importlib.util.find_spec("bleak") != None: import bleak BLEConnection.bleak = bleak - + import asyncio BLEConnection.asyncio = asyncio else: @@ -1100,7 +1100,7 @@ class BLEConnection(): else: if self.target_bt_addr != None and device.address == self.target_bt_addr: RNS.log(f"Can't connect to target device {self.target_bt_addr} over BLE, device is not bonded", RNS.LOG_ERROR) - + elif self.target_name != None and device.name == self.target_name: RNS.log(f"Can't connect to target device {self.target_name} over BLE, device is not bonded", RNS.LOG_ERROR) @@ -1115,7 +1115,7 @@ class BLEConnection(): if "props" in device.details and "Bonded" in device.details["props"]: if device.details["props"]["Bonded"] == True: return True - + except Exception as e: RNS.log(f"Error while determining device bond status for {device}, the contained exception was: {e}", RNS.LOG_ERROR) diff --git a/RNS/Interfaces/RNodeMultiInterface.py b/RNS/Interfaces/RNodeMultiInterface.py index 021bbb1..96f4084 100644 --- a/RNS/Interfaces/RNodeMultiInterface.py +++ b/RNS/Interfaces/RNodeMultiInterface.py @@ -33,7 +33,7 @@ class KISS(): FESC = 0xDB TFEND = 0xDC TFESC = 0xDD - + CMD_UNKNOWN = 0xFE CMD_FREQUENCY = 0x01 CMD_BANDWIDTH = 0x02 @@ -94,11 +94,11 @@ class KISS(): DETECT_REQ = 0x73 DETECT_RESP = 0x46 - + RADIO_STATE_OFF = 0x00 RADIO_STATE_ON = 0x01 RADIO_STATE_ASK = 0xFF - + CMD_ERROR = 0x90 ERROR_INITRADIO = 0x01 ERROR_TXFAILED = 0x02 @@ -159,7 +159,7 @@ class KISS(): data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd])) data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc])) return data - + class RNodeMultiInterface(Interface): MAX_CHUNK = 32768 @@ -188,7 +188,7 @@ class RNodeMultiInterface(Interface): super().__init__() self.HW_MTU = 508 - + self.clients = 0 self.pyserial = serial self.serial = None @@ -294,7 +294,7 @@ class RNodeMultiInterface(Interface): self.detect() sleep(0.2) - + if not self.detected: RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR) self.serial.close() @@ -327,7 +327,7 @@ class RNodeMultiInterface(Interface): interface.OUT = subint[10] interface.IN = True - + interface.announce_rate_target = self.announce_rate_target interface.mode = self.mode interface.HW_MTU = self.HW_MTU @@ -345,13 +345,13 @@ class RNodeMultiInterface(Interface): written = self.serial.write(kiss_command) if written != len(kiss_command): raise OSError(f"An IO error occurred while detecting hardware for {self}") - + def leave(self): kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) written = self.serial.write(kiss_command) if written != len(kiss_command): raise OSError("An IO error occurred while sending host left command to device") - + def enable_external_framebuffer(self): if self.display != None: kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) @@ -385,7 +385,7 @@ class RNodeMultiInterface(Interface): data = line_byte+line_data escaped_data = KISS.escape(data) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND]) - + written = self.serial.write(kiss_command) if written != len(kiss_command): raise OSError("An IO error occurred while writing framebuffer data device") @@ -485,7 +485,7 @@ class RNodeMultiInterface(Interface): if (self.maj_version >= RNodeMultiInterface.REQUIRED_FW_VER_MAJ): if (self.min_version >= RNodeMultiInterface.REQUIRED_FW_VER_MIN): self.firmware_ok = True - + if self.firmware_ok: return @@ -737,7 +737,7 @@ class RNodeMultiInterface(Interface): atl = command_buffer[2] << 8 | command_buffer[3] cus = command_buffer[4] << 8 | command_buffer[5] cul = command_buffer[6] << 8 | command_buffer[7] - + self.r_airtime_short = ats/100.0 self.r_airtime_long = atl/100.0 self.r_channel_load_short = cus/100.0 @@ -804,7 +804,7 @@ class RNodeMultiInterface(Interface): # add the interface to the back of the list, they're all given from vport 0 and up in order self.subinterface_types.append(KISS.interface_type_to_str(command_buffer[1])) command_buffer = b"" - + else: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: @@ -918,7 +918,7 @@ class RNodeSubInterface(Interface): RNS.panic() super().__init__() - + if index == 0: sel_cmd = KISS.CMD_SEL_INT0 data_cmd= KISS.CMD_INT0_DATA @@ -1079,7 +1079,7 @@ class RNodeSubInterface(Interface): RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR) RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR) - + def initRadio(self): self.parent_interface.setFrequency(self.frequency, self) diff --git a/RNS/Interfaces/SerialInterface.py b/RNS/Interfaces/SerialInterface.py index e69b347..63ee725 100755 --- a/RNS/Interfaces/SerialInterface.py +++ b/RNS/Interfaces/SerialInterface.py @@ -63,7 +63,7 @@ class SerialInterface(Interface): super().__init__() self.HW_MTU = 564 - + self.pyserial = serial self.serial = None self.owner = owner @@ -122,7 +122,7 @@ class SerialInterface(Interface): def processIncoming(self, data): - self.rxb += len(data) + self.rxb += len(data) self.owner.inbound(data, self) @@ -130,7 +130,7 @@ class SerialInterface(Interface): if self.online: data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG]) written = self.serial.write(data) - self.txb += len(data) + self.txb += len(data) if written != len(data): raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") @@ -164,7 +164,7 @@ class SerialInterface(Interface): byte = HDLC.ESC escape = False data_buffer = data_buffer+bytes([byte]) - + else: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: @@ -172,12 +172,12 @@ class SerialInterface(Interface): in_frame = False escape = False sleep(0.08) - + except Exception as e: self.online = False RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR) - + if RNS.Reticulum.panic_on_interface_error: RNS.panic() diff --git a/RNS/Interfaces/TCPInterface.py b/RNS/Interfaces/TCPInterface.py index fbdb3f3..306f35d 100644 --- a/RNS/Interfaces/TCPInterface.py +++ b/RNS/Interfaces/TCPInterface.py @@ -80,9 +80,9 @@ class TCPClientInterface(Interface): def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None, max_reconnect_tries=None, kiss_framing=False, i2p_tunneled = False, connect_timeout = None): super().__init__() - + self.HW_MTU = 1064 - + self.IN = True self.OUT = False self.socket = None @@ -99,7 +99,7 @@ class TCPClientInterface(Interface): self.i2p_tunneled = i2p_tunneled self.mode = RNS.Interfaces.Interface.Interface.MODE_FULL self.bitrate = TCPClientInterface.BITRATE_GUESS - + if max_reconnect_tries == None: self.max_reconnect_tries = TCPClientInterface.RECONNECT_MAX_TRIES else: @@ -128,14 +128,14 @@ class TCPClientInterface(Interface): self.connect_timeout = connect_timeout else: self.connect_timeout = TCPClientInterface.INITIAL_CONNECT_TIMEOUT - + if TCPClientInterface.SYNCHRONOUS_START: self.initial_connect() else: thread = threading.Thread(target=self.initial_connect) thread.daemon = True thread.start() - + def initial_connect(self): if not self.connect(initial=True): thread = threading.Thread(target=self.reconnect) @@ -170,19 +170,19 @@ class TCPClientInterface(Interface): TCP_KEEPIDLE = 0x10 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) - + if not self.i2p_tunneled: self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.TCP_PROBE_AFTER)) else: self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.I2P_PROBE_AFTER)) - + def detach(self): if self.socket != None: if hasattr(self.socket, "close"): if callable(self.socket.close): RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) self.detached = True - + try: self.socket.shutdown(socket.SHUT_RDWR) except Exception as e: @@ -209,13 +209,13 @@ class TCPClientInterface(Interface): if initial: RNS.log(f"TCP connection for {self} established", RNS.LOG_DEBUG) - + except Exception as e: if initial: RNS.log(f"Initial connection for {self} could not be established: {e}", RNS.LOG_ERROR) RNS.log(f"Leaving unconnected and retrying connection in {TCPClientInterface.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR) return False - + else: raise e @@ -223,7 +223,7 @@ class TCPClientInterface(Interface): self.set_timeouts_linux() elif platform.system() == "Darwin": self.set_timeouts_osx() - + self.online = True self.writing = False self.never_connected = False @@ -269,7 +269,7 @@ class TCPClientInterface(Interface): self.rxb += len(data) if hasattr(self, "parent_interface") and self.parent_interface != None: self.parent_interface.rxb += len(data) - + self.owner.inbound(data, self) def processOutgoing(self, data): @@ -369,7 +369,7 @@ class TCPClientInterface(Interface): break - + except Exception as e: self.online = False RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING) @@ -427,7 +427,7 @@ class TCPServerInterface(Interface): self.online = False self.clients = 0 - + self.IN = True self.OUT = False self.name = name @@ -474,7 +474,7 @@ class TCPServerInterface(Interface): spawned_interface.target_port = str(handler.client_address[1]) spawned_interface.parent_interface = self spawned_interface.bitrate = self.bitrate - + spawned_interface.ifac_size = self.ifac_size spawned_interface.ifac_netname = self.ifac_netname spawned_interface.ifac_netkey = self.ifac_netkey diff --git a/RNS/Interfaces/UDPInterface.py b/RNS/Interfaces/UDPInterface.py index d407a78..391a4ec 100644 --- a/RNS/Interfaces/UDPInterface.py +++ b/RNS/Interfaces/UDPInterface.py @@ -99,7 +99,7 @@ class UDPInterface(Interface): udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) udp_socket.sendto(data, (self.forward_ip, self.forward_port)) self.txb += len(data) - + except Exception as e: RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR) diff --git a/RNS/Link.py b/RNS/Link.py index a74a444..8d9fbc0 100644 --- a/RNS/Link.py +++ b/RNS/Link.py @@ -124,7 +124,7 @@ class Link: RNS.Transport.register_link(link) link.last_inbound = time.time() link.start_watchdog() - + RNS.log(f"Incoming link request {link} accepted on {link.attached_interface}", RNS.LOG_DEBUG) return link @@ -189,7 +189,7 @@ class Link: self.sig_prv = Ed25519PrivateKey.generate() self.fernet = None - + self.pub = self.prv.public_key() self.pub_bytes = self.pub.public_bytes() @@ -288,7 +288,7 @@ class Link: self.establishment_cost += len(packet.raw) signed_data = self.link_id+self.peer_pub_bytes+self.peer_sig_pub_bytes signature = packet.data[:RNS.Identity.SIGLENGTH//8] - + if self.destination.identity.validate(signature, signed_data): if self.status != Link.HANDSHAKE: raise OSError(f"Invalid link state for proof validation: {self.status}") @@ -301,7 +301,7 @@ class Link: self.last_proof = self.activated_at RNS.Transport.activate_link(self) RNS.log(f"Link {self} established with {self.destination}, RTT is {round(self.rtt, 3)}s", RNS.LOG_VERBOSE) - + if self.rtt != None and self.establishment_cost != None and self.rtt > 0 and self.establishment_cost > 0: self.establishment_rate = self.establishment_cost/self.rtt @@ -316,7 +316,7 @@ class Link: thread.start() else: RNS.log(f"Invalid link proof signature received by {self}. Ignoring.", RNS.LOG_DEBUG) - + except Exception as e: self.status = Link.CLOSED RNS.log(f"An error ocurred while validating link request proof on {self}.", RNS.LOG_ERROR) @@ -377,7 +377,7 @@ class Link: timeout = timeout, request_size = len(packed_request), ) - + else: request_id = RNS.Identity.truncated_hash(packed_request) RNS.log(f"Sending request {RNS.prettyhexrep(request_id)} as resource.", RNS.LOG_DEBUG) @@ -547,7 +547,7 @@ class Link: resource.cancel() if self._channel: self._channel._shutdown() - + self.prv = None self.pub = None self.pub_bytes = None @@ -620,7 +620,7 @@ class Link: self.status = Link.STALE else: sleep_time = self.keepalive - + else: sleep_time = (last_inbound + self.keepalive) - time.time() @@ -655,7 +655,7 @@ class Link: self.snr = packet.snr if packet.q != None: self.q = packet.q - + def send_keepalive(self): keepalive_packet = RNS.Packet(self, bytes([0xFF]), context=RNS.Packet.KEEPALIVE) keepalive_packet.send() @@ -782,7 +782,7 @@ class Link: thread = threading.Thread(target=self.callbacks.packet, args=(plaintext, packet)) thread.daemon = True thread.start() - + if self.destination.proof_strategy == RNS.Destination.PROVE_ALL: packet.prove() should_query = True @@ -815,7 +815,7 @@ class Link: self.callbacks.remote_identified(self, self.__remote_identity) except Exception as e: RNS.log(f"Error while executing remote identified callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) - + self.__update_phy_stats(packet, query_shared=True) elif packet.context == RNS.Packet.REQUEST: @@ -903,7 +903,7 @@ class Link: if not packet.packet_hash in resource.req_hashlist: resource.req_hashlist.append(packet.packet_hash) resource.request(plaintext) - + # TODO: Test and possibly enable this at some point # def request_job(): # resource.request(plaintext) @@ -984,7 +984,7 @@ class Link: try: if not self.fernet: self.fernet = Fernet(self.derived_key) - + return self.fernet.decrypt(ciphertext) except Exception as e: @@ -1140,7 +1140,7 @@ class RequestReceipt(): elif self.resource != None: self.hash = resource.request_id resource.set_callback(self.request_resource_concluded) - + self.link = link self.request_id = self.hash self.request_size = request_size @@ -1224,7 +1224,7 @@ class RequestReceipt(): self.packet_receipt.callbacks.delivery(self.packet_receipt) self.progress = resource.get_progress() - + if self.callbacks.progress != None: try: self.callbacks.progress(self) @@ -1233,7 +1233,7 @@ class RequestReceipt(): else: resource.cancel() - + def response_received(self, response): if not self.status == RequestReceipt.FAILED: self.progress = 1.0 diff --git a/RNS/Packet.py b/RNS/Packet.py index 03eccf0..8c909ad 100755 --- a/RNS/Packet.py +++ b/RNS/Packet.py @@ -97,7 +97,7 @@ class Packet: # the below calculation; 383 bytes. ENCRYPTED_MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.FERNET_OVERHEAD-RNS.Identity.KEYSIZE//16)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1 """ - The maximum size of the payload data in a single encrypted packet + The maximum size of the payload data in a single encrypted packet """ PLAIN_MDU = MDU """ @@ -256,7 +256,7 @@ class Packet: def send(self): """ Sends the packet. - + :returns: A :ref:`RNS.PacketReceipt` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned. """ if not self.sent: @@ -278,21 +278,21 @@ class Packet: self.sent = False self.receipt = None return False - + else: raise OSError("Packet was already sent") def resend(self): """ Re-sends the packet. - + :returns: A :ref:`RNS.PacketReceipt` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned. """ if self.sent: # Re-pack the packet to obtain new ciphertext for # encrypted destinations self.pack() - + if RNS.Transport.outbound(self): return self.receipt else: @@ -388,7 +388,7 @@ class PacketReceipt: def get_status(self): """ - :returns: The status of the associated :ref:`RNS.Packet` instance. Can be one of ``RNS.PacketReceipt.SENT``, ``RNS.PacketReceipt.DELIVERED``, ``RNS.PacketReceipt.FAILED`` or ``RNS.PacketReceipt.CULLED``. + :returns: The status of the associated :ref:`RNS.Packet` instance. Can be one of ``RNS.PacketReceipt.SENT``, ``RNS.PacketReceipt.DELIVERED``, ``RNS.PacketReceipt.FAILED`` or ``RNS.PacketReceipt.CULLED``. """ return self.status @@ -422,7 +422,7 @@ class PacketReceipt: RNS.log(f"An error occurred while evaluating external delivery callback for {link}", RNS.LOG_ERROR) RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.trace_exception(e) - + return True else: return False @@ -490,7 +490,7 @@ class PacketReceipt: self.callbacks.delivery(self) except Exception as e: RNS.log(f"Error while executing proof validated callback. The contained exception was: {e}", RNS.LOG_ERROR) - + return True else: return False @@ -524,7 +524,7 @@ class PacketReceipt: def set_timeout(self, timeout): """ Sets a timeout in seconds - + :param timeout: The timeout in seconds. """ self.timeout = float(timeout) diff --git a/RNS/Resolver.py b/RNS/Resolver.py index cd8cb36..6a36079 100644 --- a/RNS/Resolver.py +++ b/RNS/Resolver.py @@ -21,7 +21,7 @@ # SOFTWARE. class Resolver: - + @staticmethod def resolve_identity(full_name): pass \ No newline at end of file diff --git a/RNS/Resource.py b/RNS/Resource.py index 7632ca2..ce4da7a 100644 --- a/RNS/Resource.py +++ b/RNS/Resource.py @@ -59,11 +59,11 @@ class Resource: # The maximum window size for transfers on fast links WINDOW_MAX_FAST = 75 - + # For calculating maps and guard segments, this # must be set to the global maximum window. WINDOW_MAX = WINDOW_MAX_FAST - + # If the fast rate is sustained for this many request # rounds, the fast link window size will be allowed. FAST_RATE_THRESHOLD = WINDOW_MAX_SLOW - WINDOW - 2 @@ -111,7 +111,7 @@ class Resource: # fit in 3 bytes in resource advertisements. MAX_EFFICIENT_SIZE = 16 * 1024 * 1024 - 1 RESPONSE_MAX_GRACE_TIME = 10 - + # The maximum size to auto-compress with # bz2 before sending. AUTO_COMPRESS_MAX_SIZE = MAX_EFFICIENT_SIZE @@ -185,7 +185,7 @@ class Resource: resource.waiting_for_hmu = False resource.receiving_part = False resource.consecutive_completed_height = -1 - + if not resource.link.has_incoming_resource(resource): resource.link.register_incoming_resource(resource) @@ -256,7 +256,7 @@ class Resource: data_size = len(data) self.grand_total_parts = math.ceil(data_size/Resource.SDU) self.total_size = data_size - + resource_data = data self.total_segments = 1 self.segment_index = 1 @@ -323,7 +323,7 @@ class Resource: self.data = b"" self.data += RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE] self.data += self.compressed_data - + self.compressed = True self.uncompressed_data = None @@ -348,7 +348,7 @@ class Resource: self.size = len(self.data) self.sent_parts = 0 hashmap_entries = int(math.ceil(self.size/float(Resource.SDU))) - + hashmap_ok = False while not hashmap_ok: hashmap_computation_began = time.time() @@ -389,12 +389,12 @@ class Resource: self.parts.append(part) RNS.log(f"Hashmap computation concluded in {round(time.time() - hashmap_computation_began, 3)} seconds", RNS.LOG_DEBUG) - + if advertise: self.advertise() else: self.receive_lock = Lock() - + def hashmap_update_packet(self, plaintext): if not self.status == Resource.FAILED: @@ -489,7 +489,7 @@ class Resource: except Exception as e: RNS.log(f"Could not resend advertisement packet, cancelling resource. The contained exception was: {e}", RNS.LOG_VERBOSE) self.cancel() - + elif self.status == Resource.TRANSFERRING: if not self.initiator: @@ -504,7 +504,7 @@ class Resource: retries_used = self.max_retries - self.retries_left extra_wait = retries_used * Resource.PER_RETRY_DELAY sleep_time = self.last_activity + (rtt*(self.part_timeout_factor+window_remaining)) + Resource.RETRY_GRACE_TIME + extra_wait - time.time() - + if sleep_time < 0: if self.retries_left > 0: ms = "" if self.outstanding_parts == 1 else "s" @@ -554,7 +554,7 @@ class Resource: if sleep_time == None or sleep_time < 0: RNS.log("Timing error, cancelling resource transfer.", RNS.LOG_ERROR) self.cancel() - + if sleep_time != None: sleep(min(sleep_time, Resource.WATCHDOG_MAX_SLEEP)) @@ -692,7 +692,7 @@ class Resource: if self.req_resp == None: self.req_resp = self.last_activity rtt = self.req_resp-self.req_sent - + self.part_timeout_factor = Resource.PART_TIMEOUT_FACTOR_AFTER_RTT if self.rtt == None: self.rtt = self.link.rtt @@ -732,7 +732,7 @@ class Resource: # Update consecutive completed pointer if i == self.consecutive_completed_height + 1: self.consecutive_completed_height = i - + cp = self.consecutive_completed_height + 1 while cp < len(self.parts) and self.parts[cp] != None: self.consecutive_completed_height = cp @@ -797,7 +797,7 @@ class Resource: i = 0; pn = self.consecutive_completed_height+1 search_start = pn search_size = self.window - + for part in self.parts[search_start:search_start+search_size]: if part == None: part_hash = self.hashmap[pn] @@ -878,10 +878,10 @@ class Resource: RNS.log("Resource could not send parts, cancelling transfer!", RNS.LOG_DEBUG) RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) self.cancel() - + if wants_more_hashmap: last_map_hash = request_data[1:Resource.MAPHASH_LEN+1] - + part_index = self.receiver_min_consecutive_height search_start = part_index search_end = self.receiver_min_consecutive_height+ResourceAdvertisement.COLLISION_GUARD_SIZE @@ -899,7 +899,7 @@ class Resource: else: segment = part_index // ResourceAdvertisement.HASHMAP_MAX_LEN - + hashmap_start = segment*ResourceAdvertisement.HASHMAP_MAX_LEN hashmap_end = min((segment+1)*ResourceAdvertisement.HASHMAP_MAX_LEN, len(self.parts)) @@ -943,7 +943,7 @@ class Resource: self.link.cancel_outgoing_resource(self) else: self.link.cancel_incoming_resource(self) - + if self.callback != None: try: self.link.resource_concluded(self) @@ -968,7 +968,7 @@ class Resource: self.processed_parts += self.sent_parts self.progress_total_parts = float(self.grand_total_parts) else: - self.processed_parts = (self.segment_index-1)*math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU) + self.processed_parts = (self.segment_index-1)*math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU) self.processed_parts += self.received_count if self.split: self.progress_total_parts = float(math.ceil(self.total_size/Resource.SDU)) @@ -1141,7 +1141,7 @@ class ResourceAdvertisement: @staticmethod def unpack(data): dictionary = umsgpack.unpackb(data) - + adv = ResourceAdvertisement() adv.t = dictionary["t"] adv.d = dictionary["d"] diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index b9b9a1a..e58ab9e 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -128,7 +128,7 @@ class Reticulum: HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*2 IFAC_MIN_SIZE = 1 IFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8") - + MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE RESOURCE_CACHE = 24*60*60 @@ -139,7 +139,7 @@ class Reticulum: router = None config = None - + # The default configuration path will be expanded to a directory # named ".reticulum" inside the current users home directory userdir = os.path.expanduser("~") @@ -149,7 +149,7 @@ class Reticulum: cachepath = "" __instance = None - + @staticmethod def exit_handler(): # This exit handler is called whenever Reticulum is asked to @@ -211,7 +211,7 @@ class Reticulum: if logdest == RNS.LOG_FILE: RNS.logdest = RNS.LOG_FILE RNS.logfile = f"{Reticulum.configdir}/logfile" - + Reticulum.configpath = f"{Reticulum.configdir}/config" Reticulum.storagepath = f"{Reticulum.configdir}/storage" Reticulum.cachepath = f"{Reticulum.configdir}/storage/cache" @@ -277,7 +277,7 @@ class Reticulum: self.__apply_config() RNS.log(f"Configuration loaded from {self.configpath}", RNS.LOG_VERBOSE) - + RNS.Identity.load_known_destinations() RNS.Transport.start(self) @@ -285,7 +285,7 @@ class Reticulum: self.rpc_addr = ("127.0.0.1", self.local_control_port) if self.rpc_key == None: self.rpc_key = RNS.Identity.full_hash(RNS.Transport.identity.get_private_key()) - + if self.is_shared_instance: self.rpc_listener = multiprocessing.connection.Listener(self.rpc_addr, authkey=self.rpc_key) thread = threading.Thread(target=self.rpc_loop) @@ -313,7 +313,7 @@ class Reticulum: if now > self.last_data_persist+Reticulum.PERSIST_INTERVAL: self.__persist_data() - + time.sleep(Reticulum.JOB_INTERVAL) def __start_local_interface(self): @@ -329,7 +329,7 @@ class Reticulum: interface._force_bitrate = Reticulum._force_shared_instance_bitrate RNS.log(f"Forcing shared instance bitrate of {RNS.prettyspeed(interface.bitrate)}", RNS.LOG_WARNING) RNS.Transport.interfaces.append(interface) - + self.is_shared_instance = True RNS.log(f"Started shared instance interface: {interface}", RNS.LOG_DEBUG) self.__start_jobs() @@ -454,7 +454,7 @@ class Reticulum: c = self.config["interfaces"][name] interface_mode = Interface.Interface.MODE_FULL - + if "interface_mode" in c: c["interface_mode"] = str(c["interface_mode"]).lower() if c["interface_mode"] == "full": @@ -489,7 +489,7 @@ class Reticulum: if "ifac_size" in c: if c.as_int("ifac_size") >= Reticulum.IFAC_MIN_SIZE*8: ifac_size = c.as_int("ifac_size")//8 - + ifac_netname = None if "networkname" in c: if c["networkname"] != "": @@ -505,7 +505,7 @@ class Reticulum: if "pass_phrase" in c: if c["pass_phrase"] != "": ifac_netkey = c["pass_phrase"] - + ingress_control = True if "ingress_control" in c: ingress_control = c.as_bool("ingress_control") ic_max_held_announces = None @@ -532,12 +532,12 @@ class Reticulum: if "announce_rate_target" in c: if c.as_int("announce_rate_target") > 0: announce_rate_target = c.as_int("announce_rate_target") - + announce_rate_grace = None if "announce_rate_grace" in c: if c.as_int("announce_rate_grace") >= 0: announce_rate_grace = c.as_int("announce_rate_grace") - + announce_rate_penalty = None if "announce_rate_penalty" in c: if c.as_int("announce_rate_penalty") >= 0: @@ -553,7 +553,7 @@ class Reticulum: if "announce_cap" in c: if c.as_float("announce_cap") > 0 and c.as_float("announce_cap") <= 100: announce_cap = c.as_float("announce_cap")/100.0 - + try: interface = None @@ -660,7 +660,7 @@ class Reticulum: if interface_mode == Interface.Interface.MODE_ACCESS_POINT: RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) interface_mode = Interface.Interface.MODE_FULL - + interface.mode = interface_mode interface.announce_cap = announce_cap @@ -697,7 +697,7 @@ class Reticulum: if interface_mode == Interface.Interface.MODE_ACCESS_POINT: RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) interface_mode = Interface.Interface.MODE_FULL - + interface.mode = interface_mode interface.announce_cap = announce_cap @@ -734,7 +734,7 @@ class Reticulum: if interface_mode == Interface.Interface.MODE_ACCESS_POINT: RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) interface_mode = Interface.Interface.MODE_FULL - + interface.mode = interface_mode interface.announce_cap = announce_cap @@ -937,7 +937,7 @@ class Reticulum: ble_addr = ble_string else: ble_name = ble_string - + interface = RNodeInterface.RNodeInterface( RNS.Transport, name, @@ -1011,11 +1011,11 @@ class Reticulum: txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None subint_config[subint_index][4] = txpower spreadingfactor = int(subinterface_config["spreadingfactor"]) if "spreadingfactor" in subinterface_config else None - subint_config[subint_index][5] = spreadingfactor + subint_config[subint_index][5] = spreadingfactor codingrate = int(subinterface_config["codingrate"]) if "codingrate" in subinterface_config else None subint_config[subint_index][6] = codingrate flow_control = subinterface_config.as_bool("flow_control") if "flow_control" in subinterface_config else False - subint_config[subint_index][7] = flow_control + subint_config[subint_index][7] = flow_control st_alock = float(subinterface_config["airtime_limit_short"]) if "airtime_limit_short" in subinterface_config else None subint_config[subint_index][8] = st_alock lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None @@ -1037,7 +1037,7 @@ class Reticulum: id_interval = int(c["id_interval"]) if "id_interval" in c else None id_callsign = c["id_callsign"] if "id_callsign" in c else None port = c["port"] if "port" in c else None - + if port == None: raise ValueError(f"No port specified for {name}") @@ -1121,7 +1121,7 @@ class Reticulum: def _add_interface(self,interface, mode = None, configured_bitrate=None, ifac_size=None, ifac_netname=None, ifac_netkey=None, announce_cap=None, announce_rate_target=None, announce_rate_grace=None, announce_rate_penalty=None): if not self.is_connected_to_shared_instance: if interface != None and issubclass(type(interface), RNS.Interfaces.Interface.Interface): - + if mode == None: mode = Interface.Interface.MODE_FULL interface.mode = mode @@ -1199,14 +1199,14 @@ class Reticulum: age = now - mtime if age > RNS.Transport.DESTINATION_TIMEOUT: os.unlink(filepath) - + except Exception as e: RNS.log(f"Error while cleaning resources cache, the contained exception was: {e}", RNS.LOG_ERROR) def __create_default_config(self): self.config = ConfigObj(__default_rns_config__) self.config.filename = Reticulum.configpath - + if not os.path.isdir(Reticulum.configdir): os.makedirs(Reticulum.configdir) self.config.write() @@ -1278,7 +1278,7 @@ class Reticulum: interfaces = [] for interface in RNS.Transport.interfaces: ifstats = {} - + if hasattr(interface, "clients"): ifstats["clients"] = interface.clients else: diff --git a/RNS/Transport.py b/RNS/Transport.py index d1bd685..a93070a 100755 --- a/RNS/Transport.py +++ b/RNS/Transport.py @@ -51,7 +51,7 @@ class Transport: """ Maximum amount of hops that Reticulum will transport a packet. """ - + PATHFINDER_R = 1 # Retransmit retries PATHFINDER_G = 5 # Retry grace period PATHFINDER_RW = 0.5 # Random window for announce rebroadcast @@ -101,7 +101,7 @@ class Transport: announce_rate_table = {} # A table for keeping track of announce rates path_requests = {} # A table for storing path request timestamps path_states = {} # A table for keeping track of path states - + discovery_path_requests = {} # A table for keeping track of path requests on behalf of other nodes discovery_pr_tags = [] # A table for keeping track of tagged path requests max_pr_tags = 32000 # Maximum amount of unique path request tags to remember @@ -150,7 +150,7 @@ class Transport: if Transport.identity == None: transport_identity_path = f"{RNS.Reticulum.storagepath}/transport_identity" if os.path.isfile(transport_identity_path): - Transport.identity = RNS.Identity.from_file(transport_identity_path) + Transport.identity = RNS.Identity.from_file(transport_identity_path) if Transport.identity == None: RNS.log("No valid Transport Identity in storage, creating...", RNS.LOG_VERBOSE) @@ -187,7 +187,7 @@ class Transport: Transport.control_destinations.append(Transport.remote_management_destination) Transport.control_hashes.append(Transport.remote_management_destination.hash) RNS.log(f"Enabled remote management on {Transport.remote_management_destination}", RNS.LOG_NOTICE) - + Transport.jobs_running = False thread = threading.Thread(target=Transport.jobloop, daemon=True) thread.start() @@ -405,7 +405,7 @@ class Transport: announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown"); announce_destination.hash = packet.destination_hash announce_destination.hexhash = announce_destination.hash.hex() - + new_packet = RNS.Packet( announce_destination, announce_data, @@ -423,7 +423,7 @@ class Transport: RNS.log(f"Rebroadcasting announce as path response for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG) else: RNS.log(f"Rebroadcasting announce for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG) - + outgoing.append(new_packet) # This handles an edge case where a peer sends a past @@ -486,7 +486,7 @@ class Transport: path_request_throttle = time.time() - last_path_request < Transport.PATH_REQUEST_MI path_request_conditions = False - + # If the path has been invalidated between the time of # making the link request and now, try to rediscover it if not Transport.has_path(link_entry[6]): @@ -726,7 +726,7 @@ class Transport: # Assemble new payload with IFAC new_raw = new_header+ifac+raw[2:] - + # Mask payload i = 0; masked_raw = b"" for byte in new_raw: @@ -781,7 +781,7 @@ class Transport: if generate_receipt: packet.receipt = RNS.PacketReceipt(packet) Transport.receipts.append(packet.receipt) - + # TODO: Enable when caching has been redesigned # Transport.cache(packet) @@ -850,7 +850,7 @@ class Transport: should_transmit = False if interface != packet.destination.attached_interface: should_transmit = False - + if packet.attached_interface != None and interface != packet.attached_interface: should_transmit = False @@ -919,7 +919,7 @@ class Transport: tx_time = (len(packet.raw)*8) / interface.bitrate wait_time = (tx_time / interface.announce_cap) interface.announce_allowed_at = outbound_time + wait_time - + else: should_transmit = False if not len(interface.announce_queue) >= RNS.Reticulum.MAX_QUEUED_ANNOUNCES: @@ -979,10 +979,10 @@ class Transport: else: pass - + else: pass - + if should_transmit: if not stored_hash: Transport.packet_hashlist.append(packet.packet_hash) @@ -1134,14 +1134,14 @@ class Transport: if Transport.identity == None: return - + Transport.jobs_locked = True - + packet = RNS.Packet(None, raw) if not packet.unpack(): Transport.jobs_locked = False return - + packet.receiving_interface = interface packet.hops += 1 @@ -1205,7 +1205,7 @@ class Transport: Transport.packet_hashlist.append(packet.packet_hash) # TODO: Enable when caching has been redesigned # Transport.cache(packet) - + # Check special conditions for local clients connected # through a shared Reticulum instance from_local_client = (packet.receiving_interface in Transport.local_client_interfaces) @@ -1262,7 +1262,7 @@ class Transport: if packet.destination_hash in Transport.destination_table: next_hop = Transport.destination_table[packet.destination_hash][1] remaining_hops = Transport.destination_table[packet.destination_hash][2] - + if remaining_hops > 1: # Just increase hop count and transmit new_raw = packet.raw[0:1] @@ -1356,7 +1356,7 @@ class Transport: new_raw += packet.raw[2:] Transport.transmit(outbound_interface, new_raw) Transport.link_table[packet.destination_hash][0] = time.time() - + # TODO: Test and possibly enable this at some point # Transport.jobs_locked = False # return @@ -1383,13 +1383,13 @@ class Transport: if local_destination == None and RNS.Identity.validate_announce(packet): if packet.transport_id != None: received_from = packet.transport_id - + # Check if this is a next retransmission from # another node. If it is, we're removing the # announce in question from our pending table if RNS.Reticulum.transport_enabled() and packet.destination_hash in Transport.announce_table: announce_entry = Transport.announce_table[packet.destination_hash] - + if packet.hops-1 == announce_entry[4]: RNS.log(f"Heard a local rebroadcast of announce for {RNS.prettyhexrep(packet.destination_hash)}", RNS.LOG_DEBUG) announce_entry[6] += 1 @@ -1415,7 +1415,7 @@ class Transport: # local to this system, and that hops are less than the max if (not any(packet.destination_hash == d.hash for d in Transport.destinations) and packet.hops < Transport.PATHFINDER_M+1): announce_emitted = Transport.announce_emitted(packet) - + random_blob = packet.data[RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8+10] random_blobs = [] if packet.destination_hash in Transport.destination_table: @@ -1442,7 +1442,7 @@ class Transport: # the emission timestamp is more recent. now = time.time() path_expires = Transport.destination_table[packet.destination_hash][3] - + path_announce_emitted = 0 for path_random_blob in random_blobs: path_announce_emitted = max(path_announce_emitted, int.from_bytes(path_random_blob[5:10], "big")) @@ -1474,7 +1474,7 @@ class Transport: should_add = True else: should_add = False - + # If we have already heard this announce before, # but the path has been marked as unresponsive # by a failed communications attempt or similar, @@ -1527,14 +1527,14 @@ class Transport: else: rate_blocked = True - + retries = 0 announce_hops = packet.hops local_rebroadcasts = 0 block_rebroadcasts = False attached_interface = None - + retransmit_timeout = now + (RNS.rand() * Transport.PATHFINDER_RW) if hasattr(packet.receiving_interface, "mode") and packet.receiving_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ACCESS_POINT: @@ -1543,7 +1543,7 @@ class Transport: expires = now + Transport.ROAMING_PATH_TIME else: expires = now + Transport.PATHFINDER_E - + random_blobs.append(random_blob) random_blobs = random_blobs[-Transport.MAX_RANDOM_BLOBS:] @@ -1552,7 +1552,7 @@ class Transport: if rate_blocked: RNS.log(f"Blocking rebroadcast of announce from {RNS.prettyhexrep(packet.destination_hash)} due to excessive announce rate", RNS.LOG_DEBUG) - + else: if Transport.from_local_client(packet): # If the announce is from a local client, @@ -1619,7 +1619,7 @@ class Transport: attached_interface = local_interface, context_flag = packet.context_flag, ) - + new_announce.hops = packet.hops new_announce.send() @@ -1730,7 +1730,7 @@ class Transport: if destination.hash == packet.destination_hash and destination.type == packet.destination_type: packet.destination = destination destination.receive(packet) - + # Handling for local data packets elif packet.packet_type == RNS.Packet.DATA: if packet.destination_type == RNS.Destination.LINK: @@ -1835,7 +1835,7 @@ class Transport: for link in Transport.active_links: if link.link_id == packet.destination_hash: packet.link = link - + if len(packet.data) == RNS.PacketReceipt.EXPL_LENGTH: proof_hash = packet.data[:RNS.Identity.HASHLENGTH//8] else: @@ -1875,13 +1875,13 @@ class Transport: interface_hash = interface.get_hash() public_key = RNS.Transport.identity.get_public_key() random_hash = RNS.Identity.get_random_hash() - + tunnel_id_data = public_key+interface_hash tunnel_id = RNS.Identity.full_hash(tunnel_id_data) signed_data = tunnel_id_data+random_hash signature = Transport.identity.sign(signed_data) - + data = signed_data+signature tnl_snth_dst = RNS.Destination(None, RNS.Destination.OUT, RNS.Destination.PLAIN, Transport.APP_NAME, "tunnel", "synthesize") @@ -1901,7 +1901,7 @@ class Transport: tunnel_id_data = public_key+interface_hash tunnel_id = RNS.Identity.full_hash(tunnel_id_data) random_hash = data[RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8+RNS.Reticulum.TRUNCATED_HASHLENGTH//8] - + signature = data[RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8+RNS.Reticulum.TRUNCATED_HASHLENGTH//8:expected_length] signed_data = tunnel_id_data+random_hash @@ -1974,7 +1974,7 @@ class Transport: for registered_destination in Transport.destinations: if destination.hash == registered_destination.hash: raise KeyError("Attempt to register an already registered destination.") - + Transport.destinations.append(destination) if Transport.owner.is_connected_to_shared_instance: @@ -2061,7 +2061,7 @@ class Transport: if packet.receiving_interface != None: interface_reference = str(packet.receiving_interface) - file = open(f"{RNS.Reticulum.cachepath}/{packet_hash}", "wb") + file = open(f"{RNS.Reticulum.cachepath}/{packet_hash}", "wb") file.write(umsgpack.packb([packet.raw, interface_reference])) file.close() @@ -2419,11 +2419,11 @@ class Transport: if len(Transport.local_client_interfaces) > 0: if destination_hash in Transport.destination_table: destination_interface = Transport.destination_table[destination_hash][5] - + if Transport.is_local_client_interface(destination_interface): destination_exists_on_local_client = True Transport.pending_local_path_requests[destination_hash] = attached_interface - + local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None) if local_destination != None: local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface) @@ -2436,7 +2436,7 @@ class Transport: if attached_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING and attached_interface == received_from: RNS.log("Not answering path request on roaming-mode interface, since next hop is on same roaming-mode interface", RNS.LOG_DEBUG) - + else: if requestor_transport_id != None and next_hop == requestor_transport_id: # TODO: Find a bandwidth efficient way to invalidate our @@ -2480,7 +2480,7 @@ class Transport: if packet.destination_hash in Transport.announce_table: held_entry = Transport.announce_table[packet.destination_hash] Transport.held_announces[packet.destination_hash] = held_entry - + Transport.announce_table[packet.destination_hash] = [now, retransmit_timeout, retries, received_from, announce_hops, packet, local_rebroadcasts, block_rebroadcasts, attached_interface] elif is_from_local_client: @@ -2554,7 +2554,7 @@ class Transport: detachable_interfaces.append(interface) else: pass - + for interface in Transport.local_client_interfaces: # Currently no rules are being applied # here, and all interfaces will be sent diff --git a/RNS/Utilities/rncp.py b/RNS/Utilities/rncp.py index 6ae0045..979af5f 100644 --- a/RNS/Utilities/rncp.py +++ b/RNS/Utilities/rncp.py @@ -58,7 +58,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): - identity = RNS.Identity.from_file(identity_path) + identity = RNS.Identity.from_file(identity_path) if identity == None: RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO) @@ -102,7 +102,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi ms = "y" else: ms = "ies" - + RNS.log(f"Loaded {len(ali)} allowed identit{ms} from {allowed_file}", RNS.LOG_VERBOSE) except Exception as e: @@ -180,7 +180,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi destination.announce() threading.Thread(target=job, daemon=True).start() - + while True: time.sleep(1) @@ -206,7 +206,7 @@ def receive_sender_identified(link, identity): def receive_resource_callback(resource): global allow_all - + sender_identity = resource.link.get_remote_identity() if sender_identity != None: @@ -239,7 +239,7 @@ def receive_resource_concluded(resource): while os.path.isfile(saved_filename): counter += 1 saved_filename = f"{filename}.{counter}" - + file = open(saved_filename, "wb") file.write(resource.data.read()) file.close() @@ -412,7 +412,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No while os.path.isfile(saved_filename): counter += 1 saved_filename = f"{filename}.{counter}" - + file = open(saved_filename, "wb") file.write(resource.data.read()) file.close() @@ -521,7 +521,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non print(str(e)) exit(1) - + file_path = os.path.expanduser(file) if not os.path.isfile(file_path): print("File not found") @@ -637,7 +637,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non sys.stdout.flush() i = (i+1)%len(syms) - + if resource.status > RNS.Resource.COMPLETE: if silent: print(f"File was not accepted by {RNS.prettyhexrep(destination_hash)}") @@ -708,7 +708,7 @@ def main(): parser.add_argument("-w", action="store", metavar="seconds", type=float, help="sender timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT) # parser.add_argument("--limit", action="store", metavar="files", type=float, help="maximum number of files to accept", default=None) parser.add_argument("--version", action="version", version=f"rncp {__version__}") - + args = parser.parse_args() if args.listen or args.print_identity: diff --git a/RNS/Utilities/rnid.py b/RNS/Utilities/rnid.py index 211f81b..2395d61 100644 --- a/RNS/Utilities/rnid.py +++ b/RNS/Utilities/rnid.py @@ -82,7 +82,7 @@ def main(): parser.add_argument("-w", "--write", metavar="file", action="store", default=None, help="output file path", type=str) parser.add_argument("-f", "--force", action="store_true", default=None, help="write output even if it overwrites existing files") parser.add_argument("-I", "--stdin", action="store_true", default=False, help=argparse.SUPPRESS) # "read input from STDIN instead of file" - parser.add_argument("-O", "--stdout", action="store_true", default=False, help=argparse.SUPPRESS) # help="write output to STDOUT instead of file", + parser.add_argument("-O", "--stdout", action="store_true", default=False, help=argparse.SUPPRESS) # help="write output to STDOUT instead of file", parser.add_argument("-R", "--request", action="store_true", default=False, help="request unknown Identities from the network") parser.add_argument("-t", action="store", metavar="seconds", type=float, help="identity request timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT) @@ -93,14 +93,14 @@ def main(): parser.add_argument("-B", "--base32", action="store_true", default=False, help="Use base32-encoded input and output") parser.add_argument("--version", action="version", version=f"rnid {__version__}") - + args = parser.parse_args() ops = 0; for t in [args.encrypt, args.decrypt, args.validate, args.sign]: if t: ops += 1 - + if ops > 1: RNS.log("This utility currently only supports one of the encrypt, decrypt, sign or verify operations per invocation", RNS.LOG_ERROR) exit(1) @@ -179,7 +179,7 @@ def main(): quietness = args.quiet if verbosity != 0 or quietness != 0: targetloglevel = targetloglevel+verbosity-quietness - + # Start Reticulum reticulum = RNS.Reticulum(configdir=args.config, loglevel=targetloglevel) RNS.compact_log_fmt = True @@ -234,7 +234,7 @@ def main(): RNS.log("Invalid hexadecimal hash provided", RNS.LOG_ERROR) exit(7) - + else: # Try loading Identity from file if not os.path.isfile(identity_str): @@ -391,7 +391,7 @@ def main(): RNS.log("Could not open output file for writing", RNS.LOG_ERROR) RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) exit(15) - + # TODO: Actually expand this to a good solution # probably need to create a wrapper that takes # into account not closing stdout when done @@ -415,12 +415,12 @@ def main(): if not args.stdout: RNS.log(f"Signing {args.read}") - + try: data_output.write(identity.sign(data_input.read())) data_output.close() data_input.close() - + if not args.stdout: if args.read: RNS.log(f"File {args.read} signed with {identity} to {args.write}") @@ -448,7 +448,7 @@ def main(): else: # if not args.stdout: # RNS.log("Verifying "+str(args.validate)+" for "+str(args.read)) - + try: try: sig_input = open(args.validate, "rb") @@ -498,7 +498,7 @@ def main(): if not args.stdout: RNS.log(f"Encrypting {args.read}") - + try: more_data = True while more_data: @@ -545,7 +545,7 @@ def main(): if not args.stdout: RNS.log(f"Decrypting {args.read}...") - + try: more_data = True while more_data: diff --git a/RNS/Utilities/rnir.py b/RNS/Utilities/rnir.py index 01c74da..403ed98 100644 --- a/RNS/Utilities/rnir.py +++ b/RNS/Utilities/rnir.py @@ -49,7 +49,7 @@ def main(): parser.add_argument('-q', '--quiet', action='count', default=0) parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit") parser.add_argument("--version", action="version", version=f"ir {__version__}") - + args = parser.parse_args() if args.exampleconfig: diff --git a/RNS/Utilities/rnodeconf.py b/RNS/Utilities/rnodeconf.py index fc4601d..df19660 100755 --- a/RNS/Utilities/rnodeconf.py +++ b/RNS/Utilities/rnodeconf.py @@ -61,7 +61,7 @@ class KISS(): FESC = 0xDB TFEND = 0xDC TFESC = 0xDD - + CMD_UNKNOWN = 0xFE CMD_DATA = 0x00 CMD_FREQUENCY = 0x01 @@ -104,11 +104,11 @@ class KISS(): DETECT_REQ = 0x73 DETECT_RESP = 0x46 - + RADIO_STATE_OFF = 0x00 RADIO_STATE_ON = 0x01 RADIO_STATE_ASK = 0xFF - + CMD_ERROR = 0x90 ERROR_INITRADIO = 0x01 ERROR_TXFAILED = 0x02 @@ -191,7 +191,7 @@ class ROM(): PRODUCT_TECHO = 0x15 MODEL_T4 = 0x16 MODEL_T9 = 0x17 - + PRODUCT_HMBRW = 0xF0 MODEL_FF = 0xFF MODEL_FE = 0xFE @@ -610,7 +610,7 @@ class RNode(): self.detected = True else: self.detected = False - + else: time_since_last = int(time.time()*1000) - last_read_ms if len(data_buffer) > 0 and time_since_last > self.timeout: @@ -886,7 +886,7 @@ class RNode(): from cryptography.hazmat.primitives.serialization import load_der_private_key from cryptography.hazmat.primitives.asymmetric import padding - # Try loading local signing key for + # Try loading local signing key for # validation of self-signed devices if os.path.isdir(FWD_DIR) and os.path.isfile(FWD_DIR+"/signing.key"): private_bytes = None @@ -922,7 +922,7 @@ class RNode(): RNS.log("Could not deserialize local signing key") RNS.log(str(e)) - # Try loading trusted signing key for + # Try loading trusted signing key for # validation of devices if os.path.isdir(TK_DIR): for f in os.listdir(TK_DIR): @@ -1230,11 +1230,11 @@ def rnode_open_serial(port): write_timeout = None, dsrdtr = False ) - - + + def graceful_exit(C=0): if RNS.vendor.platformutils.is_windows(): - RNS.log("Windows detected; delaying DTR",RNS.LOG_VERBOSE) + RNS.log("Windows detected; delaying DTR",RNS.LOG_VERBOSE) if rnode: RNS.log("Sending \"Leave\" to Rnode",RNS.LOG_VERBOSE) rnode.leave() # Leave has wait built in @@ -1319,13 +1319,13 @@ def main(): parser.add_argument("-f", "--flash", action="store_true", help="Flash firmware and bootstrap EEPROM") parser.add_argument("-r", "--rom", action="store_true", help="Bootstrap EEPROM without flashing firmware") - parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") # + parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") # parser.add_argument("-S", "--sign", action="store_true", help="Display public part of signing key") parser.add_argument("-H", "--firmware-hash", action="store", help="Display installed firmware hash") parser.add_argument("-K", "--get-target-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get target firmware hash from device parser.add_argument("-L", "--get-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get calculated firmware hash from device parser.add_argument("--platform", action="store", metavar="platform", type=str, default=None, help="Platform specification for device bootstrap") - parser.add_argument("--product", action="store", metavar="product", type=str, default=None, help="Product specification for device bootstrap") # + parser.add_argument("--product", action="store", metavar="product", type=str, default=None, help="Product specification for device bootstrap") # parser.add_argument("--model", action="store", metavar="model", type=str, default=None, help="Model code for device bootstrap") parser.add_argument("--hwrev", action="store", metavar="revision", type=int, default=None, help="Hardware revision for device bootstrap") @@ -1354,7 +1354,7 @@ def main(): if args.fw_version != None: selected_version = args.fw_version - try: + try: check_float = float(selected_version) except ValueError: RNS.log("Selected version \""+selected_version+"\" does not appear to be a number.") @@ -1368,7 +1368,7 @@ def main(): if args.nocheck: upd_nocheck = True - + if args.public or args.key or args.flash or args.rom or args.autoinstall or args.trust_key: from cryptography.hazmat.primitives import hashes from cryptography.hazmat.backends import default_backend @@ -1419,8 +1419,8 @@ def main(): ports = list_ports.comports() portlist = [] for port in ports: - portlist.insert(0, port) - + portlist.insert(0, port) + pi = 1 print("Detected serial ports:") for port in portlist: @@ -1556,8 +1556,8 @@ def main(): ports = list_ports.comports() portlist = [] for port in ports: - portlist.insert(0, port) - + portlist.insert(0, port) + pi = 1 print("Detected serial ports:") for port in portlist: @@ -1638,7 +1638,7 @@ def main(): print("correct firmware and provision it.") else: print("\nIt looks like this is a fresh device with no RNode firmware.") - + print("") print("What kind of device is this?\n") print("[1] A specific kind of RNode") @@ -2224,7 +2224,7 @@ def main(): fw_filename = "rnode_firmware.hex" elif selected_mcu == ROM.MCU_2560: fw_filename = "rnode_firmware_m2560.hex" - + elif selected_platform == ROM.PLATFORM_ESP32: fw_filename = None print("\nWhat kind of ESP32 board is this?\n") @@ -2337,7 +2337,7 @@ def main(): except Exception as e: RNS.log("Could not load device signing key") - + graceful_exit() @@ -2413,7 +2413,7 @@ def main(): return part_hash else: return None - + elif platform == ROM.PLATFORM_NRF52: # Calculate digest manually, as it is not included in the image. firmware_data = open(partition_file, "rb") @@ -2994,7 +2994,7 @@ def main(): wants_fw_provision = False if args.flash: from subprocess import call - + if fw_filename == None: fw_filename = "rnode_firmware.hex" @@ -3032,7 +3032,7 @@ def main(): RNS.log("Error while flashing") RNS.log(str(e)) graceful_exit(1) - + else: fw_src = UPD_DIR+"/"+selected_version+"/" if os.path.isfile(fw_src+fw_filename): @@ -3215,7 +3215,7 @@ def main(): update_full_path = EXT_DIR+"/extracted_rnode_firmware.version" else: update_full_path = UPD_DIR+"/"+selected_version+"/"+fw_filename - if os.path.isfile(update_full_path): + if os.path.isfile(update_full_path): try: args.info = False RNS.log("Updating RNode firmware for device on "+args.port) @@ -3468,7 +3468,7 @@ def main(): if args.autoinstall: RNS.log("Clearing old EEPROM, this will take about 15 seconds...") rnode.wipe_eeprom() - + if rnode.platform == ROM.PLATFORM_ESP32: RNS.log("Waiting for ESP32 reset...") time.sleep(6) @@ -3849,7 +3849,7 @@ def main(): else: RNS.log("This device has not been provisioned yet, cannot get firmware hash") exit(77) - + if args.get_firmware_hash: if rnode.provisioned: RNS.log(f"The actual firmware hash is: {rnode.firmware_hash.hex()}") @@ -3923,7 +3923,7 @@ def main(): except KeyboardInterrupt: print("") graceful_exit() - + graceful_exit() def extract_recovery_esptool(): diff --git a/RNS/Utilities/rnpath.py b/RNS/Utilities/rnpath.py index 353d020..21a5b34 100644 --- a/RNS/Utilities/rnpath.py +++ b/RNS/Utilities/rnpath.py @@ -235,7 +235,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, hour_rate = round(len(entry["timestamps"])/span_hours, 3) if hour_rate-int(hour_rate) == 0: hour_rate = int(hour_rate) - + if entry["rate_violations"] > 0: if entry["rate_violations"] == 1: s_str = "" @@ -245,14 +245,14 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, rv_str = f", {entry['rate_violations']} active rate violation{s_str}" else: rv_str = "" - + if entry["blocked_until"] > time.time(): bli = time.time()-(int(entry["blocked_until"])-time.time()) bl_str = f", new announces allowed in {pretty_date(int(bli))}" else: bl_str = "" - + print(f"{RNS.prettyhexrep(entry['hash'])} last heard {last_str} ago, {hour_rate} announces/hour in the last {span_str}{rv_str}{bl_str}") except Exception as e: @@ -272,7 +272,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, print("Dropping announce queues on all interfaces...") reticulum.drop_announce_queues() - + elif drop: if remote_link: if not no_output: @@ -341,7 +341,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, except Exception as e: print(str(e)) sys.exit(1) - + if not RNS.Transport.has_path(destination_hash): RNS.Transport.request_path(destination_hash) print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=" ") @@ -376,7 +376,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, print("\r \rPath not found") sys.exit(1) - + def main(): try: @@ -479,7 +479,7 @@ def main(): help="timeout before giving up on remote queries", default=RNS.Transport.PATH_REQUEST_TIMEOUT ) - + parser.add_argument( "-j", "--json", @@ -497,7 +497,7 @@ def main(): ) parser.add_argument('-v', '--verbose', action='count', default=0) - + args = parser.parse_args() if args.config: diff --git a/RNS/Utilities/rnprobe.py b/RNS/Utilities/rnprobe.py index fcf01c4..ffa2b51 100644 --- a/RNS/Utilities/rnprobe.py +++ b/RNS/Utilities/rnprobe.py @@ -38,7 +38,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v if full_name == None: print("The full destination name including application name aspects must be specified for the destination") exit() - + try: app_name, aspects = RNS.Destination.app_and_aspects_from_name(full_name) @@ -133,7 +133,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v if time.time() > _timeout: print("\r \rProbe timed out") - + else: print("\b\b ") sys.stdout.flush() @@ -162,10 +162,10 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v if reception_rssi != None: reception_stats += f" [RSSI {reception_rssi} dBm]" - + if reception_snr != None: reception_stats += f" [SNR {reception_snr} dB]" - + if reception_q != None: reception_stats += f" [Link Quality {reception_q}%]" @@ -173,7 +173,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v if receipt.proof_packet != None: if receipt.proof_packet.rssi != None: reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" - + if receipt.proof_packet.snr != None: reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" @@ -192,7 +192,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v exit(2) else: exit(0) - + def main(): try: diff --git a/RNS/Utilities/rnsd.py b/RNS/Utilities/rnsd.py index 6c75e41..d9d5d77 100755 --- a/RNS/Utilities/rnsd.py +++ b/RNS/Utilities/rnsd.py @@ -56,7 +56,7 @@ def main(): parser.add_argument('-s', '--service', action='store_true', default=False, help="rnsd is running as a service and should log to file") parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit") parser.add_argument("--version", action="version", version=f"rnsd {__version__}") - + args = parser.parse_args() if args.exampleconfig: @@ -192,7 +192,7 @@ loglevel = 4 # The following example enables communication with other # local Reticulum peers using UDP broadcasts. - + [[UDP Interface]] type = UDPInterface enabled = no @@ -235,24 +235,24 @@ loglevel = 4 # This example demonstrates a TCP server interface. # It will listen for incoming connections on the # specified IP address and port number. - + [[TCP Server Interface]] type = TCPServerInterface enabled = no # This configuration will listen on all IP # interfaces on port 4242 - + listen_ip = 0.0.0.0 listen_port = 4242 # Alternatively you can bind to a specific IP - + # listen_ip = 10.0.0.88 # listen_port = 4242 # Or a specific network device - + # device = eth0 # port = 4242 @@ -300,7 +300,7 @@ loglevel = 4 # host device before connecting. BLE # devices can be connected by name, # BLE MAC address or by any available. - + # Connect to specific device by name # port = ble://RNode 3B87 @@ -320,7 +320,7 @@ loglevel = 4 # Set TX power to 7 dBm (5 mW) txpower = 7 - # Select spreading factor 8. Valid + # Select spreading factor 8. Valid # range is 7 through 12, with 7 # being the fastest and 12 having # the longest range. @@ -349,8 +349,8 @@ loglevel = 4 # flow control can be useful. By default # it is disabled. flow_control = False - - + + # An example KISS modem interface. Useful for running # Reticulum over packet radio hardware. @@ -365,7 +365,7 @@ loglevel = 4 # Set the serial baud-rate and other # configuration parameters. - speed = 115200 + speed = 115200 databits = 8 parity = none stopbits = 1 @@ -413,7 +413,7 @@ loglevel = 4 # way, Reticulum will automatically encapsulate it's # traffic in AX.25 and also identify your stations # transmissions with your callsign and SSID. - # + # # Only do this if you really need to! Reticulum doesn't # need the AX.25 layer for anything, and it incurs extra # overhead on every packet to encapsulate in AX.25. @@ -436,7 +436,7 @@ loglevel = 4 # Set the serial baud-rate and other # configuration parameters. - speed = 115200 + speed = 115200 databits = 8 parity = none stopbits = 1 diff --git a/RNS/Utilities/rnstatus.py b/RNS/Utilities/rnstatus.py index a65fba8..9334600 100644 --- a/RNS/Utilities/rnstatus.py +++ b/RNS/Utilities/rnstatus.py @@ -161,7 +161,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= stats, link_count = remote_status except Exception as e: raise e - + except Exception as e: print(str(e)) exit(20) @@ -215,7 +215,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= if sorting == "held": interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse) - + for ifstat in interfaces: name = ifstat["name"] @@ -301,10 +301,10 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= if "airtime_short" in ifstat and "airtime_long" in ifstat: print(" Airtime : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["airtime_short"]),atl=str(ifstat["airtime_long"]))) - + if "channel_load_short" in ifstat and "channel_load_long" in ifstat: print(" Ch.Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"]))) - + if "peers" in ifstat and ifstat["peers"] != None: print(" Peers : {np} reachable".format(np=ifstat["peers"])) @@ -314,7 +314,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= if "ifac_signature" in ifstat and ifstat["ifac_signature"] != None: sigstr = "<…"+RNS.hexrep(ifstat["ifac_signature"][-5:], delimit=False)+">" print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr)) - + if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None: print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"]))) @@ -324,14 +324,14 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= print(" Queued : {np} announce".format(np=aqn)) else: print(" Queued : {np} announces".format(np=aqn)) - + if astats and "held_announces" in ifstat and ifstat["held_announces"] != None and ifstat["held_announces"] > 0: aqn = ifstat["held_announces"] if aqn == 1: print(" Held : {np} announce".format(np=aqn)) else: print(" Held : {np} announces".format(np=aqn)) - + if astats and "incoming_announce_frequency" in ifstat and ifstat["incoming_announce_frequency"] != None: print(" Announces : {iaf}↑".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"]))) print(" {iaf}↓".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"]))) @@ -357,7 +357,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json= print(f"\n{lstr}") print("") - + else: if not remote: print("Could not get RNS status") @@ -378,7 +378,7 @@ def main(): help="show all interfaces", default=False ) - + parser.add_argument( "-A", "--announce-stats", @@ -386,7 +386,7 @@ def main(): help="show announce stats", default=False ) - + parser.add_argument( "-l", "--link-stats", @@ -394,7 +394,7 @@ def main(): help="show link stats", default=False, ) - + parser.add_argument( "-s", "--sort", @@ -403,7 +403,7 @@ def main(): default=None, type=str ) - + parser.add_argument( "-r", "--reverse", @@ -411,7 +411,7 @@ def main(): help="reverse sorting", default=False, ) - + parser.add_argument( "-j", "--json", @@ -450,7 +450,7 @@ def main(): parser.add_argument('-v', '--verbose', action='count', default=0) parser.add_argument("filter", nargs="?", default=None, help="only display interfaces with names including filter", type=str) - + args = parser.parse_args() if args.config: diff --git a/RNS/Utilities/rnx.py b/RNS/Utilities/rnx.py index 5a78d2c..861b2b7 100644 --- a/RNS/Utilities/rnx.py +++ b/RNS/Utilities/rnx.py @@ -45,7 +45,7 @@ def prepare_identity(identity_path): identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" if os.path.isfile(identity_path): - identity = RNS.Identity.from_file(identity_path) + identity = RNS.Identity.from_file(identity_path) if identity == None: RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO) @@ -57,7 +57,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed targetloglevel = 3+verbosity-quietness reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel) - + prepare_identity(identitypath) destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "execute") @@ -107,7 +107,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed if not disable_announce: destination.announce() - + while True: time.sleep(1) @@ -338,7 +338,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail if link == None or link.status == RNS.Link.CLOSED or link.status == RNS.Link.PENDING: link = RNS.Link(listener_destination) link.did_identify = False - + if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg=f"Establishing link with {RNS.prettyhexrep(destination_hash)}", timeout=timeout): print(f"Could not establish link with {RNS.prettyhexrep(destination_hash)}") exit(243) @@ -467,7 +467,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail else: tstr = "" print(f"Remote wrote {outlen} bytes to stdout{tstr}") - + if errlen != None and stderr != None: if len(stderr) < errlen: tstr = f", {len(stderr)} bytes displayed" @@ -548,7 +548,7 @@ def main(): parser.add_argument("--stdout", action='store', default=None, help="max size in bytes of returned stdout", type=int) parser.add_argument("--stderr", action='store', default=None, help="max size in bytes of returned stderr", type=int) parser.add_argument("--version", action="version", version=f"rnx {__version__}") - + args = parser.parse_args() if args.listen or args.print_identity: @@ -600,8 +600,8 @@ def main(): # while True: # ch = sys.stdin.read(1) # cmdbuf += ch.encode("utf-8") - # print("\r"+prompt+cmdbuf.decode("utf-8"), end="") - + # print("\r"+prompt+cmdbuf.decode("utf-8"), end="") + command = input() if command.lower() == "exit" or command.lower() == "quit": exit(0) @@ -676,7 +676,7 @@ def pretty_time(time, verbose=False): minutes = int(time // 60) time %= 60 seconds = round(time, 2) - + ss = "" if seconds == 1 else "s" sm = "" if minutes == 1 else "s" sh = "" if hours == 1 else "s" diff --git a/RNS/__init__.py b/RNS/__init__.py index 04ee64e..f0e99a3 100755 --- a/RNS/__init__.py +++ b/RNS/__init__.py @@ -90,7 +90,7 @@ def loglevelname(level): return "Debug" if (level == LOG_EXTREME): return "Extra" - + return "Unknown" def version(): @@ -124,7 +124,7 @@ def log(msg, level=3, _override_destination = False): file = open(logfile, "a") file.write(logstring+"\n") file.close() - + if os.path.getsize(logfile) > LOG_MAXSIZE: prevfile = logfile+".1" if os.path.isfile(prevfile): @@ -138,7 +138,7 @@ def log(msg, level=3, _override_destination = False): log("Exception occurred while writing log message to log file: "+str(e), LOG_CRITICAL) log("Dumping future log events to console!", LOG_CRITICAL) log(msg, level) - + def rand(): result = instance_random.random() @@ -155,7 +155,7 @@ def hexrep(data, delimit=True): iter(data) except TypeError: data = [data] - + delimiter = ":" if not delimit: delimiter = "" @@ -228,7 +228,7 @@ def prettytime(time, verbose=False, compact=False): seconds = int(time) else: seconds = round(time, 2) - + ss = "" if seconds == 1 else "s" sm = "" if minutes == 1 else "s" sh = "" if hours == 1 else "s" @@ -272,7 +272,7 @@ def prettytime(time, verbose=False, compact=False): def prettyshorttime(time, verbose=False, compact=False): time = time*1e6 - + seconds = int(time // 1e6); time %= 1e6 milliseconds = int(time // 1e3); time %= 1e3 @@ -280,7 +280,7 @@ def prettyshorttime(time, verbose=False, compact=False): microseconds = int(time) else: microseconds = round(time, 2) - + ss = "" if seconds == 1 else "s" sms = "" if milliseconds == 1 else "s" sus = "" if microseconds == 1 else "s" @@ -365,16 +365,16 @@ def profiler(tag=None, capture=False, super_tag=None): def profiler_results(): from statistics import mean, median, stdev results = {} - + for tag in profiler_tags: tag_captures = [] tag_entry = profiler_tags[tag] - + for thread_ident in tag_entry["threads"]: thread_entry = tag_entry["threads"][thread_ident] thread_captures = thread_entry["captures"] sample_count = len(thread_captures) - + if sample_count > 2: thread_results = { "count": sample_count, diff --git a/RNS/vendor/configobj.py b/RNS/vendor/configobj.py index e84fde5..338168a 100755 --- a/RNS/vendor/configobj.py +++ b/RNS/vendor/configobj.py @@ -139,28 +139,28 @@ class UnknownType(Exception): class Builder: - + def build(self, o): if m is None: raise UnknownType(o.__class__.__name__) return m(o) - + def build_List(self, o): return list(map(self.build, o.getChildren())) - + def build_Const(self, o): return o.value - + def build_Dict(self, o): d = {} i = iter(map(self.build, o.getChildren())) for el in i: d[el] = next(i) return d - + def build_Tuple(self, o): return tuple(self.build_List(o)) - + def build_Name(self, o): if o.name == 'None': return None @@ -168,10 +168,10 @@ class Builder: return True if o.name == 'False': return False - + # An undefined Name raise UnknownType('Undefined Name') - + def build_Add(self, o): real, imag = list(map(self.build_Const, o.getChildren())) try: @@ -181,14 +181,14 @@ class Builder: if not isinstance(imag, complex) or imag.real != 0.0: raise UnknownType('Add') return real+imag - + def build_Getattr(self, o): parent = self.build(o.expr) return getattr(parent, o.attrname) - + def build_UnarySub(self, o): return -self.build_Const(o.getChildren()[0]) - + def build_UnaryAdd(self, o): return self.build_Const(o.getChildren()[0]) @@ -199,7 +199,7 @@ _builder = Builder() def unrepr(s): if not s: return s - + # this is supposed to be safe import ast return ast.literal_eval(s) @@ -304,7 +304,7 @@ class InterpolationEngine: # short-cut if not self._cookie in value: return value - + def recursive_interpolate(key, value, section, backtrail): """The function that does the actual work. @@ -404,7 +404,7 @@ class InterpolationEngine: (e.g., if we interpolated "$$" and returned "$"). """ raise NotImplementedError() - + class ConfigParserInterpolation(InterpolationEngine): @@ -453,27 +453,27 @@ interpolation_engines = { def __newobj__(cls, *args): # Hack for pickle - return cls.__new__(cls, *args) + return cls.__new__(cls, *args) class Section(dict): """ A dictionary-like object that represents a section in a config file. - + It does string interpolation if the 'interpolation' attribute of the 'main' object is set to True. - + Interpolation is tried first from this object, then from the 'DEFAULT' section of this object, next from the parent and its 'DEFAULT' section, and so on until the main object is reached. - + A Section will behave like an ordered dictionary - following the order of the ``scalars`` and ``sections`` attributes. You can use this to change the order of members. - + Iteration follows the order: scalars, then sections. """ - + def __setstate__(self, state): dict.update(self, state[0]) self.__dict__.update(state[1]) @@ -481,8 +481,8 @@ class Section(dict): def __reduce__(self): state = (dict(self), self.__dict__) return (__newobj__, (self.__class__,), state) - - + + def __init__(self, parent, depth, main, indict=None, name=None): """ * parent is the section above @@ -507,8 +507,8 @@ class Section(dict): # (rather than just passing to ``dict.__init__``) for entry, value in indict.items(): self[entry] = value - - + + def _initialise(self): # the sequence of scalar values in this Section self.scalars = [] @@ -552,7 +552,7 @@ class Section(dict): def __getitem__(self, key): """Fetch the item and do string interpolation.""" val = dict.__getitem__(self, key) - if self.main.interpolation: + if self.main.interpolation: if isinstance(val, str): return self._interpolate(key, val) if isinstance(val, list): @@ -569,20 +569,20 @@ class Section(dict): def __setitem__(self, key, value, unrepr=False): """ Correctly set a value. - + Making dictionary values Section instances. (We have to special case 'Section' instances - which are also dicts) - + Keys must be strings. Values need only be strings (or lists of strings) if ``main.stringify`` is set. - + ``unrepr`` must be set when setting a value to a dictionary, without creating a new sub-section. """ if not isinstance(key, str): raise ValueError(f'The key "{key}" is not a string.') - + # add the comment if key not in self.comments: self.comments[key] = [] @@ -683,7 +683,7 @@ class Section(dict): """ A version of clear that also affects scalars/sections Also clears comments and configspec. - + Leaves other attributes alone : depth/main/parent are not affected """ @@ -757,10 +757,10 @@ class Section(dict): def dict(self): """ Return a deepcopy of self as a dictionary. - + All members that are ``Section`` instances are recursively turned to ordinary dictionaries - by calling their ``dict`` method. - + >>> n = a.dict() >>> n == a 1 @@ -785,7 +785,7 @@ class Section(dict): def merge(self, indict): """ A recursive update - useful for merging config files. - + >>> a = '''[section1] ... option1 = True ... [[subsection]] @@ -805,17 +805,17 @@ class Section(dict): if (key in self and isinstance(self[key], dict) and isinstance(val, dict)): self[key].merge(val) - else: + else: self[key] = val def rename(self, oldkey, newkey): """ Change a keyname to another, without changing position in sequence. - + Implemented so that transformations can be made on keys, as well as on values. (used by encode and decode) - + Also renames comments. """ if oldkey in self.scalars: @@ -843,30 +843,30 @@ class Section(dict): call_on_sections=False, **keywargs): """ Walk every member and call a function on the keyword and value. - + Return a dictionary of the return values - + If the function raises an exception, raise the errror unless ``raise_errors=False``, in which case set the return value to ``False``. - + Any unrecognised keyword arguments you pass to walk, will be pased on to the function you pass in. - + Note: if ``call_on_sections`` is ``True`` then - on encountering a subsection, *first* the function is called for the *whole* subsection, and then recurses into it's members. This means your function must be able to handle strings, dictionaries and lists. This allows you to change the key of subsections as well as for ordinary members. The return value when called on the whole subsection has to be discarded. - + See the encode and decode methods for examples, including functions. - + .. admonition:: caution - + You can use ``walk`` to transform the names of members of a section but you mustn't add or delete members. - + >>> config = '''[XXXXsection] ... XXXXkey = XXXXvalue'''.splitlines() >>> cfg = ConfigObj(config) @@ -929,17 +929,17 @@ class Section(dict): Accepts a key as input. The corresponding value must be a string or the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to retain compatibility with Python 2.2. - - If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns + + If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns ``True``. - - If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns + + If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns ``False``. - + ``as_bool`` is not case sensitive. - + Any other input will raise a ``ValueError``. - + >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_bool('a') @@ -971,10 +971,10 @@ class Section(dict): def as_int(self, key): """ A convenience method which coerces the specified value to an integer. - + If the value is an invalid literal for ``int``, a ``ValueError`` will be raised. - + >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_int('a') @@ -994,10 +994,10 @@ class Section(dict): def as_float(self, key): """ A convenience method which coerces the specified value to a float. - + If the value is an invalid literal for ``float``, a ``ValueError`` will be raised. - + >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_float('a') #doctest: +IGNORE_EXCEPTION_DETAIL @@ -1011,13 +1011,13 @@ class Section(dict): 3.2... """ return float(self[key]) - - + + def as_list(self, key): """ A convenience method which fetches the specified value, guaranteeing that it is a list. - + >>> a = ConfigObj() >>> a['a'] = 1 >>> a.as_list('a') @@ -1033,15 +1033,15 @@ class Section(dict): if isinstance(result, (tuple, list)): return list(result) return [result] - + def restore_default(self, key): """ Restore (and return) default value for the specified key. - + This method will only work for a ConfigObj that was created with a configspec and has been validated. - + If there is no default value for this key, ``KeyError`` is raised. """ default = self.default_values[key] @@ -1050,20 +1050,20 @@ class Section(dict): self.defaults.append(key) return default - + def restore_defaults(self): """ Recursively restore default values to all members that have them. - + This method will only work for a ConfigObj that was created with a configspec and has been validated. - + It doesn't delete or modify entries without default values. """ for key in self.default_values: self.restore_default(key) - + for section in self.sections: self[section].restore_defaults() @@ -1178,7 +1178,7 @@ class ConfigObj(Section): write_empty_values=False, _inspec=False): """ Parse a config file or create a config file object. - + ``ConfigObj(infile=None, configspec=None, encoding=None, interpolation=True, raise_errors=False, list_values=True, create_empty=False, file_error=False, stringify=True, @@ -1188,9 +1188,9 @@ class ConfigObj(Section): self._inspec = _inspec # init the superclass Section.__init__(self, self, 0, self) - + infile = infile or [] - + _options = {'configspec': configspec, 'encoding': encoding, 'interpolation': interpolation, 'raise_errors': raise_errors, 'list_values': list_values, @@ -1206,7 +1206,7 @@ class ConfigObj(Section): warnings.warn('Passing in an options dictionary to ConfigObj() is ' 'deprecated. Use **options instead.', DeprecationWarning, stacklevel=2) - + # TODO: check the values too. for entry in options: if entry not in OPTION_DEFAULTS: @@ -1217,18 +1217,18 @@ class ConfigObj(Section): keyword_value = _options[entry] if value != keyword_value: options[entry] = keyword_value - + # XXXX this ignores an explicit list_values = True in combination # with _inspec. The user should *never* do that anyway, but still... if _inspec: options['list_values'] = False - + self._initialise(options) configspec = options['configspec'] self._original_configspec = configspec self._load(infile, configspec) - - + + def _load(self, infile, configspec): if isinstance(infile, str): self.filename = infile @@ -1246,10 +1246,10 @@ class ConfigObj(Section): with open(infile, 'w') as h: h.write('') content = [] - + elif isinstance(infile, (list, tuple)): content = list(infile) - + elif isinstance(infile, dict): # initialise self # the Section class handles creating subsections @@ -1262,18 +1262,18 @@ class ConfigObj(Section): this_section[section] = {} set_section(in_section[section], this_section[section]) set_section(infile, self) - + else: for entry in infile: self[entry] = infile[entry] del self._errors - + if configspec is not None: self._handle_configspec(configspec) else: self.configspec = None return - + elif getattr(infile, 'read', MISSING) is not MISSING: # This supports file like objects content = infile.read() or [] @@ -1300,7 +1300,7 @@ class ConfigObj(Section): assert all(isinstance(line, str) for line in content), repr(content) content = [line.rstrip('\r\n') for line in content] - + self._parse(content) # if we had any errors, now is the time to raise them if self._errors: @@ -1318,17 +1318,17 @@ class ConfigObj(Section): raise error # delete private attributes del self._errors - + if configspec is None: self.configspec = None else: self._handle_configspec(configspec) - - + + def _initialise(self, options=None): if options is None: options = OPTION_DEFAULTS - + # initialise a few variables self.filename = None self._errors = [] @@ -1345,18 +1345,18 @@ class ConfigObj(Section): self.newlines = None self.write_empty_values = options['write_empty_values'] self.unrepr = options['unrepr'] - + self.initial_comment = [] self.final_comment = [] self.configspec = None - + if self._inspec: self.list_values = False - + # Clear section attributes as well Section._initialise(self) - - + + def __repr__(self): def _getval(key): try: @@ -1364,27 +1364,27 @@ class ConfigObj(Section): except MissingInterpolationOption: return dict.__getitem__(self, key) return ('ConfigObj({%s})' % ', '.join([f'{key!r}: {_getval(key)!r}' for key in (self.scalars + self.sections)])) - - + + def _handle_bom(self, infile): """ Handle any BOM, and decode if necessary. - + If an encoding is specified, that *must* be used - but the BOM should still be removed (and the BOM attribute set). - + (If the encoding is wrongly specified, then a BOM for an alternative encoding won't be discovered or removed.) - + If an encoding is not specified, UTF8 or UTF16 BOM will be detected and removed. The BOM attribute will be set. UTF16 will be decoded to unicode. - + NOTE: This method must not be called with an empty ``infile``. - + Specifying the *wrong* encoding is likely to cause a ``UnicodeDecodeError``. - + ``infile`` must always be returned as a list of lines, but may be passed in as a single string. """ @@ -1395,7 +1395,7 @@ class ConfigObj(Section): # the encoding specified doesn't have one # just decode return self._decode(infile, self.encoding) - + if isinstance(infile, (list, tuple)): line = infile[0] else: @@ -1424,18 +1424,18 @@ class ConfigObj(Section): ##self.BOM = True # Don't need to remove BOM return self._decode(infile, encoding) - + # If we get this far, will *probably* raise a DecodeError # As it doesn't appear to start with a BOM return self._decode(infile, self.encoding) - + # Must be UTF8 BOM = BOM_SET[enc] if not line.startswith(BOM): return self._decode(infile, self.encoding) - + newline = line[len(BOM):] - + # BOM removed if isinstance(infile, (list, tuple)): infile[0] = newline @@ -1443,7 +1443,7 @@ class ConfigObj(Section): infile = newline self.BOM = True return self._decode(infile, self.encoding) - + # No encoding specified - so we need to check for UTF8/UTF16 for BOM, (encoding, final_encoding) in list(BOMS.items()): if not isinstance(line, bytes) or not line.startswith(BOM): @@ -1470,7 +1470,7 @@ class ConfigObj(Section): return self._decode(infile, 'utf-8') # UTF16 - have to decode return self._decode(infile, encoding) - + if six.PY2 and isinstance(line, str): # don't actually do any decoding, since we're on python 2 and @@ -1494,7 +1494,7 @@ class ConfigObj(Section): def _decode(self, infile, encoding): """ Decode infile to unicode. Using the specified encoding. - + if is a string, it also needs converting to a list. """ if isinstance(infile, str): @@ -1543,14 +1543,14 @@ class ConfigObj(Section): temp_list_values = self.list_values if self.unrepr: self.list_values = False - + comment_list = [] done_start = False this_section = self maxline = len(infile) - 1 cur_index = -1 reset_comment = False - + while cur_index < maxline: if reset_comment: comment_list = [] @@ -1562,13 +1562,13 @@ class ConfigObj(Section): reset_comment = False comment_list.append(line) continue - + if not done_start: # preserve initial comment self.initial_comment = comment_list comment_list = [] done_start = True - + reset_comment = True # first we check if it's a section marker mat = self._sectionmarker.match(line) @@ -1582,7 +1582,7 @@ class ConfigObj(Section): self._handle_error("Cannot compute the section depth", NestingError, infile, cur_index) continue - + if cur_depth < this_section.depth: # the new section is dropping back to a previous level try: @@ -1602,13 +1602,13 @@ class ConfigObj(Section): self._handle_error("Section too nested", NestingError, infile, cur_index) continue - + sect_name = self._unquote(sect_name) if sect_name in parent: self._handle_error('Duplicate section name', DuplicateError, infile, cur_index) continue - + # create the new section this_section = Section( parent, @@ -1709,7 +1709,7 @@ class ConfigObj(Section): """ Given a section and a depth level, walk back through the sections parents to see if the depth level matches a previous section. - + Return a reference to the right section, or raise a SyntaxError. """ @@ -1727,7 +1727,7 @@ class ConfigObj(Section): def _handle_error(self, text, ErrorClass, infile, cur_index): """ Handle an error according to the error settings. - + Either raise the error or store it. The error will have occured at ``cur_index`` """ @@ -1756,19 +1756,19 @@ class ConfigObj(Section): def _quote(self, value, multiline=True): """ Return a safely quoted version of a value. - + Raise a ConfigObjError if the value cannot be safely quoted. If multiline is ``True`` (default) then use triple quotes if necessary. - + * Don't quote values that don't need it. * Recursively quote members of a list and return a comma joined list. * Multiline is ``False`` for lists. * Obey list syntax for empty and single member lists. - + If ``list_values=False`` then the value is only quoted if it contains a ``\\n`` (is multiline) or '#'. - + If ``write_empty_values`` is set, and the value is an empty string, it won't be quoted. """ @@ -1776,7 +1776,7 @@ class ConfigObj(Section): # Only if multiline is set, so that it is used for values not # keys, and not values that are part of a list return '' - + if multiline and isinstance(value, (list, tuple)): if not value: return ',' @@ -1794,12 +1794,12 @@ class ConfigObj(Section): if not value: return '""' - + no_lists_no_quotes = not self.list_values and '\n' not in value and '#' not in value need_triple = multiline and ((("'" in value) and ('"' in value)) or ('\n' in value )) hash_triple_quote = multiline and not need_triple and ("'" in value) and ('"' in value) and ('#' in value) check_for_single = (no_lists_no_quotes or not need_triple) and not hash_triple_quote - + if check_for_single: if not self.list_values: # we don't quote if ``list_values=False`` @@ -1817,13 +1817,13 @@ class ConfigObj(Section): else: # if value has '\n' or "'" *and* '"', it will need triple quotes quot = self._get_triple_quote(value) - + if quot == noquot and '#' in value and self.list_values: quot = self._get_single_quote(value) - + return quot % value - - + + def _get_single_quote(self, value): if ("'" in value) and ('"' in value): raise ConfigObjError(f'Value "{value}" cannot be safely quoted.') @@ -1832,15 +1832,15 @@ class ConfigObj(Section): else: quot = dquot return quot - - + + def _get_triple_quote(self, value): if (value.find('"""') != -1) and (value.find("'''") != -1): raise ConfigObjError(f'Value "{value}" cannot be safely quoted.') if value.find('"""') == -1: quot = tdquot else: - quot = tsquot + quot = tsquot return quot @@ -1930,7 +1930,7 @@ class ConfigObj(Section): def _handle_configspec(self, configspec): """Parse the configspec.""" - # FIXME: Should we check that the configspec was created with the + # FIXME: Should we check that the configspec was created with the # correct settings ? (i.e. ``list_values=False``) if not isinstance(configspec, ConfigObj): try: @@ -1944,11 +1944,11 @@ class ConfigObj(Section): raise ConfigspecError(f'Parsing configspec failed: {e}') except OSError as e: raise OSError(f'Reading configspec failed: {e}') - - self.configspec = configspec - - + self.configspec = configspec + + + def _set_configspec(self, section, copy): """ Called by validate. Handles setting the configspec on subsections @@ -1960,7 +1960,7 @@ class ConfigObj(Section): for entry in section.sections: if entry not in configspec: section[entry].configspec = many - + for entry in configspec.sections: if entry == '__many__': continue @@ -1971,11 +1971,11 @@ class ConfigObj(Section): # copy comments section.comments[entry] = configspec.comments.get(entry, []) section.inline_comments[entry] = configspec.inline_comments.get(entry, '') - + # Could be a scalar when we expect a section if isinstance(section[entry], Section): section[entry].configspec = configspec[entry] - + def _write_line(self, indent_string, entry, this_entry, comment): """Write an individual line, for the write method""" @@ -2007,9 +2007,9 @@ class ConfigObj(Section): def write(self, outfile=None, section=None): """ Write the current ConfigObj as a file - + tekNico: FIXME: use StringIO instead of real files - + >>> filename = a.filename >>> a.filename = 'test.ini' >>> a.write() @@ -2022,7 +2022,7 @@ class ConfigObj(Section): if self.indent_type is None: # this can be true if initialised from a dictionary self.indent_type = DEFAULT_INDENT_TYPE - + out = [] cs = self._a_to_u('#') csp = self._a_to_u('# ') @@ -2036,7 +2036,7 @@ class ConfigObj(Section): if stripped_line and not stripped_line.startswith(cs): line = csp + line out.append(line) - + indent_string = self.indent_type * section.depth for entry in (section.scalars + section.sections): if entry in section.defaults: @@ -2049,7 +2049,7 @@ class ConfigObj(Section): out.append(indent_string + comment_line) this_entry = section[entry] comment = self._handle_comment(section.inline_comments[entry]) - + if isinstance(this_entry, Section): # a section out.append(self._write_marker( @@ -2064,7 +2064,7 @@ class ConfigObj(Section): entry, this_entry, comment)) - + if section is self: for line in self.final_comment: line = self._decode_element(line) @@ -2073,10 +2073,10 @@ class ConfigObj(Section): line = csp + line out.append(line) self.interpolation = int_val - + if section is not self: return out - + if (self.filename is None) and (outfile is None): # output a list of lines # might need to encode @@ -2090,7 +2090,7 @@ class ConfigObj(Section): out.append('') out[0] = BOM_UTF8 + out[0] return out - + # Turn the list to a string, joined with correct newlines newline = self.newlines or os.linesep if (getattr(outfile, 'mode', None) is not None and outfile.mode == 'w' @@ -2122,34 +2122,34 @@ class ConfigObj(Section): section=None): """ Test the ConfigObj against a configspec. - + It uses the ``validator`` object from *validate.py*. - + To run ``validate`` on the current ConfigObj, call: :: - + test = config.validate(validator) - + (Normally having previously passed in the configspec when the ConfigObj was created - you can dynamically assign a dictionary of checks to the ``configspec`` attribute of a section though). - + It returns ``True`` if everything passes, or a dictionary of pass/fails (True/False). If every member of a subsection passes, it will just have the value ``True``. (It also returns ``False`` if all members fail). - + In addition, it converts the values from strings to their native types if their checks pass (and ``stringify`` is set). - + If ``preserve_errors`` is ``True`` (``False`` is default) then instead of a marking a fail with a ``False``, it will preserve the actual exception object. This can contain info about the reason for failure. For example the ``VdtValueTooSmallError`` indicates that the value supplied was too small. If a value (or section) is missing it will still be marked as ``False``. - + You must have the validate module to use ``preserve_errors=True``. - + You can then use the ``flatten_errors`` function to turn your nested results dictionary into a flattened list of failures - useful for displaying meaningful error messages. @@ -2162,7 +2162,7 @@ class ConfigObj(Section): # Which makes importing configobj faster from validate import VdtMissingValue self._vdtMissingValue = VdtMissingValue - + section = self if copy: @@ -2172,23 +2172,23 @@ class ConfigObj(Section): section.BOM = section.configspec.BOM section.newlines = section.configspec.newlines section.indent_type = section.configspec.indent_type - + # # section.default_values.clear() #?? configspec = section.configspec self._set_configspec(section, copy) - + def validate_entry(entry, spec, val, missing, ret_true, ret_false): section.default_values.pop(entry, None) - + try: section.default_values[entry] = validator.get_default_value(configspec[entry]) except (KeyError, AttributeError, validator.baseErrorClass): # No default, bad default or validator has no 'get_default_value' # (e.g. SimpleVal) pass - + try: check = validator.check(spec, val, @@ -2222,16 +2222,16 @@ class ConfigObj(Section): if not copy and missing and entry not in section.defaults: section.defaults.append(entry) return ret_true, ret_false - + # out = {} ret_true = True ret_false = True - + unvalidated = [k for k in section.scalars if k not in configspec] - incorrect_sections = [k for k in configspec.sections if k in section.scalars] + incorrect_sections = [k for k in configspec.sections if k in section.scalars] incorrect_scalars = [k for k in configspec.scalars if k in section.sections] - + for entry in configspec.scalars: if entry in ('__many__', '___many___'): # reserved names @@ -2251,16 +2251,16 @@ class ConfigObj(Section): else: missing = False val = section[entry] - - ret_true, ret_false = validate_entry(entry, configspec[entry], val, + + ret_true, ret_false = validate_entry(entry, configspec[entry], val, missing, ret_true, ret_false) - + many = None if '__many__' in configspec.scalars: many = configspec['__many__'] elif '___many___' in configspec.scalars: many = configspec['___many___'] - + if many is not None: for entry in unvalidated: val = section[entry] @@ -2284,7 +2284,7 @@ class ConfigObj(Section): ret_false = False msg = f'Section {entry!r} was provided as a single value' out[entry] = validator.baseErrorClass(msg) - + # Missing sections will have been created as empty ones when the # configspec was read. for entry in section.sections: @@ -2305,7 +2305,7 @@ class ConfigObj(Section): ret_false = False else: ret_true = False - + section.extra_values = unvalidated if preserve_errors and not section._created: # If the section wasn't created (i.e. it wasn't missing) @@ -2334,12 +2334,12 @@ class ConfigObj(Section): self.configspec = None # Just to be sure ;-) self._original_configspec = None - - + + def reload(self): """ Reload a ConfigObj from file. - + This method raises a ``ReloadError`` if the ConfigObj doesn't have a filename attribute pointing to a file. """ @@ -2352,31 +2352,31 @@ class ConfigObj(Section): if entry == 'configspec': continue current_options[entry] = getattr(self, entry) - + configspec = self._original_configspec current_options['configspec'] = configspec - + self.clear() self._initialise(current_options) self._load(filename, configspec) - + class SimpleVal: """ A simple validator. Can be used to check that all members expected are present. - + To use it, provide a configspec with all your members in (the value given will be ignored). Pass an instance of ``SimpleVal`` to the ``validate`` method of your ``ConfigObj``. ``validate`` will return ``True`` if all members are present, or a dictionary with True/False meaning present/missing. (Whole missing sections will be replaced with ``False``) """ - + def __init__(self): self.baseErrorClass = ConfigObjError - + def check(self, check, member, missing=False): """A dummy check method, always returns the value unchanged.""" if missing: @@ -2388,32 +2388,32 @@ def flatten_errors(cfg, res, levels=None, results=None): """ An example function that will turn a nested dictionary of results (as returned by ``ConfigObj.validate``) into a flat list. - + ``cfg`` is the ConfigObj instance being checked, ``res`` is the results dictionary returned by ``validate``. - + (This is a recursive function, so you shouldn't use the ``levels`` or ``results`` arguments - they are used by the function.) - + Returns a list of keys that failed. Each member of the list is a tuple:: - + ([list of sections...], key, result) - + If ``validate`` was called with ``preserve_errors=False`` (the default) then ``result`` will always be ``False``. *list of sections* is a flattened list of sections that the key was found in. - + If the section was missing (or a section was expected and a scalar provided - or vice-versa) then key will be ``None``. - + If the value (or section) was missing then ``result`` will be ``False``. - + If ``validate`` was called with ``preserve_errors=True`` and a value was present, but failed the check, then ``result`` will be the exception object returned. You can use this as a string that describes the failure. - + For example *The value "3" is of the wrong type*. """ if levels is None: @@ -2448,21 +2448,21 @@ def get_extra_values(conf, _prepend=()): """ Find all the values and sections not in the configspec from a validated ConfigObj. - + ``get_extra_values`` returns a list of tuples where each tuple represents either an extra section, or an extra value. - - The tuples contain two values, a tuple representing the section the value + + The tuples contain two values, a tuple representing the section the value is in and the name of the extra values. For extra values in the top level section the first member will be an empty tuple. For values in the 'foo' section the first member will be ``('foo',)``. For members in the 'bar' subsection of the 'foo' section the first member will be ``('foo', 'bar')``. - + NOTE: If you call ``get_extra_values`` on a ConfigObj instance that hasn't been validated it will return an empty list. """ out = [] - + out.extend([(_prepend, name) for name in conf.extra_values]) for name in conf.sections: if name not in conf.extra_values: diff --git a/RNS/vendor/i2plib/__init__.py b/RNS/vendor/i2plib/__init__.py index ee6de01..1de6e30 100644 --- a/RNS/vendor/i2plib/__init__.py +++ b/RNS/vendor/i2plib/__init__.py @@ -1,5 +1,5 @@ """ -A modern asynchronous library for building I2P applications. +A modern asynchronous library for building I2P applications. """ from .__version__ import ( @@ -10,7 +10,7 @@ from .__version__ import ( from .sam import Destination, PrivateKey from .aiosam import ( - get_sam_socket, dest_lookup, new_destination, + get_sam_socket, dest_lookup, new_destination, create_session, stream_connect, stream_accept, Session, StreamConnection, StreamAcceptor ) diff --git a/RNS/vendor/i2plib/aiosam.py b/RNS/vendor/i2plib/aiosam.py index eccff10..25807e2 100644 --- a/RNS/vendor/i2plib/aiosam.py +++ b/RNS/vendor/i2plib/aiosam.py @@ -34,12 +34,12 @@ async def get_sam_socket(sam_address=sam.DEFAULT_ADDRESS, loop=None): writer.close() raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]() -async def dest_lookup(domain, sam_address=sam.DEFAULT_ADDRESS, +async def dest_lookup(domain, sam_address=sam.DEFAULT_ADDRESS, loop=None): - """A coroutine used to lookup a full I2P destination by .i2p domain or + """A coroutine used to lookup a full I2P destination by .i2p domain or .b32.i2p address. - :param domain: Address to be resolved, can be a .i2p domain or a .b32.i2p + :param domain: Address to be resolved, can be a .i2p domain or a .b32.i2p address. :param sam_address: (optional) SAM API address :param loop: (optional) Event loop instance @@ -56,7 +56,7 @@ async def dest_lookup(domain, sam_address=sam.DEFAULT_ADDRESS, async def new_destination(sam_address=sam.DEFAULT_ADDRESS, loop=None, sig_type=sam.Destination.default_sig_type): - """A coroutine used to generate a new destination with a private key of a + """A coroutine used to generate a new destination with a private key of a chosen signature type. :param sam_address: (optional) SAM API address @@ -70,7 +70,7 @@ async def new_destination(sam_address=sam.DEFAULT_ADDRESS, loop=None, writer.close() return sam.Destination(reply["PRIV"], has_private_key=True) -async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, +async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, loop=None, style="STREAM", signature_type=sam.Destination.default_sig_type, destination=None, options={}): @@ -80,10 +80,10 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, :param sam_address: (optional) SAM API address :param loop: (optional) Event loop instance :param style: (optional) Session style, can be STREAM, DATAGRAM, RAW - :param signature_type: (optional) If the destination is TRANSIENT, this + :param signature_type: (optional) If the destination is TRANSIENT, this signature type is used - :param destination: (optional) Destination to use in this session. Can be - a base64 encoded string, :class:`Destination` + :param destination: (optional) Destination to use in this session. Can be + a base64 encoded string, :class:`Destination` instance or None. TRANSIENT destination is used when it is None. :param options: (optional) A dict object with i2cp options @@ -111,7 +111,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, if reply.ok: if not destination: destination = sam.Destination( - reply["DESTINATION"], has_private_key=True) + reply["DESTINATION"], has_private_key=True) logger.debug(destination.base32) logger.debug(f"Session created {session_name}") return (reader, writer) @@ -119,7 +119,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS, writer.close() raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]() -async def stream_connect(session_name, destination, +async def stream_connect(session_name, destination, sam_address=sam.DEFAULT_ADDRESS, loop=None): """A coroutine used to connect to a remote I2P destination. @@ -173,16 +173,16 @@ class Session: :param sam_address: (optional) SAM API address :param loop: (optional) Event loop instance :param style: (optional) Session style, can be STREAM, DATAGRAM, RAW - :param signature_type: (optional) If the destination is TRANSIENT, this + :param signature_type: (optional) If the destination is TRANSIENT, this signature type is used - :param destination: (optional) Destination to use in this session. Can be - a base64 encoded string, :class:`Destination` + :param destination: (optional) Destination to use in this session. Can be + a base64 encoded string, :class:`Destination` instance or None. TRANSIENT destination is used when it is None. :param options: (optional) A dict object with i2cp options :return: :class:`Session` object """ - def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS, + def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS, loop=None, style="STREAM", signature_type=sam.Destination.default_sig_type, destination=None, options={}): @@ -195,9 +195,9 @@ class Session: self.options = options async def __aenter__(self): - self.reader, self.writer = await create_session(self.session_name, - sam_address=self.sam_address, loop=self.loop, style=self.style, - signature_type=self.signature_type, + self.reader, self.writer = await create_session(self.session_name, + sam_address=self.sam_address, loop=self.loop, style=self.style, + signature_type=self.signature_type, destination=self.destination, options=self.options) return self @@ -214,7 +214,7 @@ class StreamConnection: :param loop: (optional) Event loop instance :return: :class:`StreamConnection` object """ - def __init__(self, session_name, destination, + def __init__(self, session_name, destination, sam_address=sam.DEFAULT_ADDRESS, loop=None): self.session_name = session_name self.sam_address = sam_address @@ -222,7 +222,7 @@ class StreamConnection: self.destination = destination async def __aenter__(self): - self.reader, self.writer = await stream_connect(self.session_name, + self.reader, self.writer = await stream_connect(self.session_name, self.destination, sam_address=self.sam_address, loop=self.loop) self.read = self.reader.read self.write = self.writer.write @@ -240,14 +240,14 @@ class StreamAcceptor: :param loop: (optional) Event loop instance :return: :class:`StreamAcceptor` object """ - def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS, + def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS, loop=None): self.session_name = session_name self.sam_address = sam_address self.loop = loop async def __aenter__(self): - self.reader, self.writer = await stream_accept(self.session_name, + self.reader, self.writer = await stream_accept(self.session_name, sam_address=self.sam_address, loop=self.loop) self.read = self.reader.read self.write = self.writer.write diff --git a/RNS/vendor/i2plib/sam.py b/RNS/vendor/i2plib/sam.py index dad8b76..2220ae8 100644 --- a/RNS/vendor/i2plib/sam.py +++ b/RNS/vendor/i2plib/sam.py @@ -8,7 +8,7 @@ I2P_B64_CHARS = "-~" def i2p_b64encode(x): """Encode I2P destination""" - return b64encode(x, altchars=I2P_B64_CHARS.encode()).decode() + return b64encode(x, altchars=I2P_B64_CHARS.encode()).decode() def i2p_b64decode(x): """Decode I2P destination""" @@ -79,9 +79,9 @@ class Destination: https://geti2p.net/spec/common-structures#destination - :param data: (optional) Base64 encoded data or binary data - :param path: (optional) A path to a file with binary data - :param has_private_key: (optional) Does data have a private key? + :param data: (optional) Base64 encoded data or binary data + :param path: (optional) A path to a file with binary data + :param has_private_key: (optional) Does data have a private key? """ ECDSA_SHA256_P256 = 1 @@ -97,12 +97,12 @@ class Destination: def __init__(self, data=None, path=None, has_private_key=False): #: Binary destination - self.data = b'' + self.data = b'' #: Base64 encoded destination - self.base64 = "" + self.base64 = "" #: :class:`RNS.vendor.i2plib.PrivateKey` instance or None - self.private_key = None - + self.private_key = None + if path: with open(path, "rb") as f: data = f.read() @@ -126,13 +126,13 @@ class Destination: """Base32 destination hash of this destination""" desthash = sha256(self.data).digest() return b32encode(desthash).decode()[:52].lower() - + class PrivateKey: """I2P private key https://geti2p.net/spec/common-structures#keysandcert - :param data: Base64 encoded data or binary data + :param data: Base64 encoded data or binary data """ def __init__(self, data): diff --git a/RNS/vendor/i2plib/tunnel.py b/RNS/vendor/i2plib/tunnel.py index aeb0f63..51fb045 100644 --- a/RNS/vendor/i2plib/tunnel.py +++ b/RNS/vendor/i2plib/tunnel.py @@ -2,7 +2,7 @@ import logging import asyncio import argparse -from . import sam +from . import sam from . import aiosam from . import utils from .log import logger @@ -29,9 +29,9 @@ async def proxy_data(reader, writer): class I2PTunnel: """Base I2P Tunnel object, not to be used directly - :param local_address: A local address to use for a tunnel. + :param local_address: A local address to use for a tunnel. E.g. ("127.0.0.1", 6668) - :param destination: (optional) Destination to use for this tunnel. Can be + :param destination: (optional) Destination to use for this tunnel. Can be a base64 encoded string, :class:`Destination` instance or None. A new destination is created when it is None. @@ -42,7 +42,7 @@ class I2PTunnel: :param sam_address: (optional) SAM API address """ - def __init__(self, local_address, destination=None, session_name=None, + def __init__(self, local_address, destination=None, session_name=None, options={}, loop=None, sam_address=sam.DEFAULT_ADDRESS): self.local_address = local_address self.destination = destination @@ -57,7 +57,7 @@ class I2PTunnel: sam_address=self.sam_address, loop=self.loop) _, self.session_writer = await aiosam.create_session( self.session_name, style=self.style, options=self.options, - sam_address=self.sam_address, + sam_address=self.sam_address, loop=self.loop, destination=self.destination) def stop(self): @@ -68,11 +68,11 @@ class ClientTunnel(I2PTunnel): """Client tunnel, a subclass of tunnel.I2PTunnel If you run a client tunnel with a local address ("127.0.0.1", 6668) and - a remote destination "irc.echelon.i2p", all connections to 127.0.0.1:6668 + a remote destination "irc.echelon.i2p", all connections to 127.0.0.1:6668 will be proxied to irc.echelon.i2p. - :param remote_destination: Remote I2P destination, can be either .i2p - domain, .b32.i2p address, base64 destination or + :param remote_destination: Remote I2P destination, can be either .i2p + domain, .b32.i2p address, base64 destination or :class:`Destination` instance """ @@ -90,12 +90,12 @@ class ClientTunnel(I2PTunnel): """Handle local client connection""" try: sc_task = aiosam.stream_connect( - self.session_name, self.remote_destination, + self.session_name, self.remote_destination, sam_address=self.sam_address, loop=self.loop) self.status["connect_tasks"].append(sc_task) - + remote_reader, remote_writer = await sc_task - asyncio.ensure_future(proxy_data(remote_reader, client_writer), + asyncio.ensure_future(proxy_data(remote_reader, client_writer), loop=self.loop) asyncio.ensure_future(proxy_data(client_reader, remote_writer), loop=self.loop) @@ -123,8 +123,8 @@ class ServerTunnel(I2PTunnel): """Server tunnel, a subclass of tunnel.I2PTunnel If you want to expose a local service 127.0.0.1:80 to the I2P network, run - a server tunnel with a local address ("127.0.0.1", 80). If you don't - provide a private key or a session name, it will use a TRANSIENT + a server tunnel with a local address ("127.0.0.1", 80). If you don't + provide a private key or a session name, it will use a TRANSIENT destination. """ def __init__(self, *args, **kwargs): @@ -139,7 +139,7 @@ class ServerTunnel(I2PTunnel): async def handle_client(incoming, client_reader, client_writer): try: # data and dest may come in one chunk - dest, data = incoming.split(b"\n", 1) + dest, data = incoming.split(b"\n", 1) remote_destination = sam.Destination(dest.decode()) logger.debug(f"{self.session_name} client connected: {remote_destination.base32}.b32.i2p") @@ -151,7 +151,7 @@ class ServerTunnel(I2PTunnel): try: sc_task = asyncio.wait_for( asyncio.open_connection( - host=self.local_address[0], + host=self.local_address[0], port=self.local_address[1]), timeout=5) self.status["connect_tasks"].append(sc_task) @@ -172,7 +172,7 @@ class ServerTunnel(I2PTunnel): try: while True: client_reader, client_writer = await aiosam.stream_accept( - self.session_name, sam_address=self.sam_address, + self.session_name, sam_address=self.sam_address, loop=self.loop) incoming = await client_reader.read(BUFFER_SIZE) asyncio.ensure_future(handle_client( @@ -192,13 +192,13 @@ if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('type', metavar="TYPE", choices=('server', 'client'), help="Tunnel type (server or client)") - parser.add_argument('address', metavar="ADDRESS", + parser.add_argument('address', metavar="ADDRESS", help="Local address (e.g. 127.0.0.1:8000)") parser.add_argument('--debug', '-d', action='store_true', help='Debugging') parser.add_argument('--key', '-k', default='', metavar='PRIVATE_KEY', help='Path to private key file') - parser.add_argument('--destination', '-D', default='', + parser.add_argument('--destination', '-D', default='', metavar='DESTINATION', help='Remote destination') args = parser.parse_args() @@ -216,10 +216,10 @@ if __name__ == '__main__': local_address = utils.address_from_string(args.address) if args.type == "client": - tunnel = ClientTunnel(args.destination, local_address, loop=loop, + tunnel = ClientTunnel(args.destination, local_address, loop=loop, destination=destination, sam_address=SAM_ADDRESS) elif args.type == "server": - tunnel = ServerTunnel(local_address, loop=loop, destination=destination, + tunnel = ServerTunnel(local_address, loop=loop, destination=destination, sam_address=SAM_ADDRESS) asyncio.ensure_future(tunnel.run(), loop=loop) diff --git a/tests/channel.py b/tests/channel.py index 85e7217..793ad8c 100644 --- a/tests/channel.py +++ b/tests/channel.py @@ -62,7 +62,7 @@ class Packet: def set_delivered_callback(self, callback: Callable[[Packet], None]): self.delivered_callback = callback - + def delivered(self): with self.lock: self.state = MessageState.MSGSTATE_DELIVERED diff --git a/tests/identity.py b/tests/identity.py index 9f66a10..990197a 100644 --- a/tests/identity.py +++ b/tests/identity.py @@ -187,7 +187,7 @@ class TestIdentity(unittest.TestCase): lb = 1 else: lb = 8 - + for i in range(1, lb): msg = os.urandom(mlen) b += mlen diff --git a/tests/link.py b/tests/link.py index 1713df7..5b61921 100644 --- a/tests/link.py +++ b/tests/link.py @@ -105,7 +105,7 @@ class TestLink(unittest.TestCase): dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish") self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) - + l1 = RNS.Link(dest) time.sleep(0.5) self.assertEqual(l1.status, RNS.Link.ACTIVE) @@ -129,7 +129,7 @@ class TestLink(unittest.TestCase): dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish") self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) - + l1 = RNS.Link(dest) time.sleep(0.5) self.assertEqual(l1.status, RNS.Link.ACTIVE) @@ -176,7 +176,7 @@ class TestLink(unittest.TestCase): if n_failed > 0: ns = "s" if n_failed != 1 else "" print(f"Failed to receive proof for {n_failed} packet{ns}") - + self.assertEqual(all_ok, True) print("OK!") print(f"Single packet and proof round-trip throughput is {self.size_str(b / pduration, 'b')}ps") @@ -201,7 +201,7 @@ class TestLink(unittest.TestCase): dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish") self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) - + l1 = RNS.Link(dest) time.sleep(0.5) self.assertEqual(l1.status, RNS.Link.ACTIVE) @@ -241,7 +241,7 @@ class TestLink(unittest.TestCase): dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish") self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) - + l1 = RNS.Link(dest) time.sleep(0.5) self.assertEqual(l1.status, RNS.Link.ACTIVE) @@ -280,7 +280,7 @@ class TestLink(unittest.TestCase): dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish") self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) - + l1 = RNS.Link(dest) time.sleep(0.5) self.assertEqual(l1.status, RNS.Link.ACTIVE) @@ -310,7 +310,7 @@ class TestLink(unittest.TestCase): if RNS.Cryptography.backend() == "internal": print("Skipping medium resource test...") return - + init_rns(self) print("") print("Medium resource test") @@ -324,7 +324,7 @@ class TestLink(unittest.TestCase): dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish") self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) - + l1 = RNS.Link(dest) time.sleep(0.5) self.assertEqual(l1.status, RNS.Link.ACTIVE) @@ -371,7 +371,7 @@ class TestLink(unittest.TestCase): dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish") self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) - + l1 = RNS.Link(dest) time.sleep(0.5) self.assertEqual(l1.status, RNS.Link.ACTIVE) @@ -553,11 +553,11 @@ class TestLink(unittest.TestCase): target_bytes = 3000 else: target_bytes = BUFFER_TEST_TARGET - + random.seed(154889) message = random.randbytes(target_bytes) buffer_read_target = len(message) - + # the return message will have an appendage string " back at you" # for every StreamDataMessage that arrives. To verify, we need # to insert that string every MAX_DATA_LEN and also at the end. @@ -572,7 +572,7 @@ class TestLink(unittest.TestCase): # StreamDataMessage, the appended text will end up in a # separate packet. print(f"Sending {len(message)} bytes, receiving {len(expected_rx_message)} bytes, ") - + buffer.write(message) buffer.flush() @@ -723,7 +723,7 @@ def profile_resource(): resource_profiling() def profile_targets(): - + targets_profiling(yp=True) # cProfile.runctx("entry()", {"entry": targets_profiling, "size_str": size_str}, {}, "profile-targets.data") # p = pstats.Stats("profile-targets.data") @@ -749,7 +749,7 @@ def resource_profiling(): import yappi yappi.start() - + resource = RNS.Resource(data, l1, timeout=resource_timeout) start = time.time()