modernize

This commit is contained in:
Pavol Rusnak 2024-10-07 10:44:18 +02:00
parent 30248854ed
commit ce9dc56048
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
78 changed files with 1414 additions and 1486 deletions

View File

@ -93,9 +93,7 @@ def announceLoop(destination_1, destination_2):
# Send the announce including the app data # Send the announce including the app data
destination_1.announce(app_data=fruit.encode("utf-8")) destination_1.announce(app_data=fruit.encode("utf-8"))
RNS.log( RNS.log(
"Sent announce from "+ f"Sent announce from {RNS.prettyhexrep(destination_1.hash)} ({destination_1.name})"
RNS.prettyhexrep(destination_1.hash)+
" ("+destination_1.name+")"
) )
# Randomly select a noble gas # Randomly select a noble gas
@ -104,9 +102,7 @@ def announceLoop(destination_1, destination_2):
# Send the announce including the app data # Send the announce including the app data
destination_2.announce(app_data=noble_gas.encode("utf-8")) destination_2.announce(app_data=noble_gas.encode("utf-8"))
RNS.log( RNS.log(
"Sent announce from "+ f"Sent announce from {RNS.prettyhexrep(destination_2.hash)} ({destination_2.name})"
RNS.prettyhexrep(destination_2.hash)+
" ("+destination_2.name+")"
) )
# We will need to define an announce handler class that # We will need to define an announce handler class that
@ -126,14 +122,12 @@ class ExampleAnnounceHandler:
# and cannot use wildcards. # and cannot use wildcards.
def received_announce(self, destination_hash, announced_identity, app_data): def received_announce(self, destination_hash, announced_identity, app_data):
RNS.log( RNS.log(
"Received an announce from "+ f"Received an announce from {RNS.prettyhexrep(destination_hash)}"
RNS.prettyhexrep(destination_hash)
) )
if app_data: if app_data:
RNS.log( RNS.log(
"The announce contained the following app data: "+ f"The announce contained the following app data: {app_data.decode('utf-8')}"
app_data.decode("utf-8")
) )
########################################################## ##########################################################

View File

@ -48,15 +48,13 @@ def program_setup(configpath, channel=None):
def packet_callback(data, packet): def packet_callback(data, packet):
# Simply print out the received data # Simply print out the received data
print("") 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() sys.stdout.flush()
def broadcastLoop(destination): def broadcastLoop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Broadcast example "+ f"Broadcast example {RNS.prettyhexrep(destination.hash)} running, enter text and hit enter to broadcast (Ctrl-C to quit)"
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. # We enter a loop that runs until the users exits.

View File

@ -61,9 +61,7 @@ def server(configpath):
def server_loop(destination): def server_loop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Link buffer example "+ f"Link buffer example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection."
RNS.prettyhexrep(destination.hash)+
" running, waiting for a connection."
) )
RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
@ -75,7 +73,7 @@ def server_loop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() 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 # When a client establishes a link to our server
# destination, this function will be called with # 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 = latest_buffer.read(ready_bytes)
data = data.decode("utf-8") 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") reply_message = reply_message.encode("utf-8")
latest_buffer.write(reply_message) latest_buffer.write(reply_message)
latest_buffer.flush() latest_buffer.flush()
@ -151,7 +149,7 @@ def client(destination_hexhash, configpath):
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: if len(destination_hexhash) != dest_len:
raise ValueError( 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) destination_hash = bytes.fromhex(destination_hexhash)
@ -223,7 +221,7 @@ def client_loop():
except Exception as e: 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 should_quit = True
server_link.teardown() server_link.teardown()
@ -262,7 +260,7 @@ def link_closed(link):
def client_buffer_ready(ready_bytes: int): def client_buffer_ready(ready_bytes: int):
global buffer global buffer
data = buffer.read(ready_bytes) 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=" ") print("> ", end=" ")
sys.stdout.flush() sys.stdout.flush()

View File

@ -124,9 +124,7 @@ def server(configpath):
def server_loop(destination): def server_loop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Link example "+ f"Link example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection."
RNS.prettyhexrep(destination.hash)+
" running, waiting for a connection."
) )
RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
@ -138,7 +136,7 @@ def server_loop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() 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 # When a client establishes a link to our server
# destination, this function will be called with # destination, this function will be called with
@ -176,9 +174,9 @@ def server_message_received(message):
# #
# #
if isinstance(message, StringMessage): 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) latest_client_link.get_channel().send(reply_message)
# Incoming messages are sent to each 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 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: if len(destination_hexhash) != dest_len:
raise ValueError( 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) destination_hash = bytes.fromhex(destination_hexhash)
@ -280,17 +278,14 @@ def client_loop():
channel.send(message) channel.send(message)
else: else:
RNS.log( RNS.log(
"Cannot send this packet, the data size of "+ f"Cannot send this packet, the data size of {packed_size} bytes exceeds the link packet MDU of {channel.MDU} bytes",
str(packed_size)+" bytes exceeds the link packet MDU of "+
str(channel.MDU)+" bytes",
RNS.LOG_ERROR RNS.LOG_ERROR
) )
else: else:
RNS.log("Channel is not ready to send, please wait for " + RNS.log(f"Channel is not ready to send, please wait for pending messages to complete.", RNS.LOG_ERROR)
"pending messages to complete.", RNS.LOG_ERROR)
except Exception as e: 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 should_quit = True
server_link.teardown() server_link.teardown()
@ -329,7 +324,7 @@ def link_closed(link):
# simply print out the data. # simply print out the data.
def client_message_received(message): def client_message_received(message):
if isinstance(message, StringMessage): 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=" ") print("> ", end=" ")
sys.stdout.flush() sys.stdout.flush()

View File

@ -64,9 +64,7 @@ def server(configpath):
def announceLoop(destination): def announceLoop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Echo server "+ f"Echo server {RNS.prettyhexrep(destination.hash)} running, hit enter to manually send an announce (Ctrl-C to quit)"
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. # We enter a loop that runs until the users exits.
@ -76,7 +74,7 @@ def announceLoop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() 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): def server_callback(message, packet):
@ -93,19 +91,19 @@ def server_callback(message, packet):
reception_snr = reticulum.get_packet_snr(packet.packet_hash) reception_snr = reticulum.get_packet_snr(packet.packet_hash)
if reception_rssi != None: if reception_rssi != None:
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += " [SNR "+str(reception_snr)+" dBm]" reception_stats += f" [SNR {reception_snr} dBm]"
else: else:
if packet.rssi != None: if packet.rssi != None:
reception_stats += " [RSSI "+str(packet.rssi)+" dBm]" reception_stats += f" [RSSI {packet.rssi} dBm]"
if packet.snr != None: 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 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: if len(destination_hexhash) != dest_len:
raise ValueError( 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) destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e: except Exception as e:
RNS.log("Invalid destination entered. Check your input!") RNS.log("Invalid destination entered. Check your input!")
RNS.log(str(e)+"\n") RNS.log(f"{e}\n")
exit() exit()
# We must first initialise Reticulum # We must first initialise Reticulum
@ -142,9 +140,7 @@ def client(destination_hexhash, configpath, timeout=None):
# Tell the user that the client is ready! # Tell the user that the client is ready!
RNS.log( RNS.log(
"Echo client ready, hit enter to send echo request to "+ f"Echo client ready, hit enter to send echo request to {destination_hexhash} (Ctrl-C to quit)"
destination_hexhash+
" (Ctrl-C to quit)"
) )
# We enter a loop that runs until the user exits. # 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) packet_receipt.set_delivery_callback(packet_delivered)
# Tell the user that the echo request was sent # 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: else:
# If we do not know this destination, tell the # If we do not know this destination, tell the
# user to wait for an announce to arrive. # user to wait for an announce to arrive.
@ -222,10 +218,10 @@ def packet_delivered(receipt):
rtt = receipt.get_rtt() rtt = receipt.get_rtt()
if (rtt >= 1): if (rtt >= 1):
rtt = round(rtt, 3) rtt = round(rtt, 3)
rttstring = str(rtt)+" seconds" rttstring = f"{rtt} seconds"
else: else:
rtt = round(rtt*1000, 3) rtt = round(rtt*1000, 3)
rttstring = str(rtt)+" milliseconds" rttstring = f"{rtt} milliseconds"
reception_stats = "" reception_stats = ""
if reticulum.is_connected_to_shared_instance: 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) reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash)
if reception_rssi != None: if reception_rssi != None:
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += " [SNR "+str(reception_snr)+" dB]" reception_stats += f" [SNR {reception_snr} dB]"
else: else:
if receipt.proof_packet != None: if receipt.proof_packet != None:
if receipt.proof_packet.rssi != 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: 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( RNS.log(
"Valid reply received from "+ f"Valid reply received from {RNS.prettyhexrep(receipt.destination.hash)}, round-trip time is {rttstring}{reception_stats}"
RNS.prettyhexrep(receipt.destination.hash)+
", round-trip time is "+rttstring+
reception_stats
) )
# This function is called if a packet times out. # This function is called if a packet times out.
def packet_timed_out(receipt): def packet_timed_out(receipt):
if receipt.status == RNS.PacketReceipt.FAILED: 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")
########################################################## ##########################################################

View File

@ -73,7 +73,7 @@ def server(configpath, path):
def announceLoop(destination): def announceLoop(destination):
# Let the user know that everything is ready # 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)") RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
# We enter a loop that runs until the users exits. # We enter a loop that runs until the users exits.
@ -83,7 +83,7 @@ def announceLoop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() 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 # Here's a convenience function for listing all files
# in our served directory # in our served directory
@ -145,7 +145,7 @@ def client_request(message, packet):
try: try:
# If we have the requested file, we'll # If we have the requested file, we'll
# read it and pack it as a resource # 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 = open(os.path.join(serve_path, filename), "rb")
file_resource = RNS.Resource( file_resource = RNS.Resource(
@ -158,7 +158,7 @@ def client_request(message, packet):
except Exception as e: except Exception as e:
# If somethign went wrong, we close # If somethign went wrong, we close
# the link # 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() packet.link.teardown()
raise e raise e
else: else:
@ -175,9 +175,9 @@ def resource_sending_concluded(resource):
name = "resource" name = "resource"
if resource.status == RNS.Resource.COMPLETE: 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: 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): def list_delivered(receipt):
RNS.log("The file list was received by the client") 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 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: if len(destination_hexhash) != dest_len:
raise ValueError( 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) destination_hash = bytes.fromhex(destination_hexhash)
@ -293,7 +293,7 @@ def download(filename):
request_packet.send() request_packet.send()
print("") 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" menu_mode = "download_started"
# This function runs a simple menu for the user # This function runs a simple menu for the user
@ -363,7 +363,7 @@ def print_menu():
while menu_mode == "downloading": while menu_mode == "downloading":
global current_download global current_download
percent = round(current_download.get_progress() * 100.0, 1) percent = round(current_download.get_progress() * 100.0, 1)
print(("\rProgress: "+str(percent)+" % "), end=' ') print(f'\rProgress: {percent} % ', end=' ')
sys.stdout.flush() sys.stdout.flush()
time.sleep(0.1) time.sleep(0.1)
@ -383,15 +383,15 @@ def print_menu():
# Print statistics # Print statistics
hours, rem = divmod(download_time, 3600) hours, rem = divmod(download_time, 3600)
minutes, seconds = divmod(rem, 60) 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("") print("")
print("--- Statistics -----") print("--- Statistics -----")
print("\tTime taken : "+timestring) print(f"\tTime taken : {timestring}")
print("\tFile size : "+size_str(file_size)) print(f"\tFile size : {size_str(file_size)}")
print("\tData transferred : "+size_str(transfer_size)) print(f"\tData transferred : {size_str(transfer_size)}")
print("\tEffective rate : "+size_str(file_size/download_time, suffix='b')+"/s") print(f"\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"\tTransfer rate : {size_str(transfer_size / download_time, suffix='b')}/s")
print("") print("")
print("The download completed! Press enter to return to the menu.") print("The download completed! Press enter to return to the menu.")
print("") print("")
@ -412,7 +412,7 @@ def print_filelist():
global server_files global server_files
print("Files on server:") print("Files on server:")
for index,file in enumerate(server_files): 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): def filelist_received(filelist_data, packet):
global server_files, menu_mode global server_files, menu_mode
@ -509,7 +509,7 @@ def download_concluded(resource):
counter = 0 counter = 0
while os.path.isfile(saved_filename): while os.path.isfile(saved_filename):
counter += 1 counter += 1
saved_filename = current_filename+"."+str(counter) saved_filename = f"{current_filename}.{counter}"
try: try:
file = open(saved_filename, "wb") file = open(saved_filename, "wb")
@ -534,9 +534,9 @@ def size_str(num, suffix='B'):
for unit in units: for unit in units:
if abs(num) < 1024.0: if abs(num) < 1024.0:
return "%3.2f %s%s" % (num, unit, suffix) return f"{num:3.2f} {unit}{suffix}"
num /= 1024.0 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 # A convenience function for clearing the screen
def clear_screen(): def clear_screen():

View File

@ -53,9 +53,7 @@ def server(configpath):
def server_loop(destination): def server_loop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Link identification example "+ f"Link identification example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection."
RNS.prettyhexrep(destination.hash)+
" running, waiting for a connection."
) )
RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
@ -67,7 +65,7 @@ def server_loop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() 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 # When a client establishes a link to our server
# destination, this function will be called with # destination, this function will be called with
@ -85,7 +83,7 @@ def client_disconnected(link):
RNS.log("Client disconnected") RNS.log("Client disconnected")
def remote_identified(link, identity): 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): def server_packet_received(message, packet):
global latest_client_link global latest_client_link
@ -100,9 +98,9 @@ def server_packet_received(message, packet):
# that connected. # that connected.
text = message.decode("utf-8") 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") reply_data = reply_text.encode("utf-8")
RNS.Packet(latest_client_link, reply_data).send() 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 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: if len(destination_hexhash) != dest_len:
raise ValueError( 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) destination_hash = bytes.fromhex(destination_hexhash)
@ -141,8 +139,7 @@ def client(destination_hexhash, configpath):
# Create a new client identity # Create a new client identity
client_identity = RNS.Identity() client_identity = RNS.Identity()
RNS.log( RNS.log(
"Client created new identity "+ f"Client created new identity {client_identity}"
str(client_identity)
) )
# Check if we know a path to the destination # Check if we know a path to the destination
@ -210,14 +207,12 @@ def client_loop():
RNS.Packet(server_link, data).send() RNS.Packet(server_link, data).send()
else: else:
RNS.log( RNS.log(
"Cannot send this packet, the data size of "+ f"Cannot send this packet, the data size of {len(data)} bytes exceeds the link packet MDU of {RNS.Link.MDU} bytes",
str(len(data))+" bytes exceeds the link packet MDU of "+
str(RNS.Link.MDU)+" bytes",
RNS.LOG_ERROR RNS.LOG_ERROR
) )
except Exception as e: 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 should_quit = True
server_link.teardown() server_link.teardown()
@ -253,7 +248,7 @@ def link_closed(link):
# simply print out the data. # simply print out the data.
def client_packet_received(message, packet): def client_packet_received(message, packet):
text = message.decode("utf-8") text = message.decode("utf-8")
RNS.log("Received data on the link: "+text) RNS.log(f"Received data on the link: {text}")
print("> ", end=" ") print("> ", end=" ")
sys.stdout.flush() sys.stdout.flush()

View File

@ -53,9 +53,7 @@ def server(configpath):
def server_loop(destination): def server_loop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Link example "+ f"Link example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection."
RNS.prettyhexrep(destination.hash)+
" running, waiting for a connection."
) )
RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
@ -67,7 +65,7 @@ def server_loop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() 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 # When a client establishes a link to our server
# destination, this function will be called with # 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 # it will all be directed to the last client
# that connected. # that connected.
text = message.decode("utf-8") 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") reply_data = reply_text.encode("utf-8")
RNS.Packet(latest_client_link, reply_data).send() 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 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: if len(destination_hexhash) != dest_len:
raise ValueError( 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) destination_hash = bytes.fromhex(destination_hexhash)
@ -189,14 +187,12 @@ def client_loop():
RNS.Packet(server_link, data).send() RNS.Packet(server_link, data).send()
else: else:
RNS.log( RNS.log(
"Cannot send this packet, the data size of "+ f"Cannot send this packet, the data size of {len(data)} bytes exceeds the link packet MDU of {RNS.Link.MDU} bytes",
str(len(data))+" bytes exceeds the link packet MDU of "+
str(RNS.Link.MDU)+" bytes",
RNS.LOG_ERROR RNS.LOG_ERROR
) )
except Exception as e: 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 should_quit = True
server_link.teardown() server_link.teardown()
@ -230,7 +226,7 @@ def link_closed(link):
# simply print out the data. # simply print out the data.
def client_packet_received(message, packet): def client_packet_received(message, packet):
text = message.decode("utf-8") text = message.decode("utf-8")
RNS.log("Received data on the link: "+text) RNS.log(f"Received data on the link: {text}")
print("> ", end=" ") print("> ", end=" ")
sys.stdout.flush() sys.stdout.flush()

View File

@ -51,9 +51,7 @@ def program_setup(configpath):
def announceLoop(destination): def announceLoop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Minimal example "+ f"Minimal example {RNS.prettyhexrep(destination.hash)} running, hit enter to manually send an announce (Ctrl-C to quit)"
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. # We enter a loop that runs until the users exits.
@ -63,7 +61,7 @@ def announceLoop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() destination.announce()
RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) RNS.log(f"Sent announce from {RNS.prettyhexrep(destination.hash)}")
########################################################## ##########################################################

View File

@ -75,9 +75,7 @@ def server(configpath):
def announceLoop(destination): def announceLoop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Ratcheted echo server "+ f"Ratcheted echo server {RNS.prettyhexrep(destination.hash)} running, hit enter to manually send an announce (Ctrl-C to quit)"
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. # We enter a loop that runs until the users exits.
@ -87,7 +85,7 @@ def announceLoop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() 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): def server_callback(message, packet):
@ -104,19 +102,19 @@ def server_callback(message, packet):
reception_snr = reticulum.get_packet_snr(packet.packet_hash) reception_snr = reticulum.get_packet_snr(packet.packet_hash)
if reception_rssi != None: if reception_rssi != None:
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += " [SNR "+str(reception_snr)+" dBm]" reception_stats += f" [SNR {reception_snr} dBm]"
else: else:
if packet.rssi != None: if packet.rssi != None:
reception_stats += " [RSSI "+str(packet.rssi)+" dBm]" reception_stats += f" [RSSI {packet.rssi} dBm]"
if packet.snr != None: 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 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: if len(destination_hexhash) != dest_len:
raise ValueError( 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) destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e: except Exception as e:
RNS.log("Invalid destination entered. Check your input!") RNS.log("Invalid destination entered. Check your input!")
RNS.log(str(e)+"\n") RNS.log(f"{e}\n")
exit() exit()
# We must first initialise Reticulum # We must first initialise Reticulum
@ -153,9 +151,7 @@ def client(destination_hexhash, configpath, timeout=None):
# Tell the user that the client is ready! # Tell the user that the client is ready!
RNS.log( RNS.log(
"Echo client ready, hit enter to send echo request to "+ f"Echo client ready, hit enter to send echo request to {destination_hexhash} (Ctrl-C to quit)"
destination_hexhash+
" (Ctrl-C to quit)"
) )
# We enter a loop that runs until the user exits. # 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) packet_receipt.set_delivery_callback(packet_delivered)
# Tell the user that the echo request was sent # 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: else:
# If we do not know this destination, tell the # If we do not know this destination, tell the
# user to wait for an announce to arrive. # user to wait for an announce to arrive.
@ -234,10 +230,10 @@ def packet_delivered(receipt):
rtt = receipt.get_rtt() rtt = receipt.get_rtt()
if (rtt >= 1): if (rtt >= 1):
rtt = round(rtt, 3) rtt = round(rtt, 3)
rttstring = str(rtt)+" seconds" rttstring = f"{rtt} seconds"
else: else:
rtt = round(rtt*1000, 3) rtt = round(rtt*1000, 3)
rttstring = str(rtt)+" milliseconds" rttstring = f"{rtt} milliseconds"
reception_stats = "" reception_stats = ""
if reticulum.is_connected_to_shared_instance: 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) reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash)
if reception_rssi != None: if reception_rssi != None:
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += " [SNR "+str(reception_snr)+" dB]" reception_stats += f" [SNR {reception_snr} dB]"
else: else:
if receipt.proof_packet != None: if receipt.proof_packet != None:
if receipt.proof_packet.rssi != 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: 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( RNS.log(
"Valid reply received from "+ f"Valid reply received from {RNS.prettyhexrep(receipt.destination.hash)}, round-trip time is {rttstring}{reception_stats}"
RNS.prettyhexrep(receipt.destination.hash)+
", round-trip time is "+rttstring+
reception_stats
) )
# This function is called if a packet times out. # This function is called if a packet times out.
def packet_timed_out(receipt): def packet_timed_out(receipt):
if receipt.status == RNS.PacketReceipt.FAILED: 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")
########################################################## ##########################################################

View File

@ -24,7 +24,7 @@ APP_NAME = "example_utilities"
latest_client_link = None latest_client_link = None
def random_text_generator(path, data, request_id, link_id, remote_identity, requested_at): 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", "Ill stay away from it", "The pet shop stocks everything"] texts = ["They looked up", "On each full moon", "Becky was upset", "Ill stay away from it", "The pet shop stocks everything"]
return texts[random.randint(0, len(texts)-1)] return texts[random.randint(0, len(texts)-1)]
@ -67,9 +67,7 @@ def server(configpath):
def server_loop(destination): def server_loop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Request example "+ f"Request example {RNS.prettyhexrep(destination.hash)} running, waiting for a connection."
RNS.prettyhexrep(destination.hash)+
" running, waiting for a connection."
) )
RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
@ -81,7 +79,7 @@ def server_loop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() 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 # When a client establishes a link to our server
# destination, this function will be called with # destination, this function will be called with
@ -113,7 +111,7 @@ def client(destination_hexhash, configpath):
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: if len(destination_hexhash) != dest_len:
raise ValueError( 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) destination_hash = bytes.fromhex(destination_hexhash)
@ -187,7 +185,7 @@ def client_loop():
except Exception as e: 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 should_quit = True
server_link.teardown() server_link.teardown()
@ -195,13 +193,13 @@ def got_response(request_receipt):
request_id = request_receipt.request_id request_id = request_receipt.request_id
response = request_receipt.response 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): 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): 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 # This function is called when a link

View File

@ -62,9 +62,7 @@ def server(configpath):
def server_loop(destination): def server_loop(destination):
# Let the user know that everything is ready # Let the user know that everything is ready
RNS.log( RNS.log(
"Speedtest "+ f"Speedtest {RNS.prettyhexrep(destination.hash)} running, waiting for a connection."
RNS.prettyhexrep(destination.hash)+
" running, waiting for a connection."
) )
RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
@ -76,7 +74,7 @@ def server_loop(destination):
while True: while True:
entered = input() entered = input()
destination.announce() 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 # When a client establishes a link to our server
# destination, this function will be called with # destination, this function will be called with
@ -108,9 +106,9 @@ def size_str(num, suffix='B'):
for unit in units: for unit in units:
if abs(num) < 1024.0: if abs(num) < 1024.0:
return "%3.2f %s%s" % (num, unit, suffix) return f"{num:3.2f} {unit}{suffix}"
num /= 1024.0 num /= 1024.0
return "%.2f %s%s" % (num, last_unit, suffix) return f"{num:.2f} {last_unit}{suffix}"
def server_packet_received(message, packet): def server_packet_received(message, packet):
@ -134,14 +132,14 @@ def server_packet_received(message, packet):
download_time = last_packet_at-first_packet_at download_time = last_packet_at-first_packet_at
hours, rem = divmod(download_time, 3600) hours, rem = divmod(download_time, 3600)
minutes, seconds = divmod(rem, 60) 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("") print("")
print("--- Statistics -----") print("--- Statistics -----")
print("\tTime taken : "+timestring) print(f"\tTime taken : {timestring}")
print("\tData transferred : "+size_str(rcv_d)) print(f"\tData transferred : {size_str(rcv_d)}")
print("\tTransfer rate : "+size_str(rcv_d/download_time, suffix='b')+"/s") print(f"\tTransfer rate : {size_str(rcv_d / download_time, suffix='b')}/s")
print("") print("")
sys.stdout.flush() sys.stdout.flush()
@ -169,7 +167,7 @@ def client(destination_hexhash, configpath):
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: if len(destination_hexhash) != dest_len:
raise ValueError( 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) destination_hash = bytes.fromhex(destination_hexhash)
@ -260,13 +258,13 @@ def link_established(link):
download_time = ended-started download_time = ended-started
hours, rem = divmod(download_time, 3600) hours, rem = divmod(download_time, 3600)
minutes, seconds = divmod(rem, 60) 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("") print("")
print("--- Statistics -----") print("--- Statistics -----")
print("\tTime taken : "+timestring) print(f"\tTime taken : {timestring}")
print("\tData transferred : "+size_str(data_sent)) print(f"\tData transferred : {size_str(data_sent)}")
print("\tTransfer rate : "+size_str(data_sent/download_time, suffix='b')+"/s") print(f"\tTransfer rate : {size_str(data_sent / download_time, suffix='b')}/s")
print("") print("")
sys.stdout.flush() sys.stdout.flush()

View File

@ -65,7 +65,7 @@ class StreamDataMessage(MessageBase):
raise ValueError("stream_id must be 0-16383") raise ValueError("stream_id must be 0-16383")
self.stream_id = stream_id self.stream_id = stream_id
self.compressed = compressed self.compressed = compressed
self.data = data or bytes() self.data = data or b''
self.eof = eof self.eof = eof
def pack(self) -> bytes: def pack(self) -> bytes:
@ -73,7 +73,7 @@ class StreamDataMessage(MessageBase):
raise ValueError("stream_id") raise ValueError("stream_id")
header_val = (0x3fff & self.stream_id) | (0x8000 if self.eof else 0x0000) | (0x4000 if self.compressed > 0 else 0x0000) 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): def unpack(self, raw):
self.stream_id = struct.unpack(">H", raw[:2])[0] self.stream_id = struct.unpack(">H", raw[:2])[0]
@ -148,7 +148,7 @@ class RawChannelReader(RawIOBase, AbstractContextManager):
try: try:
threading.Thread(target=listener, name="Message Callback", args=[len(self._buffer)], daemon=True).start() threading.Thread(target=listener, name="Message Callback", args=[len(self._buffer)], daemon=True).start()
except Exception as ex: 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 True
return False return False
@ -264,7 +264,7 @@ class RawChannelWriter(RawIOBase, AbstractContextManager):
time.sleep(0.05) time.sleep(0.05)
self._eof = True self._eof = True
self.write(bytes()) self.write(b'')
def __enter__(self): def __enter__(self):
return self return self

View File

@ -168,7 +168,7 @@ class Envelope:
Internal wrapper used to transport messages over a channel and Internal wrapper used to transport messages over a channel and
track its state within the channel framework. 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]) msgtype, self.sequence, length = struct.unpack(">HHH", self.raw[:6])
raw = self.raw[6:] raw = self.raw[6:]
ctor = message_factories.get(msgtype, None) ctor = message_factories.get(msgtype, None)
@ -282,7 +282,7 @@ class Channel(contextlib.AbstractContextManager):
self._message_callbacks: [MessageCallbackType] = [] self._message_callbacks: [MessageCallbackType] = []
self._next_sequence = 0 self._next_sequence = 0
self._next_rx_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._max_tries = 5
self.fast_rate_rounds = 0 self.fast_rate_rounds = 0
self.medium_rate_rounds = 0 self.medium_rate_rounds = 0
@ -301,12 +301,12 @@ class Channel(contextlib.AbstractContextManager):
def __enter__(self) -> Channel: def __enter__(self) -> Channel:
return self 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: __traceback: TracebackType | None) -> bool | None:
self._shutdown() self._shutdown()
return False 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``. 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) 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: with self._lock:
if not issubclass(message_class, MessageBase): if not issubclass(message_class, MessageBase):
raise ChannelException(CEType.ME_INVALID_MSG_TYPE, raise ChannelException(CEType.ME_INVALID_MSG_TYPE,
@ -384,7 +384,7 @@ class Channel(contextlib.AbstractContextManager):
for existing in ring: for existing in ring:
if envelope.sequence == existing.sequence: 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 return False
if envelope.sequence < existing.sequence and not (self._next_rx_sequence - envelope.sequence) > (Channel.SEQ_MAX//2): 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): if cb(message):
return return
except Exception as e: 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): def _receive(self, raw: bytes):
try: try:
@ -420,16 +420,16 @@ class Channel(contextlib.AbstractContextManager):
window_overflow = (self._next_rx_sequence+Channel.WINDOW_MAX) % Channel.SEQ_MODULUS window_overflow = (self._next_rx_sequence+Channel.WINDOW_MAX) % Channel.SEQ_MODULUS
if window_overflow < self._next_rx_sequence: if window_overflow < self._next_rx_sequence:
if envelope.sequence > window_overflow: 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 return
else: 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 return
is_new = self._emplace_envelope(envelope, self._rx_ring) is_new = self._emplace_envelope(envelope, self._rx_ring)
if not is_new: 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 return
else: else:
with self._lock: with self._lock:
@ -454,7 +454,7 @@ class Channel(contextlib.AbstractContextManager):
self._run_callbacks(m) self._run_callbacks(m)
except Exception as e: 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: def is_ready_to_send(self) -> bool:
""" """
@ -520,9 +520,9 @@ class Channel(contextlib.AbstractContextManager):
else: 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: 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): def _packet_delivered(self, packet: TPacket):
self._packet_tx_op(packet, lambda env: True) self._packet_tx_op(packet, lambda env: True)
@ -541,7 +541,7 @@ class Channel(contextlib.AbstractContextManager):
def _packet_timeout(self, packet: TPacket): def _packet_timeout(self, packet: TPacket):
def retry_envelope(envelope: Envelope) -> bool: def retry_envelope(envelope: Envelope) -> bool:
if envelope.tries >= self._max_tries: 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._shutdown() # start on separate thread?
self._outlet.timed_out() self._outlet.timed_out()
return True return True

View File

@ -48,7 +48,7 @@ class Fernet():
raise ValueError("Token key cannot be None") raise ValueError("Token key cannot be None")
if len(key) != 32: 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._signing_key = key[:16]
self._encryption_key = key[16:] self._encryption_key = key[16:]
@ -56,7 +56,7 @@ class Fernet():
def verify_hmac(self, token): def verify_hmac(self, token):
if len(token) <= 32: 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: else:
received_hmac = token[-32:] received_hmac = token[-32:]
expected_hmac = HMAC.new(self._signing_key, token[:-32]).digest() expected_hmac = HMAC.new(self._signing_key, token[:-32]).digest()

View File

@ -37,7 +37,7 @@ class HMAC:
""" """
if not isinstance(key, (bytes, bytearray)): 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: if not digestmod:
raise TypeError("Missing required parameter 'digestmod'.") raise TypeError("Missing required parameter 'digestmod'.")
@ -60,13 +60,11 @@ class HMAC:
if hasattr(self._inner, 'block_size'): if hasattr(self._inner, 'block_size'):
blocksize = self._inner.block_size blocksize = self._inner.block_size
if blocksize < 16: if blocksize < 16:
_warnings.warn('block_size of %d seems too small; using our ' _warnings.warn(f'block_size of {int(blocksize)} seems too small; using our default of {int(self.blocksize)}.',
'default of %d.' % (blocksize, self.blocksize),
RuntimeWarning, 2) RuntimeWarning, 2)
blocksize = self.blocksize blocksize = self.blocksize
else: else:
_warnings.warn('No block_size attribute on given digest object; ' _warnings.warn(f'No block_size attribute on given digest object; Assuming {int(self.blocksize)}.',
'Assuming %d.' % (self.blocksize),
RuntimeWarning, 2) RuntimeWarning, 2)
blocksize = self.blocksize blocksize = self.blocksize

View File

@ -35,6 +35,6 @@ class PKCS7:
l = len(data) l = len(data)
n = data[-1] n = data[-1]
if n > bs: 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: else:
return data[:l-n] return data[:l-n]

View File

@ -35,4 +35,4 @@ def backend():
elif PROVIDER == PROVIDER_INTERNAL: elif PROVIDER == PROVIDER_INTERNAL:
return "internal" return "internal"
elif PROVIDER == PROVIDER_PYCA: elif PROVIDER == PROVIDER_PYCA:
return "openssl, PyCA "+str(pyca_v) return f"openssl, PyCA {pyca_v}"

View File

@ -28,7 +28,7 @@ import sys
def new(m=None): def new(m=None):
return sha256(m) return sha256(m)
class sha256(object): class sha256:
_k = (0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, _k = (0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
@ -59,7 +59,7 @@ class sha256(object):
if m is not None: if m is not None:
if type(m) is not bytes: 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) self.update(m)
def _rotr(self, x, y): def _rotr(self, x, y):
@ -100,7 +100,7 @@ class sha256(object):
return return
if type(m) is not bytes: 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._buffer += m
self._counter += len(m) self._counter += len(m)

View File

@ -25,7 +25,7 @@ import copy, struct, sys
def new(m=None): def new(m=None):
return sha512(m) return sha512(m)
class sha512(object): class sha512:
_k = (0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, _k = (0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
@ -60,7 +60,7 @@ class sha512(object):
if m is not None: if m is not None:
if type(m) is not bytes: 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) self.update(m)
def _rotr(self, x, y): def _rotr(self, x, y):
@ -100,7 +100,7 @@ class sha512(object):
if not m: if not m:
return return
if type(m) is not bytes: 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._buffer += m
self._counter += len(m) self._counter += len(m)

View File

@ -20,5 +20,5 @@ elif cp.PROVIDER == cp.PROVIDER_PYCA:
from RNS.Cryptography.Proxies import Ed25519PrivateKeyProxy as Ed25519PrivateKey from RNS.Cryptography.Proxies import Ed25519PrivateKeyProxy as Ed25519PrivateKey
from RNS.Cryptography.Proxies import Ed25519PublicKeyProxy as Ed25519PublicKey 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')] __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]

View File

@ -230,7 +230,7 @@ def test():
print(f"Ciphertext Hex: {ciphertext_block.hex()}") print(f"Ciphertext Hex: {ciphertext_block.hex()}")
print(f"Plaintext: {plaintext_block.decode()}") print(f"Plaintext: {plaintext_block.decode()}")
assert plaintext_block == single_block_text 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() print()
# test a less than a block length phrase # test a less than a block length phrase
@ -246,7 +246,7 @@ def test():
print(f"Ciphertext Hex: {ciphertext_short.hex()}") print(f"Ciphertext Hex: {ciphertext_short.hex()}")
print(f"Plaintext: {plaintext_short.decode()}") print(f"Plaintext: {plaintext_short.decode()}")
assert short_text == plaintext_short 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() print()
# test an arbitrary length phrase # test an arbitrary length phrase
@ -262,7 +262,7 @@ def test():
print(f"Ciphertext Hex: {ciphertext.hex()}") print(f"Ciphertext Hex: {ciphertext.hex()}")
print(f"Plaintext: {plaintext.decode()}") print(f"Plaintext: {plaintext.decode()}")
assert text == plaintext 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() print()

View File

@ -141,7 +141,7 @@ def encodepoint(P):
assert 0 <= y < (1<<255) # always < 0x7fff..ff assert 0 <= y < (1<<255) # always < 0x7fff..ff
if x & 1: if x & 1:
y += 1<<255 y += 1<<255
return binascii.unhexlify("%064x" % y)[::-1] return binascii.unhexlify(f"{y:064x}")[::-1]
def isoncurve(P): def isoncurve(P):
x = P[0] x = P[0]
@ -192,7 +192,7 @@ def password_to_scalar(pw):
def scalar_to_bytes(y): def scalar_to_bytes(y):
y = y % L y = y % L
assert 0 <= y < 2**256 assert 0 <= y < 2**256
return binascii.unhexlify("%064x" % y)[::-1] return binascii.unhexlify(f"{y:064x}")[::-1]
# Elements, of various orders # Elements, of various orders

View File

@ -39,7 +39,7 @@ class BadPrefixError(Exception):
def remove_prefix(s_bytes, prefix): def remove_prefix(s_bytes, prefix):
assert(type(s_bytes) == type(prefix)) assert(type(s_bytes) == type(prefix))
if s_bytes[:len(prefix)] != 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):] return s_bytes[len(prefix):]
def to_ascii(s_bytes, prefix="", encoding="base64"): def to_ascii(s_bytes, prefix="", encoding="base64"):
@ -93,7 +93,7 @@ def from_ascii(s_ascii, prefix="", encoding="base64"):
raise NotImplementedError raise NotImplementedError
return s_bytes return s_bytes
class SigningKey(object): class SigningKey:
# this can only be used to reconstruct a key created by create_keypair(). # this can only be used to reconstruct a key created by create_keypair().
def __init__(self, sk_s, prefix="", encoding=None): def __init__(self, sk_s, prefix="", encoding=None):
assert isinstance(sk_s, bytes) assert isinstance(sk_s, bytes)
@ -150,7 +150,7 @@ class SigningKey(object):
return to_ascii(sig_out, prefix, encoding) return to_ascii(sig_out, prefix, encoding)
return prefix+sig_out return prefix+sig_out
class VerifyingKey(object): class VerifyingKey:
def __init__(self, vk_s, prefix="", encoding=None): def __init__(self, vk_s, prefix="", encoding=None):
if not isinstance(prefix, bytes): if not isinstance(prefix, bytes):
prefix = prefix.encode('ascii') prefix = prefix.encode('ascii')

View File

@ -78,16 +78,16 @@ def sign(skbytes, msg):
"""Return just the signature, given the message and just the secret """Return just the signature, given the message and just the secret
key.""" key."""
if len(skbytes) != 32: 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) vkbytes = create_verifying_key(skbytes)
sig = signature(msg, skbytes, vkbytes) sig = signature(msg, skbytes, vkbytes)
return sig return sig
def verify(vkbytes, sig, msg): def verify(vkbytes, sig, msg):
if len(vkbytes) != 32: 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: 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) rc = checkvalid(sig, msg, vkbytes)
if not rc: if not rc:
raise ValueError("rc != 0", rc) raise ValueError("rc != 0", rc)

View File

@ -96,10 +96,10 @@ class Destination:
name = app_name name = app_name
for aspect in aspects: for aspect in aspects:
if "." in aspect: raise ValueError("Dots can't be used in aspects") if "." in aspect: raise ValueError("Dots can't be used in aspects")
name += "." + aspect name += f".{aspect}"
if identity != None: if identity != None:
name += "." + identity.hexhash name += f".{identity.hexhash}"
return name return name
@ -192,7 +192,7 @@ class Destination:
""" """
:returns: A human-readable representation of the destination including addressable hash and full name. :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): def _clean_ratchets(self):
if self.ratchets != None: if self.ratchets != None:
@ -210,13 +210,13 @@ class Destination:
except Exception as e: except Exception as e:
self.ratchets = None self.ratchets = None
self.ratchets_path = 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): def rotate_ratchets(self):
if self.ratchets != None: if self.ratchets != None:
now = time.time() now = time.time()
if now > self.latest_ratchet_time+self.ratchet_interval: 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() new_ratchet = RNS.Identity._generate_ratchet()
self.ratchets.insert(0, new_ratchet) self.ratchets.insert(0, new_ratchet)
self.latest_ratchet_time = now self.latest_ratchet_time = now
@ -224,7 +224,7 @@ class Destination:
self._persist_ratchets() self._persist_ratchets()
return True return True
else: 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 return False
@ -262,7 +262,7 @@ class Destination:
# received via multiple paths. The difference in reception time will # received via multiple paths. The difference in reception time will
# potentially also be useful in determining characteristics of the # potentially also be useful in determining characteristics of the
# multiple available paths, and to choose the best one. # 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] announce_data = self.path_responses[tag][1]
else: else:
@ -413,7 +413,7 @@ class Destination:
try: try:
self.callbacks.packet(plaintext, packet) self.callbacks.packet(plaintext, packet)
except Exception as e: 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): def incoming_link_request(self, data, packet):
if self.accept_link_requests: if self.accept_link_requests:
@ -437,9 +437,9 @@ class Destination:
except Exception as e: except Exception as e:
self.ratchets = None self.ratchets = None
self.ratchets_path = 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: 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 = []
self.ratchets_path = ratchets_path self.ratchets_path = ratchets_path
self._persist_ratchets() self._persist_ratchets()
@ -464,11 +464,11 @@ class Destination:
self._reload_ratchets(ratchets_path) self._reload_ratchets(ratchets_path)
# TODO: Remove at some point # 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 return True
else: 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): def enforce_ratchets(self):
""" """
@ -478,7 +478,7 @@ class Destination:
""" """
if self.ratchets != None: if self.ratchets != None:
self.__enforce_ratchets = True 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 return True
else: else:
return False return False
@ -586,7 +586,7 @@ class Destination:
return self.prv.encrypt(plaintext) return self.prv.encrypt(plaintext)
except Exception as e: except Exception as e:
RNS.log("The GROUP destination could not encrypt data", RNS.LOG_ERROR) 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: else:
raise ValueError("No private key held by GROUP destination. Did you create or load one?") 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) return self.prv.decrypt(ciphertext)
except Exception as e: except Exception as e:
RNS.log("The GROUP destination could not decrypt data", RNS.LOG_ERROR) 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: else:
raise ValueError("No private key held by GROUP destination. Did you create or load one?") raise ValueError("No private key held by GROUP destination. Did you create or load one?")

View File

@ -87,7 +87,7 @@ class Identity:
@staticmethod @staticmethod
def remember(packet_hash, destination_hash, public_key, app_data = None): def remember(packet_hash, destination_hash, public_key, app_data = None):
if len(public_key) != Identity.KEYSIZE//8: 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: else:
Identity.known_destinations[destination_hash] = [time.time(), packet_hash, public_key, app_data] Identity.known_destinations[destination_hash] = [time.time(), packet_hash, public_key, app_data]
@ -153,9 +153,9 @@ class Identity:
save_start = time.time() save_start = time.time()
storage_known_destinations = {} storage_known_destinations = {}
if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"): if os.path.isfile(f"{RNS.Reticulum.storagepath}/known_destinations"):
try: try:
file = open(RNS.Reticulum.storagepath+"/known_destinations","rb") file = open(f"{RNS.Reticulum.storagepath}/known_destinations","rb")
storage_known_destinations = umsgpack.load(file) storage_known_destinations = umsgpack.load(file)
file.close() file.close()
except: except:
@ -166,32 +166,32 @@ class Identity:
if not destination_hash in Identity.known_destinations: if not destination_hash in Identity.known_destinations:
Identity.known_destinations[destination_hash] = storage_known_destinations[destination_hash] Identity.known_destinations[destination_hash] = storage_known_destinations[destination_hash]
except Exception as e: 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) RNS.log(f"Saving {len(Identity.known_destinations)} known destinations to storage...", RNS.LOG_DEBUG)
file = open(RNS.Reticulum.storagepath+"/known_destinations","wb") file = open(f"{RNS.Reticulum.storagepath}/known_destinations","wb")
umsgpack.dump(Identity.known_destinations, file) umsgpack.dump(Identity.known_destinations, file)
file.close() file.close()
save_time = time.time() - save_start save_time = time.time() - save_start
if save_time < 1: if save_time < 1:
time_str = str(round(save_time*1000,2))+"ms" time_str = f"{round(save_time * 1000, 2)}ms"
else: 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: 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) RNS.trace_exception(e)
Identity.saving_known_destinations = False Identity.saving_known_destinations = False
@staticmethod @staticmethod
def load_known_destinations(): def load_known_destinations():
if os.path.isfile(RNS.Reticulum.storagepath+"/known_destinations"): if os.path.isfile(f"{RNS.Reticulum.storagepath}/known_destinations"):
try: try:
file = open(RNS.Reticulum.storagepath+"/known_destinations","rb") file = open(f"{RNS.Reticulum.storagepath}/known_destinations","rb")
loaded_known_destinations = umsgpack.load(file) loaded_known_destinations = umsgpack.load(file)
file.close() file.close()
@ -200,7 +200,7 @@ class Identity:
if len(known_destination) == RNS.Reticulum.TRUNCATED_HASHLENGTH//8: if len(known_destination) == RNS.Reticulum.TRUNCATED_HASHLENGTH//8:
Identity.known_destinations[known_destination] = loaded_known_destinations[known_destination] 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: except Exception as e:
RNS.log("Error loading known destinations from disk, file will be recreated on exit", RNS.LOG_ERROR) 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) hexhash = RNS.hexrep(destination_hash, delimit=False)
ratchet_data = {"ratchet": ratchet, "received": time.time()} ratchet_data = {"ratchet": ratchet, "received": time.time()}
ratchetdir = RNS.Reticulum.storagepath+"/ratchets" ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets"
if not os.path.isdir(ratchetdir): if not os.path.isdir(ratchetdir):
os.makedirs(ratchetdir) os.makedirs(ratchetdir)
@ -303,7 +303,7 @@ class Identity:
RNS.log("Cleaning ratchets...", RNS.LOG_DEBUG) RNS.log("Cleaning ratchets...", RNS.LOG_DEBUG)
try: try:
now = time.time() now = time.time()
ratchetdir = RNS.Reticulum.storagepath+"/ratchets" ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets"
if os.path.isdir(ratchetdir): if os.path.isdir(ratchetdir):
for filename in os.listdir(ratchetdir): for filename in os.listdir(ratchetdir):
try: try:
@ -326,7 +326,7 @@ class Identity:
@staticmethod @staticmethod
def get_ratchet(destination_hash): def get_ratchet(destination_hash):
if not destination_hash in Identity.known_ratchets: 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) hexhash = RNS.hexrep(destination_hash, delimit=False)
ratchet_path = f"{ratchetdir}/{hexhash}" ratchet_path = f"{ratchetdir}/{hexhash}"
if os.path.isfile(ratchet_path): if os.path.isfile(ratchet_path):
@ -417,19 +417,19 @@ class Identity:
if packet.rssi != None or packet.snr != None: if packet.rssi != None or packet.snr != None:
signal_str = " [" signal_str = " ["
if packet.rssi != None: if packet.rssi != None:
signal_str += "RSSI "+str(packet.rssi)+"dBm" signal_str += f"RSSI {packet.rssi}dBm"
if packet.snr != None: if packet.snr != None:
signal_str += ", " signal_str += ", "
if packet.snr != None: if packet.snr != None:
signal_str += "SNR "+str(packet.snr)+"dB" signal_str += f"SNR {packet.snr}dB"
signal_str += "]" signal_str += "]"
else: else:
signal_str = "" signal_str = ""
if hasattr(packet, "transport_id") and packet.transport_id != None: 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: 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: if ratchet:
Identity._remember_ratchet(destination_hash, ratchet) Identity._remember_ratchet(destination_hash, ratchet)
@ -437,16 +437,16 @@ class Identity:
return True return True
else: 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 return False
else: 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 del announced_identity
return False return False
except Exception as e: 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 return False
@staticmethod @staticmethod
@ -505,8 +505,8 @@ class Identity:
return True return True
return False return False
except Exception as e: except Exception as e:
RNS.log("Error while saving identity to "+str(path), RNS.LOG_ERROR) RNS.log(f"Error while saving identity to {path}", RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e)) RNS.log(f"The contained exception was: {e}")
def __init__(self,create_keys=True): def __init__(self,create_keys=True):
# Initialize keys to none # Initialize keys to none
@ -541,7 +541,7 @@ class Identity:
self.update_hashes() 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): def get_private_key(self):
""" """
@ -581,7 +581,7 @@ class Identity:
except Exception as e: except Exception as e:
raise e raise e
RNS.log("Failed to load identity key", RNS.LOG_ERROR) 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 return False
def load_public_key(self, pub_bytes): def load_public_key(self, pub_bytes):
@ -600,7 +600,7 @@ class Identity:
self.update_hashes() self.update_hashes()
except Exception as e: 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): def update_hashes(self):
self.hash = Identity.truncated_hash(self.get_public_key()) self.hash = Identity.truncated_hash(self.get_public_key())
@ -613,8 +613,8 @@ class Identity:
return self.load_private_key(prv_bytes) return self.load_private_key(prv_bytes)
return False return False
except Exception as e: except Exception as e:
RNS.log("Error while loading identity from "+str(path), RNS.LOG_ERROR) RNS.log(f"Error while loading identity from {path}", 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)
def get_salt(self): def get_salt(self):
return self.hash return self.hash
@ -697,7 +697,7 @@ class Identity:
pass pass
if enforce_ratchets and plaintext == None: 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: if ratchet_id_receiver:
ratchet_id_receiver.latest_ratchet_id = None ratchet_id_receiver.latest_ratchet_id = None
return None return None
@ -717,7 +717,7 @@ class Identity:
ratchet_id_receiver.latest_ratchet_id = None ratchet_id_receiver.latest_ratchet_id = None
except Exception as e: 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: if ratchet_id_receiver:
ratchet_id_receiver.latest_ratchet_id = None ratchet_id_receiver.latest_ratchet_id = None
@ -741,7 +741,7 @@ class Identity:
try: try:
return self.sig_prv.sign(message) return self.sig_prv.sign(message)
except Exception as e: 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 raise e
else: else:
raise KeyError("Signing failed because identity does not hold a private key") raise KeyError("Signing failed because identity does not hold a private key")

View File

@ -87,7 +87,7 @@ class AX25KISSInterface(Interface):
self.name = name self.name = name
self.src_call = callsign.upper().encode("ascii") self.src_call = callsign.upper().encode("ascii")
self.src_ssid = ssid self.src_ssid = ssid
self.dst_call = "APZRNS".encode("ascii") self.dst_call = b"APZRNS"
self.dst_ssid = 0 self.dst_ssid = 0
self.port = port self.port = port
self.speed = speed self.speed = speed
@ -105,10 +105,10 @@ class AX25KISSInterface(Interface):
self.flow_control_locked = time.time() self.flow_control_locked = time.time()
if (len(self.src_call) < 3 or len(self.src_call) > 6): 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): 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.preamble = preamble if preamble != None else 350;
self.txtail = txtail if txtail != None else 20; self.txtail = txtail if txtail != None else 20;
@ -124,16 +124,16 @@ class AX25KISSInterface(Interface):
try: try:
self.open_port() self.open_port()
except Exception as e: 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 raise e
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
else: else:
raise IOError("Could not open serial port") raise OSError("Could not open serial port")
def open_port(self): 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( self.serial = self.pyserial.Serial(
port = self.port, port = self.port,
baudrate = self.speed, baudrate = self.speed,
@ -155,7 +155,7 @@ class AX25KISSInterface(Interface):
thread.daemon = True thread.daemon = True
thread.start() thread.start()
self.online = True 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...") RNS.log("Configuring AX.25 KISS interface parameters...")
self.setPreamble(self.preamble) self.setPreamble(self.preamble)
self.setTxTail(self.txtail) 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXDELAY])+bytes([preamble])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setTxTail(self, txtail):
txtail_ms = 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXTAIL])+bytes([txtail])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setPersistence(self, persistence):
if persistence < 0: if persistence < 0:
@ -200,7 +200,7 @@ class AX25KISSInterface(Interface):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setSlotTime(self, slottime):
slottime_ms = 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SLOTTIME])+bytes([slottime])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setFlowControl(self, flow_control):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
if (flow_control): 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: 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): def processIncoming(self, data):
@ -270,7 +270,7 @@ class AX25KISSInterface(Interface):
if written != len(kiss_frame): if written != len(kiss_frame):
if self.flow_control: if self.flow_control:
self.interface_ready = True 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: else:
self.queue(data) self.queue(data)
@ -336,13 +336,13 @@ class AX25KISSInterface(Interface):
if self.flow_control: if self.flow_control:
if not self.interface_ready: if not self.interface_ready:
if time.time() > self.flow_control_locked + self.flow_control_timeout: 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() self.process_queue()
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -357,17 +357,17 @@ class AX25KISSInterface(Interface):
while not self.online: while not self.online:
try: try:
time.sleep(5) 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() self.open_port()
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
except Exception as e: 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): def should_ingress_limit(self):
return False return False
def __str__(self): def __str__(self):
return "AX25KISSInterface["+self.name+"]" return f"AX25KISSInterface[{self.name}]"

View File

@ -125,17 +125,17 @@ class KISSInterface(Interface):
try: try:
self.open_port() self.open_port()
except Exception as e: 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 raise e
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
else: else:
raise IOError("Could not open serial port") raise OSError("Could not open serial port")
def open_port(self): def open_port(self):
RNS.log("Opening serial port "+self.port+"...") RNS.log(f"Opening serial port {self.port}...")
# Get device parameters # Get device parameters
from usb4a import usb from usb4a import usb
device = usb.get_usb_device(self.port) device = usb.get_usb_device(self.port)
@ -147,7 +147,7 @@ class KISSInterface(Interface):
proxy = self.pyserial.get_serial_port proxy = self.pyserial.get_serial_port
if vid == 0x1A86 and pid == 0x55D4: if vid == 0x1A86 and pid == 0x55D4:
# Force CDC driver for Qinheng CH34x # 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 from usbserial4a.cdcacmserial4a import CdcAcmSerial
proxy = CdcAcmSerial proxy = CdcAcmSerial
@ -186,9 +186,9 @@ class KISSInterface(Interface):
self.serial.USB_READ_TIMEOUT_MILLIS = 100 self.serial.USB_READ_TIMEOUT_MILLIS = 100
self.serial.timeout = 0.1 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(f"{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(f"{self} USB read timeout set to {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 write timeout set to {self.serial.USB_WRITE_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG)
def configure_device(self): def configure_device(self):
# Allow time for interface to initialise before config # Allow time for interface to initialise before config
@ -197,7 +197,7 @@ class KISSInterface(Interface):
thread.daemon = True thread.daemon = True
thread.start() thread.start()
self.online = True 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...") RNS.log("Configuring KISS interface parameters...")
self.setPreamble(self.preamble) self.setPreamble(self.preamble)
self.setTxTail(self.txtail) 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXDELAY])+bytes([preamble])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setTxTail(self, txtail):
txtail_ms = 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXTAIL])+bytes([txtail])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setPersistence(self, persistence):
if persistence < 0: if persistence < 0:
@ -242,7 +242,7 @@ class KISSInterface(Interface):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setSlotTime(self, slottime):
slottime_ms = 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SLOTTIME])+bytes([slottime])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setFlowControl(self, flow_control):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
if (flow_control): if (flow_control):
raise IOError("Could not enable KISS interface flow control") raise OSError("Could not enable KISS interface flow control")
else: else:
raise IOError("Could not enable KISS interface flow control") raise OSError("Could not enable KISS interface flow control")
def processIncoming(self, data): def processIncoming(self, data):
@ -295,7 +295,7 @@ class KISSInterface(Interface):
self.first_tx = time.time() self.first_tx = time.time()
if written != len(frame): 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: else:
self.queue(data) self.queue(data)
@ -365,20 +365,20 @@ class KISSInterface(Interface):
if self.flow_control: if self.flow_control:
if not self.interface_ready: if not self.interface_ready:
if time.time() > self.flow_control_locked + self.flow_control_timeout: 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() self.process_queue()
if self.beacon_i != None and self.beacon_d != None: if self.beacon_i != None and self.beacon_d != None:
if self.first_tx != None: if self.first_tx != None:
if time.time() > self.first_tx + self.beacon_i: 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.first_tx = None
self.processOutgoing(self.beacon_d) self.processOutgoing(self.beacon_d)
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -393,17 +393,17 @@ class KISSInterface(Interface):
while not self.online: while not self.online:
try: try:
time.sleep(5) 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() self.open_port()
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
except Exception as e: 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): def should_ingress_limit(self):
return False return False
def __str__(self): def __str__(self):
return "KISSInterface["+self.name+"]" return f"KISSInterface[{self.name}]"

View File

@ -172,7 +172,7 @@ class AndroidBluetoothManager():
try: try:
self.rfcomm_socket = device.createRfcommSocketToServiceRecord(self.bt_rfcomm_service_record) self.rfcomm_socket = device.createRfcommSocketToServiceRecord(self.bt_rfcomm_service_record)
if self.rfcomm_socket == None: if self.rfcomm_socket == None:
raise IOError("Bluetooth stack returned no socket object") raise OSError("Bluetooth stack returned no socket object")
else: else:
if not self.rfcomm_socket.isConnected(): if not self.rfcomm_socket.isConnected():
try: try:
@ -181,13 +181,13 @@ class AndroidBluetoothManager():
self.rfcomm_writer = self.rfcomm_socket.getOutputStream() self.rfcomm_writer = self.rfcomm_socket.getOutputStream()
self.connected = True self.connected = True
self.connected_device = device 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: 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: 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(f"Could not create and connect Bluetooth RFcomm socket for {device.getName()} {device.getAddress()}", RNS.LOG_EXTREME)
RNS.log("The contained exception was: "+str(e), RNS.LOG_EXTREME) RNS.log(f"The contained exception was: {e}", RNS.LOG_EXTREME)
def close(self): def close(self):
if self.connected: if self.connected:
@ -209,7 +209,7 @@ class AndroidBluetoothManager():
def read(self, len = None): def read(self, len = None):
if self.connection_failed: if self.connection_failed:
raise IOError("Bluetooth connection failed") raise OSError("Bluetooth connection failed")
else: else:
if self.connected and self.rfcomm_reader != None: if self.connected and self.rfcomm_reader != None:
available = self.rfcomm_reader.available() available = self.rfcomm_reader.available()
@ -223,7 +223,7 @@ class AndroidBluetoothManager():
else: else:
return bytes([]) return bytes([])
else: else:
raise IOError("No RFcomm socket available") raise OSError("No RFcomm socket available")
def write(self, data): def write(self, data):
try: try:
@ -231,7 +231,7 @@ class AndroidBluetoothManager():
self.rfcomm_writer.flush() self.rfcomm_writer.flush()
return len(data) return len(data)
except Exception as e: 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 self.connection_failed = True
return 0 return 0
@ -274,7 +274,7 @@ class RNodeInterface(Interface):
bluetooth_state = 0x00 bluetooth_state = 0x00
if port != None: if port != None:
RNS.log("Opening serial port "+port+"...") RNS.log(f"Opening serial port {port}...")
# Get device parameters # Get device parameters
from usb4a import usb from usb4a import usb
device = usb.get_usb_device(port) device = usb.get_usb_device(port)
@ -287,7 +287,7 @@ class RNodeInterface(Interface):
proxy = pyserial.get_serial_port proxy = pyserial.get_serial_port
if vid == 0x1A86 and pid == 0x55D4: if vid == 0x1A86 and pid == 0x55D4:
# Force CDC driver for Qinheng CH34x # 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 from usbserial4a.cdcacmserial4a import CdcAcmSerial
proxy = CdcAcmSerial proxy = CdcAcmSerial
@ -466,31 +466,31 @@ class RNodeInterface(Interface):
self.validcfg = True self.validcfg = True
if (self.frequency < RNodeInterface.FREQ_MIN or self.frequency > RNodeInterface.FREQ_MAX): 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 self.validcfg = False
if (self.txpower < 0 or self.txpower > 22): 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 self.validcfg = False
if (self.bandwidth < 7800 or self.bandwidth > 500000): 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 self.validcfg = False
if (self.sf < 5 or self.sf > 12): 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 self.validcfg = False
if (self.cr < 5 or self.cr > 8): 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 self.validcfg = False
if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)): 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 self.validcfg = False
if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)): 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 self.validcfg = False
if id_interval != None and id_callsign != None: 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_callsign = id_callsign.encode("utf-8")
self.id_interval = id_interval self.id_interval = id_interval
else: 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 self.validcfg = False
else: else:
self.id_interval = None self.id_interval = None
self.id_callsign = None self.id_callsign = None
if (not self.validcfg): 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: try:
self.open_port() self.open_port()
@ -515,18 +515,18 @@ class RNodeInterface(Interface):
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
else: else:
raise IOError("Could not open serial port") raise OSError("Could not open serial port")
elif self.bt_manager != None: elif self.bt_manager != None:
if self.bt_manager.connected: if self.bt_manager.connected:
self.configure_device() self.configure_device()
else: else:
raise IOError("Could not connect to any Bluetooth devices") raise OSError("Could not connect to any Bluetooth devices")
else: else:
raise IOError("Neither serial port nor Bluetooth devices available") raise OSError("Neither serial port nor Bluetooth devices available")
except Exception as e: 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)
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
if len(self.hw_errors) == 0: if len(self.hw_errors) == 0:
RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR) RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR)
thread = threading.Thread(target=self.reconnect_port, daemon=True).start() thread = threading.Thread(target=self.reconnect_port, daemon=True).start()
@ -538,7 +538,7 @@ class RNodeInterface(Interface):
elif self.bt_manager != None: elif self.bt_manager != None:
return self.bt_manager.read() return self.bt_manager.read()
else: else:
raise IOError("No ports available for reading") raise OSError("No ports available for reading")
def write_mux(self, data): def write_mux(self, data):
if self.serial != None: if self.serial != None:
@ -551,7 +551,7 @@ class RNodeInterface(Interface):
self.last_port_io = time.time() self.last_port_io = time.time()
return written return written
else: else:
raise IOError("No ports available for writing") raise OSError("No ports available for writing")
# def reset_ble(self): # def reset_ble(self):
# RNS.log(f"Clearing previous connection instance: "+str(self.ble)) # RNS.log(f"Clearing previous connection instance: "+str(self.ble))
@ -565,7 +565,7 @@ class RNodeInterface(Interface):
def open_port(self): def open_port(self):
if not self.use_ble: if not self.use_ble:
if self.port != None: if self.port != None:
RNS.log("Opening serial port "+self.port+"...") RNS.log(f"Opening serial port {self.port}...")
# Get device parameters # Get device parameters
from usb4a import usb from usb4a import usb
device = usb.get_usb_device(self.port) device = usb.get_usb_device(self.port)
@ -577,7 +577,7 @@ class RNodeInterface(Interface):
proxy = self.pyserial.get_serial_port proxy = self.pyserial.get_serial_port
if vid == 0x1A86 and pid == 0x55D4: if vid == 0x1A86 and pid == 0x55D4:
# Force CDC driver for Qinheng CH34x # 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 from usbserial4a.cdcacmserial4a import CdcAcmSerial
proxy = CdcAcmSerial proxy = CdcAcmSerial
@ -616,9 +616,9 @@ class RNodeInterface(Interface):
self.serial.USB_READ_TIMEOUT_MILLIS = 100 self.serial.USB_READ_TIMEOUT_MILLIS = 100
self.serial.timeout = 0.1 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(f"{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(f"{self} USB read timeout set to {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 write timeout set to {self.serial.USB_WRITE_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG)
elif self.allow_bluetooth: elif self.allow_bluetooth:
if self.bt_manager == None: 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) RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR)
if not self.detected: if not self.detected:
raise IOError("Could not detect device") raise OSError("Could not detect device")
else: else:
if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52: if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52:
self.display = True self.display = True
if not self.firmware_ok: if not self.firmware_ok:
raise IOError("Invalid device firmware") raise OSError("Invalid device firmware")
if self.serial != None and self.port != None: if self.serial != None and self.port != None:
self.timeout = 200 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: if self.bt_manager != None and self.bt_manager.connected:
self.timeout = 1500 self.timeout = 1500
@ -680,11 +680,11 @@ class RNodeInterface(Interface):
self.initRadio() self.initRadio()
if (self.validateRadioState()): if (self.validateRadioState()):
self.interface_ready = True 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) sleep(0.3)
self.online = True self.online = True
else: 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("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR)
RNS.log("Aborting RNode startup", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
@ -693,7 +693,7 @@ class RNodeInterface(Interface):
if self.bt_manager != None: if self.bt_manager != None:
self.bt_manager.close() 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): 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]) 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) written = self.write_mux(kiss_command)
if written != len(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): def leave(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def enable_bluetooth(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def disable_bluetooth(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x00, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x00, KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def bluetooth_pair(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x02, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x02, KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def enable_external_framebuffer(self):
if self.display != None: if self.display != None:
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def disable_external_framebuffer(self):
if self.display != None: if self.display != None:
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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_PIXEL_WIDTH = 64
FB_BITS_PER_PIXEL = 1 FB_BITS_PER_PIXEL = 1
@ -791,13 +791,13 @@ class RNodeInterface(Interface):
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def hard_reset(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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); sleep(4.0);
def setFrequency(self): def setFrequency(self):
@ -810,7 +810,7 @@ class RNodeInterface(Interface):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def setBandwidth(self):
c1 = self.bandwidth >> 24 c1 = self.bandwidth >> 24
@ -822,28 +822,28 @@ class RNodeInterface(Interface):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def setTXPower(self):
txp = bytes([self.txpower]) txp = bytes([self.txpower])
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def setSpreadingFactor(self):
sf = bytes([self.sf]) sf = bytes([self.sf])
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def setCodingRate(self):
cr = bytes([self.cr]) cr = bytes([self.cr])
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def setSTALock(self):
if self.st_alock != None: 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def setLTALock(self):
if self.lt_alock != None: 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def setRadioState(self, state):
self.state = state self.state = state
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(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): def validate_firmware(self):
if (self.maj_version > RNodeInterface.REQUIRED_FW_VER_MAJ): if (self.maj_version > RNodeInterface.REQUIRED_FW_VER_MAJ):
@ -887,17 +887,17 @@ class RNodeInterface(Interface):
if self.firmware_ok: if self.firmware_ok:
return return
RNS.log("The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version), 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("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"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/") 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 = f"The firmware version of the connected RNode is {self.maj_version}.{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"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/" 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}) self.hw_errors.append({"error": KISS.ERROR_INVALID_FIRMWARE, "description": error_description})
def validateRadioState(self): 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: if not self.platform == KISS.PLATFORM_ESP32:
sleep(1.00); sleep(1.00);
else: else:
@ -937,7 +937,7 @@ class RNodeInterface(Interface):
try: try:
self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 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) 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: except:
self.bitrate = 0 self.bitrate = 0
@ -969,7 +969,7 @@ class RNodeInterface(Interface):
self.txb += datalen self.txb += datalen
if written != len(frame): 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: else:
self.queue(data) self.queue(data)
@ -1042,7 +1042,7 @@ class RNodeInterface(Interface):
command_buffer = command_buffer+bytes([byte]) command_buffer = command_buffer+bytes([byte])
if (len(command_buffer) == 4): if (len(command_buffer) == 4):
self.r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] 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() self.updateBitrate()
elif (command == KISS.CMD_BANDWIDTH): elif (command == KISS.CMD_BANDWIDTH):
@ -1058,26 +1058,26 @@ class RNodeInterface(Interface):
command_buffer = command_buffer+bytes([byte]) command_buffer = command_buffer+bytes([byte])
if (len(command_buffer) == 4): if (len(command_buffer) == 4):
self.r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] 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() self.updateBitrate()
elif (command == KISS.CMD_TXPOWER): elif (command == KISS.CMD_TXPOWER):
self.r_txpower = byte 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): elif (command == KISS.CMD_SF):
self.r_sf = byte 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() self.updateBitrate()
elif (command == KISS.CMD_CR): elif (command == KISS.CMD_CR):
self.r_cr = byte 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() self.updateBitrate()
elif (command == KISS.CMD_RADIO_STATE): elif (command == KISS.CMD_RADIO_STATE):
self.r_state = byte self.r_state = byte
if self.r_state: 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: 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): elif (command == KISS.CMD_RADIO_LOCK):
self.r_lock = byte self.r_lock = byte
@ -1156,7 +1156,7 @@ class RNodeInterface(Interface):
if (len(command_buffer) == 2): if (len(command_buffer) == 2):
at = command_buffer[0] << 8 | command_buffer[1] at = command_buffer[0] << 8 | command_buffer[1]
self.r_st_alock = at/100.0 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): elif (command == KISS.CMD_LT_ALOCK):
if (byte == KISS.FESC): if (byte == KISS.FESC):
escape = True escape = True
@ -1171,7 +1171,7 @@ class RNodeInterface(Interface):
if (len(command_buffer) == 2): if (len(command_buffer) == 2):
at = command_buffer[0] << 8 | command_buffer[1] at = command_buffer[0] << 8 | command_buffer[1]
self.r_lt_alock = at/100.0 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): elif (command == KISS.CMD_STAT_CHTM):
if (byte == KISS.FESC): if (byte == KISS.FESC):
escape = True escape = True
@ -1217,9 +1217,9 @@ class RNodeInterface(Interface):
self.r_preamble_symbols = prs self.r_preamble_symbols = prs
self.r_premable_time_ms = prt self.r_premable_time_ms = prt
self.r_csma_slot_time_ms = cst 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(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(str(self)+" Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", 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(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 CSMA slot time is {self.r_csma_slot_time_ms}ms", RNS.LOG_DEBUG)
elif (command == KISS.CMD_STAT_BAT): elif (command == KISS.CMD_STAT_BAT):
if (byte == KISS.FESC): if (byte == KISS.FESC):
escape = True escape = True
@ -1247,26 +1247,26 @@ class RNodeInterface(Interface):
self.mcu = byte self.mcu = byte
elif (command == KISS.CMD_ERROR): elif (command == KISS.CMD_ERROR):
if (byte == KISS.ERROR_INITRADIO): if (byte == KISS.ERROR_INITRADIO):
RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) RNS.log(f"{self} hardware initialisation error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR)
raise IOError("Radio initialisation failure") raise OSError("Radio initialisation failure")
elif (byte == KISS.ERROR_TXFAILED): elif (byte == KISS.ERROR_TXFAILED):
RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) RNS.log(f"{self} hardware TX error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR)
raise IOError("Hardware transmit failure") raise OSError("Hardware transmit failure")
elif (byte == KISS.ERROR_MEMORY_LOW): 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"}) self.hw_errors.append({"error": KISS.ERROR_MEMORY_LOW, "description": "Memory exhausted on connected device"})
elif (byte == KISS.ERROR_MODEM_TIMEOUT): 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"}) self.hw_errors.append({"error": KISS.ERROR_MODEM_TIMEOUT, "description": "Modem communication timed out on connected device"})
else: else:
RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR)
raise IOError("Unknown hardware failure") raise OSError("Unknown hardware failure")
elif (command == KISS.CMD_RESET): elif (command == KISS.CMD_RESET):
if (byte == 0xF8): if (byte == 0xF8):
if self.platform == KISS.PLATFORM_ESP32: if self.platform == KISS.PLATFORM_ESP32:
if self.online: if self.online:
RNS.log("Detected reset while device was online, reinitialising device...", RNS.LOG_ERROR) 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): elif (command == KISS.CMD_READY):
self.process_queue() self.process_queue()
elif (command == KISS.CMD_DETECT): elif (command == KISS.CMD_DETECT):
@ -1278,7 +1278,7 @@ class RNodeInterface(Interface):
if got == 0: if got == 0:
time_since_last = int(time.time()*1000) - last_read_ms time_since_last = int(time.time()*1000) - last_read_ms
if len(data_buffer) > 0 and time_since_last > self.timeout: 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"" data_buffer = b""
in_frame = False in_frame = False
command = KISS.CMD_UNKNOWN command = KISS.CMD_UNKNOWN
@ -1287,22 +1287,22 @@ class RNodeInterface(Interface):
if self.id_interval != None and self.id_callsign != None: if self.id_interval != None and self.id_callsign != None:
if self.first_tx != None: if self.first_tx != None:
if time.time() > self.first_tx + self.id_interval: 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) self.processOutgoing(self.id_callsign)
if (time.time() - self.last_port_io > self.port_io_timeout): if (time.time() - self.last_port_io > self.port_io_timeout):
self.detect() self.detect()
if (time.time() - self.last_port_io > self.port_io_timeout*3): 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: if self.bt_manager != None:
sleep(0.08) sleep(0.08)
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"A serial port occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -1330,10 +1330,10 @@ class RNodeInterface(Interface):
try: try:
time.sleep(self.reconnect_w) time.sleep(self.reconnect_w)
if self.serial != None and self.port != None: 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: 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() self.open_port()
@ -1352,10 +1352,10 @@ class RNodeInterface(Interface):
self.enable_external_framebuffer() self.enable_external_framebuffer()
except Exception as e: 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: if self.online:
RNS.log("Reconnected serial port for "+str(self)) RNS.log(f"Reconnected serial port for {self}")
def detach(self): def detach(self):
self.detached = True self.detached = True
@ -1399,7 +1399,7 @@ class RNodeInterface(Interface):
return data return data
def __str__(self): def __str__(self):
return "RNodeInterface["+str(self.name)+"]" return f"RNodeInterface[{self.name}]"
class BLEConnection(BluetoothDispatcher): class BLEConnection(BluetoothDispatcher):
UART_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e" UART_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"
@ -1472,7 +1472,7 @@ class BLEConnection(BluetoothDispatcher):
RNS.trace_exception(e) RNS.trace_exception(e)
def __init__(self, owner=None, target_name=None, target_bt_addr=None): def __init__(self, owner=None, target_name=None, target_bt_addr=None):
super(BLEConnection, self).__init__() super().__init__()
self.owner = owner self.owner = owner
self.target_name = target_name self.target_name = target_name
self.target_bt_addr = target_bt_addr self.target_bt_addr = target_bt_addr

View File

@ -98,17 +98,17 @@ class SerialInterface(Interface):
try: try:
self.open_port() self.open_port()
except Exception as e: 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 raise e
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
else: else:
raise IOError("Could not open serial port") raise OSError("Could not open serial port")
def open_port(self): def open_port(self):
RNS.log("Opening serial port "+self.port+"...") RNS.log(f"Opening serial port {self.port}...")
# Get device parameters # Get device parameters
from usb4a import usb from usb4a import usb
device = usb.get_usb_device(self.port) device = usb.get_usb_device(self.port)
@ -120,7 +120,7 @@ class SerialInterface(Interface):
proxy = self.pyserial.get_serial_port proxy = self.pyserial.get_serial_port
if vid == 0x1A86 and pid == 0x55D4: if vid == 0x1A86 and pid == 0x55D4:
# Force CDC driver for Qinheng CH34x # 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 from usbserial4a.cdcacmserial4a import CdcAcmSerial
proxy = CdcAcmSerial proxy = CdcAcmSerial
@ -159,9 +159,9 @@ class SerialInterface(Interface):
self.serial.USB_READ_TIMEOUT_MILLIS = 100 self.serial.USB_READ_TIMEOUT_MILLIS = 100
self.serial.timeout = 0.1 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(f"{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(f"{self} USB read timeout set to {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 write timeout set to {self.serial.USB_WRITE_TIMEOUT_MILLIS}ms", RNS.LOG_DEBUG)
def configure_device(self): def configure_device(self):
sleep(0.5) sleep(0.5)
@ -169,7 +169,7 @@ class SerialInterface(Interface):
thread.daemon = True thread.daemon = True
thread.start() thread.start()
self.online = True 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): def processIncoming(self, data):
@ -184,7 +184,7 @@ class SerialInterface(Interface):
written = self.serial.write(data) written = self.serial.write(data)
self.txb += len(data) self.txb += len(data)
if written != 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): def readLoop(self):
try: try:
@ -228,8 +228,8 @@ class SerialInterface(Interface):
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -244,17 +244,17 @@ class SerialInterface(Interface):
while not self.online: while not self.online:
try: try:
time.sleep(5) 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() self.open_port()
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
except Exception as e: 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): def should_ingress_limit(self):
return False return False
def __str__(self): def __str__(self):
return "SerialInterface["+self.name+"]" return f"SerialInterface[{self.name}]"

View File

@ -23,5 +23,5 @@
import os import os
import glob 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')] __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]

View File

@ -35,7 +35,7 @@ import RNS
class AutoInterface(Interface): class AutoInterface(Interface):
DEFAULT_DISCOVERY_PORT = 29716 DEFAULT_DISCOVERY_PORT = 29716
DEFAULT_DATA_PORT = 42671 DEFAULT_DATA_PORT = 42671
DEFAULT_GROUP_ID = "reticulum".encode("utf-8") DEFAULT_GROUP_ID = b"reticulum"
SCOPE_LINK = "2" SCOPE_LINK = "2"
SCOPE_ADMIN = "4" SCOPE_ADMIN = "4"
@ -169,32 +169,32 @@ class AutoInterface(Interface):
self.group_hash = RNS.Identity.full_hash(self.group_id) self.group_hash = RNS.Identity.full_hash(self.group_id)
g = self.group_hash g = self.group_hash
#gt = "{:02x}".format(g[1]+(g[0]<<8)) #gt = f"{g[1] + (g[0] << 8):02x}"
gt = "0" gt = "0"
gt += ":"+"{:02x}".format(g[3]+(g[2]<<8)) gt += f":{g[3] + (g[2] << 8):02x}"
gt += ":"+"{:02x}".format(g[5]+(g[4]<<8)) gt += f":{g[5] + (g[4] << 8):02x}"
gt += ":"+"{:02x}".format(g[7]+(g[6]<<8)) gt += f":{g[7] + (g[6] << 8):02x}"
gt += ":"+"{:02x}".format(g[9]+(g[8]<<8)) gt += f":{g[9] + (g[8] << 8):02x}"
gt += ":"+"{:02x}".format(g[11]+(g[10]<<8)) gt += f":{g[11] + (g[10] << 8):02x}"
gt += ":"+"{:02x}".format(g[13]+(g[12]<<8)) gt += f":{g[13] + (g[12] << 8):02x}"
self.mcast_discovery_address = "ff"+self.multicast_address_type+self.discovery_scope+":"+gt self.mcast_discovery_address = f"ff{self.multicast_address_type}{self.discovery_scope}:{gt}"
suitable_interfaces = 0 suitable_interfaces = 0
for ifname in self.list_interfaces(): for ifname in self.list_interfaces():
try: try:
if RNS.vendor.platformutils.is_darwin() and ifname in AutoInterface.DARWIN_IGNORE_IFS and not ifname in self.allowed_interfaces: 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": 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: 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: 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: 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: else:
if len(self.allowed_interfaces) > 0 and not ifname in self.allowed_interfaces: 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: else:
addresses = self.list_addresses(ifname) addresses = self.list_addresses(ifname)
if self.netinfo.AF_INET6 in addresses: 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) RNS.log(f"{self} Selecting link-local address {link_local_addr} for interface {ifname}", RNS.LOG_EXTREME)
if link_local_addr == None: 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: else:
mcast_addr = self.mcast_discovery_address 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 # Struct with interface index
if_struct = struct.pack("I", self.interface_name_to_index(ifname)) if_struct = struct.pack("I", self.interface_name_to_index(ifname))
@ -243,7 +243,7 @@ class AutoInterface(Interface):
else: else:
if self.discovery_scope == AutoInterface.SCOPE_LINK: 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: else:
addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) 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) 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: 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: else:
self.receives = True self.receives = True
@ -277,13 +277,13 @@ class AutoInterface(Interface):
self.bitrate = AutoInterface.BITRATE_GUESS self.bitrate = AutoInterface.BITRATE_GUESS
peering_wait = self.announce_interval*1.2 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 self.owner = owner
socketserver.UDPServer.address_family = socket.AF_INET6 socketserver.UDPServer.address_family = socket.AF_INET6
for ifname in self.adopted_interfaces: 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) addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM)
address = addr_info[0][4] address = addr_info[0][4]
@ -317,7 +317,7 @@ class AutoInterface(Interface):
if data == expected_hash: if data == expected_hash:
self.add_peer(ipv6_src[0], ifname) self.add_peer(ipv6_src[0], ifname)
else: 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): def peer_jobs(self):
while True: while True:
@ -335,7 +335,7 @@ class AutoInterface(Interface):
# Remove any timed out peers # Remove any timed out peers
for peer_addr in timed_out_peers: for peer_addr in timed_out_peers:
removed_peer = self.peers.pop(peer_addr) 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: for ifname in self.adopted_interfaces:
# Check that the link-local address has not changed # Check that the link-local address has not changed
@ -349,25 +349,25 @@ class AutoInterface(Interface):
link_local_addr = self.descope_linklocal(address["addr"]) link_local_addr = self.descope_linklocal(address["addr"])
if link_local_addr != self.adopted_interfaces[ifname]: if link_local_addr != self.adopted_interfaces[ifname]:
old_link_local_address = 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.adopted_interfaces[ifname] = link_local_addr
self.link_local_addresses.append(link_local_addr) self.link_local_addresses.append(link_local_addr)
if old_link_local_address in self.link_local_addresses: if old_link_local_address in self.link_local_addresses:
self.link_local_addresses.remove(old_link_local_address) 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) addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM)
listen_address = addr_info[0][4] listen_address = addr_info[0][4]
if ifname in self.interface_servers: 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] previous_server = self.interface_servers[ifname]
def shutdown_server(): def shutdown_server():
previous_server.shutdown() previous_server.shutdown()
threading.Thread(target=shutdown_server, daemon=True).start() 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)) udp_server = socketserver.UDPServer(listen_address, self.handler_factory(self.processIncoming))
self.interface_servers[ifname] = udp_server self.interface_servers[ifname] = udp_server
@ -379,7 +379,7 @@ class AutoInterface(Interface):
self.carrier_changed = True self.carrier_changed = True
except Exception as e: 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 # Check multicast echo timeouts
last_multicast_echo = 0 last_multicast_echo = 0
@ -389,12 +389,12 @@ class AutoInterface(Interface):
if now - last_multicast_echo > self.multicast_echo_timeout: if now - last_multicast_echo > self.multicast_echo_timeout:
if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == False: if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == False:
self.carrier_changed = True 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 self.timed_out_interfaces[ifname] = True
else: else:
if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == True: if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == True:
self.carrier_changed = 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 self.timed_out_interfaces[ifname] = False
@ -417,7 +417,7 @@ class AutoInterface(Interface):
except Exception as e: 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: 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: else:
pass pass
@ -431,12 +431,12 @@ class AutoInterface(Interface):
if ifname != None: if ifname != None:
self.multicast_echoes[ifname] = time.time() self.multicast_echoes[ifname] = time.time()
else: 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: else:
if not addr in self.peers: if not addr in self.peers:
self.peers[addr] = [ifname, time.time()] 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: else:
self.refresh_peer(addr) self.refresh_peer(addr)
@ -464,12 +464,12 @@ class AutoInterface(Interface):
if self.outbound_udp_socket == None: if self.outbound_udp_socket == None:
self.outbound_udp_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) 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) 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]) self.outbound_udp_socket.sendto(data, addr_info[0][4])
except Exception as e: 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) self.txb += len(data)
@ -481,7 +481,7 @@ class AutoInterface(Interface):
return False return False
def __str__(self): def __str__(self):
return "AutoInterface["+self.name+"]" return f"AutoInterface[{self.name}]"
class AutoInterfaceHandler(socketserver.BaseRequestHandler): class AutoInterfaceHandler(socketserver.BaseRequestHandler):
def __init__(self, callback, *args, **keys): def __init__(self, callback, *args, **keys):

View File

@ -90,7 +90,7 @@ class I2PController:
time.sleep(0.10) time.sleep(0.10)
if self.loop == None: 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: while self.loop == None:
self.loop = asyncio.get_event_loop() self.loop = asyncio.get_event_loop()
@ -101,7 +101,7 @@ class I2PController:
self.loop.run_forever() self.loop.run_forever()
except Exception as e: except Exception as e:
self.ready = False 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: finally:
self.loop.close() self.loop.close()
@ -136,7 +136,7 @@ class I2PController:
if not self.client_tunnels[i2p_destination]: if not self.client_tunnels[i2p_destination]:
try: try:
async def tunnel_up(): 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) tunnel = self.i2plib.ClientTunnel(i2p_destination, owner.local_addr, sam_address=self.sam_address, loop=self.loop)
self.i2plib_tunnels[i2p_destination] = tunnel self.i2plib_tunnels[i2p_destination] = tunnel
await tunnel.run() await tunnel.run()
@ -145,7 +145,7 @@ class I2PController:
result = asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result() result = asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result()
if not i2p_destination in self.i2plib_tunnels: 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: else:
tn = self.i2plib_tunnels[i2p_destination] tn = self.i2plib_tunnels[i2p_destination]
@ -167,19 +167,19 @@ class I2PController:
try: try:
owner.socket.shutdown(socket.SHUT_RDWR) owner.socket.shutdown(socket.SHUT_RDWR)
except Exception as e: 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: try:
owner.socket.close() owner.socket.close()
except Exception as e: 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 self.client_tunnels[i2p_destination] = True
owner.awaiting_i2p_tunnel = False 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: else:
raise IOError("Got no status response from SAM API") raise OSError("Got no status response from SAM API")
except ConnectionRefusedError as e: except ConnectionRefusedError as e:
raise e raise e
@ -188,7 +188,7 @@ class I2PController:
raise e raise e
except Exception as 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 raise e
else: else:
@ -197,16 +197,16 @@ class I2PController:
i2p_exception = i2ptunnel.status["exception"] i2p_exception = i2ptunnel.status["exception"]
if i2ptunnel.status["setup_ran"] == False: 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) self.stop_tunnel(i2ptunnel)
return False return False
elif i2p_exception != None: 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): 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): 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) 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) 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): 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): 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): 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): elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError):
RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR)
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): 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) RNS.log("Resetting I2P tunnel and retrying later", RNS.LOG_ERROR)
@ -238,13 +238,13 @@ class I2PController:
return False return False
elif i2ptunnel.status["setup_failed"] == True: 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) self.stop_tunnel(i2ptunnel)
return False return False
else: 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) self.stop_tunnel(i2ptunnel)
return False return False
@ -259,11 +259,11 @@ class I2PController:
# Old format # Old format
i2p_dest_hash_of = RNS.Identity.full_hash(RNS.Identity.full_hash(owner.name.encode("utf-8"))) 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 # 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_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 # Use old format if a key is already present
if os.path.isfile(i2p_keyfile_of): if os.path.isfile(i2p_keyfile_of):
@ -279,7 +279,7 @@ class I2PController:
key_file.write(i2p_dest.private_key.base64) key_file.write(i2p_dest.private_key.base64)
key_file.close() key_file.close()
else: else:
key_file = open(i2p_keyfile, "r") key_file = open(i2p_keyfile)
prvd = key_file.read() prvd = key_file.read()
key_file.close() key_file.close()
i2p_dest = self.i2plib.Destination(data=prvd, has_private_key=True) i2p_dest = self.i2plib.Destination(data=prvd, has_private_key=True)
@ -294,12 +294,12 @@ class I2PController:
if self.server_tunnels[i2p_b32] == False: if self.server_tunnels[i2p_b32] == False:
try: try:
async def tunnel_up(): 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) 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 self.i2plib_tunnels[i2p_b32] = tunnel
await tunnel.run() await tunnel.run()
owner.online = True 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() asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result()
self.server_tunnels[i2p_b32] = True self.server_tunnels[i2p_b32] = True
@ -313,7 +313,7 @@ class I2PController:
i2p_exception = i2ptunnel.status["exception"] i2p_exception = i2ptunnel.status["exception"]
if i2ptunnel.status["setup_ran"] == False: 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) self.stop_tunnel(i2ptunnel)
return False return False
@ -322,7 +322,7 @@ class I2PController:
RNS.log("An error ocurred while setting up I2P tunnel", RNS.LOG_ERROR) RNS.log("An error ocurred while setting up I2P tunnel", RNS.LOG_ERROR)
if isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.CantReachPeer): 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): 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) 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) 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): 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): 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): 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): elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError):
RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR)
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): 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) RNS.log("Resetting I2P tunnel and retrying later", RNS.LOG_ERROR)
@ -354,13 +354,13 @@ class I2PController:
return False return False
elif i2ptunnel.status["setup_failed"] == True: 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) self.stop_tunnel(i2ptunnel)
return False return False
else: 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) self.stop_tunnel(i2ptunnel)
return False return False
@ -475,11 +475,11 @@ class I2PInterfacePeer(Interface):
self.target_port = self.bind_port self.target_port = self.bind_port
if not self.parent_interface.i2p.client_tunnel(self, target_i2p_dest): 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 self.awaiting_i2p_tunnel = True
except Exception as e: 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) RNS.log("Check that I2P is installed and running, and that SAM is enabled. Retrying tunnel setup later.", RNS.LOG_ERROR)
time.sleep(8) time.sleep(8)
@ -532,16 +532,16 @@ class I2PInterfacePeer(Interface):
if socket != None: if socket != None:
target_socket.shutdown(socket.SHUT_RDWR) target_socket.shutdown(socket.SHUT_RDWR)
except Exception as e: 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: try:
if socket != None: if socket != None:
target_socket.close() target_socket.close()
except Exception as e: 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): def detach(self):
RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) RNS.log(f"Detaching {self}", RNS.LOG_DEBUG)
if self.socket != None: if self.socket != None:
if hasattr(self.socket, "close"): if hasattr(self.socket, "close"):
if callable(self.socket.close): if callable(self.socket.close):
@ -550,12 +550,12 @@ class I2PInterfacePeer(Interface):
try: try:
self.socket.shutdown(socket.SHUT_RDWR) self.socket.shutdown(socket.SHUT_RDWR)
except Exception as e: 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: try:
self.socket.close() self.socket.close()
except Exception as e: 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 self.socket = None
@ -568,8 +568,8 @@ class I2PInterfacePeer(Interface):
except Exception as e: except Exception as e:
if initial: if initial:
if not self.awaiting_i2p_tunnel: if not self.awaiting_i2p_tunnel:
RNS.log("Initial connection for "+str(self)+" could not be established: "+str(e), RNS.LOG_ERROR) RNS.log(f"Initial connection for {self} could not be established: {e}", RNS.LOG_ERROR)
RNS.log("Leaving unconnected and retrying connection in "+str(I2PInterfacePeer.RECONNECT_WAIT)+" seconds.", RNS.LOG_ERROR) RNS.log(f"Leaving unconnected and retrying connection in {I2PInterfacePeer.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR)
return False return False
@ -600,7 +600,7 @@ class I2PInterfacePeer(Interface):
attempts += 1 attempts += 1
if self.max_reconnect_tries != None and attempts > self.max_reconnect_tries: 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() self.teardown()
break break
@ -609,12 +609,12 @@ class I2PInterfacePeer(Interface):
except Exception as e: except Exception as e:
if not self.awaiting_i2p_tunnel: 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: 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: 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 self.reconnecting = False
thread = threading.Thread(target=self.read_loop) thread = threading.Thread(target=self.read_loop)
@ -625,7 +625,7 @@ class I2PInterfacePeer(Interface):
else: else:
RNS.log("Attempt to reconnect on a non-initiator I2P interface. This should not happen.", RNS.LOG_ERROR) 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): def processIncoming(self, data):
self.rxb += len(data) self.rxb += len(data)
@ -656,8 +656,8 @@ class I2PInterfacePeer(Interface):
self.parent_interface.txb += len(data) self.parent_interface.txb += len(data)
except Exception as e: except Exception as e:
RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) RNS.log(f"Exception occurred while transmitting via {self}, tearing down interface", 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.teardown() self.teardown()
@ -683,7 +683,7 @@ class I2PInterfacePeer(Interface):
if self.socket != None: if self.socket != None:
self.socket.sendall(bytes([HDLC.FLAG, HDLC.FLAG])) self.socket.sendall(bytes([HDLC.FLAG, HDLC.FLAG]))
except Exception as e: 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) self.shutdown_socket(self.socket)
should_run = False should_run = False
@ -693,12 +693,12 @@ class I2PInterfacePeer(Interface):
try: try:
self.socket.shutdown(socket.SHUT_RDWR) self.socket.shutdown(socket.SHUT_RDWR)
except Exception as e: 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: try:
self.socket.close() self.socket.close()
except Exception as e: 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 should_run = False
@ -782,10 +782,10 @@ class I2PInterfacePeer(Interface):
self.wd_reset = False self.wd_reset = False
if self.initiator and not self.detached: 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() self.reconnect()
else: 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() self.teardown()
break break
@ -793,7 +793,7 @@ class I2PInterfacePeer(Interface):
except Exception as e: except Exception as e:
self.online = False 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: if self.initiator:
RNS.log("Attempting to reconnect...", RNS.LOG_WARNING) RNS.log("Attempting to reconnect...", RNS.LOG_WARNING)
@ -803,12 +803,12 @@ class I2PInterfacePeer(Interface):
def teardown(self): def teardown(self):
if self.initiator and not self.detached: 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
else: 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.online = False
self.OUT = False self.OUT = False
@ -824,7 +824,7 @@ class I2PInterfacePeer(Interface):
def __str__(self): def __str__(self):
return "I2PInterfacePeer["+str(self.name)+"]" return f"I2PInterfacePeer[{self.name}]"
class I2PInterface(Interface): class I2PInterface(Interface):
@ -895,11 +895,11 @@ class I2PInterface(Interface):
while True: while True:
try: try:
if not self.i2p.server_tunnel(self): 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 self.online = False
except Exception as e: 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) RNS.log("Check that I2P is installed and running, and that SAM is enabled. Retrying tunnel setup later.", RNS.LOG_ERROR)
time.sleep(15) time.sleep(15)
@ -911,7 +911,7 @@ class I2PInterface(Interface):
if peers != None: if peers != None:
for peer_addr in peers: 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 = I2PInterfacePeer(self, self.owner, interface_name, peer_addr)
peer_interface.OUT = True peer_interface.OUT = True
peer_interface.IN = True peer_interface.IN = True
@ -921,7 +921,7 @@ class I2PInterface(Interface):
def incoming_connection(self, handler): def incoming_connection(self, handler):
RNS.log("Accepting incoming I2P connection", RNS.LOG_VERBOSE) 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 = I2PInterfacePeer(self, self.owner, interface_name, connected_socket=handler.request)
spawned_interface.OUT = True spawned_interface.OUT = True
spawned_interface.IN = True spawned_interface.IN = True
@ -954,7 +954,7 @@ class I2PInterface(Interface):
spawned_interface.announce_rate_penalty = self.announce_rate_penalty spawned_interface.announce_rate_penalty = self.announce_rate_penalty
spawned_interface.mode = self.mode spawned_interface.mode = self.mode
spawned_interface.HW_MTU = self.HW_MTU 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) RNS.Transport.interfaces.append(spawned_interface)
self.clients += 1 self.clients += 1
spawned_interface.read_loop() spawned_interface.read_loop()
@ -969,11 +969,11 @@ class I2PInterface(Interface):
if from_spawned: self.oa_freq_deque.append(time.time()) if from_spawned: self.oa_freq_deque.append(time.time())
def detach(self): def detach(self):
RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) RNS.log(f"Detaching {self}", RNS.LOG_DEBUG)
self.i2p.stop() self.i2p.stop()
def __str__(self): def __str__(self):
return "I2PInterface["+self.name+"]" return f"I2PInterface[{self.name}]"
class I2PInterfaceHandler(socketserver.BaseRequestHandler): class I2PInterfaceHandler(socketserver.BaseRequestHandler):
def __init__(self, callback, *args, **keys): def __init__(self, callback, *args, **keys):

View File

@ -140,7 +140,7 @@ class Interface:
selected_announce_packet = announce_packet selected_announce_packet = announce_packet
if selected_announce_packet != None: 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.ic_held_release = time.time() + self.ic_held_release_interval
self.held_announces.pop(selected_announce_packet.destination_hash) self.held_announces.pop(selected_announce_packet.destination_hash)
def release(): def release():
@ -148,8 +148,8 @@ class Interface:
threading.Thread(target=release, daemon=True).start() threading.Thread(target=release, daemon=True).start()
except Exception as e: except Exception as e:
RNS.log("An error occurred while processing held announces for "+str(self), RNS.LOG_ERROR) RNS.log(f"An error occurred while processing held announces for {self}", 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)
def received_announce(self): def received_announce(self):
self.ia_freq_deque.append(time.time()) self.ia_freq_deque.append(time.time())
@ -234,7 +234,7 @@ class Interface:
except Exception as e: except Exception as e:
self.announce_queue = [] 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) RNS.log("The announce queue for this interface has been cleared.", RNS.LOG_ERROR)
def detach(self): def detach(self):

View File

@ -113,17 +113,17 @@ class KISSInterface(Interface):
try: try:
self.open_port() self.open_port()
except Exception as e: 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 raise e
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
else: else:
raise IOError("Could not open serial port") raise OSError("Could not open serial port")
def open_port(self): 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( self.serial = self.pyserial.Serial(
port = self.port, port = self.port,
baudrate = self.speed, baudrate = self.speed,
@ -146,7 +146,7 @@ class KISSInterface(Interface):
thread.daemon = True thread.daemon = True
thread.start() thread.start()
self.online = True 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...") RNS.log("Configuring KISS interface parameters...")
self.setPreamble(self.preamble) self.setPreamble(self.preamble)
self.setTxTail(self.txtail) 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXDELAY])+bytes([preamble])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setTxTail(self, txtail):
txtail_ms = 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXTAIL])+bytes([txtail])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setPersistence(self, persistence):
if persistence < 0: if persistence < 0:
@ -192,7 +192,7 @@ class KISSInterface(Interface):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_P])+bytes([persistence])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setSlotTime(self, slottime):
slottime_ms = 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]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SLOTTIME])+bytes([slottime])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setFlowControl(self, flow_control):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_READY])+bytes([0x01])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
if (flow_control): if (flow_control):
raise IOError("Could not enable KISS interface flow control") raise OSError("Could not enable KISS interface flow control")
else: else:
raise IOError("Could not enable KISS interface flow control") raise OSError("Could not enable KISS interface flow control")
def processIncoming(self, data): def processIncoming(self, data):
@ -244,7 +244,7 @@ class KISSInterface(Interface):
self.first_tx = time.time() self.first_tx = time.time()
if written != len(frame): 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: else:
self.queue(data) self.queue(data)
@ -311,20 +311,20 @@ class KISSInterface(Interface):
if self.flow_control: if self.flow_control:
if not self.interface_ready: if not self.interface_ready:
if time.time() > self.flow_control_locked + self.flow_control_timeout: 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() self.process_queue()
if self.beacon_i != None and self.beacon_d != None: if self.beacon_i != None and self.beacon_d != None:
if self.first_tx != None: if self.first_tx != None:
if time.time() > self.first_tx + self.beacon_i: 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.first_tx = None
self.processOutgoing(self.beacon_d) self.processOutgoing(self.beacon_d)
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -339,17 +339,17 @@ class KISSInterface(Interface):
while not self.online: while not self.online:
try: try:
time.sleep(5) 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() self.open_port()
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
except Exception as e: 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): def should_ingress_limit(self):
return False return False
def __str__(self): def __str__(self):
return "KISSInterface["+self.name+"]" return f"KISSInterface[{self.name}]"

View File

@ -133,10 +133,10 @@ class LocalClientInterface(Interface):
self.connect() self.connect()
except Exception as e: 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: 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 self.reconnecting = False
thread = threading.Thread(target=self.read_loop) thread = threading.Thread(target=self.read_loop)
@ -149,7 +149,7 @@ class LocalClientInterface(Interface):
else: else:
RNS.log("Attempt to reconnect on a non-initiator shared local interface. This should not happen.", RNS.LOG_ERROR) 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): def processIncoming(self, data):
@ -188,8 +188,8 @@ class LocalClientInterface(Interface):
self.parent_interface.txb += len(data) self.parent_interface.txb += len(data)
except Exception as e: except Exception as e:
RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) RNS.log(f"Exception occurred while transmitting via {self}, tearing down interface", 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.teardown() self.teardown()
@ -226,7 +226,7 @@ class LocalClientInterface(Interface):
else: else:
self.online = False self.online = False
if self.is_connected_to_shared_instance and not self.detached: 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() RNS.Transport.shared_connection_disappeared()
self.reconnect() self.reconnect()
else: else:
@ -237,26 +237,26 @@ class LocalClientInterface(Interface):
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("An interface error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"An interface error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("Tearing down "+str(self), RNS.LOG_ERROR) RNS.log(f"Tearing down {self}", RNS.LOG_ERROR)
self.teardown() self.teardown()
def detach(self): def detach(self):
if self.socket != None: if self.socket != None:
if hasattr(self.socket, "close"): if hasattr(self.socket, "close"):
if callable(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 self.detached = True
try: try:
self.socket.shutdown(socket.SHUT_RDWR) self.socket.shutdown(socket.SHUT_RDWR)
except Exception as e: 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: try:
self.socket.close() self.socket.close()
except Exception as e: 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 self.socket = None
@ -276,7 +276,7 @@ class LocalClientInterface(Interface):
RNS.Transport.owner._should_persist_data() RNS.Transport.owner._should_persist_data()
if nowarning == False: 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -288,7 +288,7 @@ class LocalClientInterface(Interface):
def __str__(self): def __str__(self):
return "LocalInterface["+str(self.target_port)+"]" return f"LocalInterface[{self.target_port}]"
class LocalServerInterface(Interface): class LocalServerInterface(Interface):
@ -360,7 +360,7 @@ class LocalServerInterface(Interface):
if from_spawned: self.oa_freq_deque.append(time.time()) if from_spawned: self.oa_freq_deque.append(time.time())
def __str__(self): def __str__(self):
return "Shared Instance["+str(self.bind_port)+"]" return f"Shared Instance[{self.bind_port}]"
class LocalInterfaceHandler(socketserver.BaseRequestHandler): class LocalInterfaceHandler(socketserver.BaseRequestHandler):
def __init__(self, callback, *args, **keys): def __init__(self, callback, *args, **keys):

View File

@ -72,17 +72,17 @@ class PipeInterface(Interface):
self.open_pipe() self.open_pipe()
except Exception as e: 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 raise e
if self.pipe_is_open: if self.pipe_is_open:
self.configure_pipe() self.configure_pipe()
else: else:
raise IOError("Could not connect pipe") raise OSError("Could not connect pipe")
def open_pipe(self): 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: try:
self.process = subprocess.Popen(shlex.split(self.command), stdin=subprocess.PIPE, stdout=subprocess.PIPE) 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.daemon = True
thread.start() thread.start()
self.online = True 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): def processIncoming(self, data):
@ -113,7 +113,7 @@ class PipeInterface(Interface):
self.process.stdin.flush() self.process.stdin.flush()
self.txb += len(data) self.txb += len(data)
if written != 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): def readLoop(self):
@ -150,7 +150,7 @@ class PipeInterface(Interface):
escape = False escape = False
data_buffer = data_buffer+bytes([byte]) data_buffer = data_buffer+bytes([byte])
RNS.log("Subprocess terminated on "+str(self)) RNS.log(f"Subprocess terminated on {self}")
self.process.kill() self.process.kill()
except Exception as e: except Exception as e:
@ -160,8 +160,8 @@ class PipeInterface(Interface):
except Exception as e: except Exception as e:
pass pass
RNS.log("A pipe error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"A pipe error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -175,14 +175,14 @@ class PipeInterface(Interface):
while not self.online: while not self.online:
try: try:
time.sleep(self.respawn_delay) 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() self.open_pipe()
if self.pipe_is_open: if self.pipe_is_open:
self.configure_pipe() self.configure_pipe()
except Exception as e: 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): def __str__(self):
return "PipeInterface["+self.name+"]" return f"PipeInterface[{self.name}]"

View File

@ -211,31 +211,31 @@ class RNodeInterface(Interface):
self.validcfg = True self.validcfg = True
if (self.frequency < RNodeInterface.FREQ_MIN or self.frequency > RNodeInterface.FREQ_MAX): 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 self.validcfg = False
if (self.txpower < 0 or self.txpower > 22): 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 self.validcfg = False
if (self.bandwidth < 7800 or self.bandwidth > 1625000): 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 self.validcfg = False
if (self.sf < 5 or self.sf > 12): 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 self.validcfg = False
if (self.cr < 5 or self.cr > 8): 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 self.validcfg = False
if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)): 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 self.validcfg = False
if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)): 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 self.validcfg = False
if id_interval != None and id_callsign != None: 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_callsign = id_callsign.encode("utf-8")
self.id_interval = id_interval self.id_interval = id_interval
else: 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 self.validcfg = False
else: else:
self.id_interval = None self.id_interval = None
self.id_callsign = None self.id_callsign = None
if (not self.validcfg): 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: try:
self.open_port() self.open_port()
@ -259,11 +259,11 @@ class RNodeInterface(Interface):
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
else: else:
raise IOError("Could not open serial port") raise OSError("Could not open serial port")
except Exception as e: 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)
RNS.log("The contained exception was: "+str(e), 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) RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR)
if not self.detached and not self.reconnecting: if not self.detached and not self.reconnecting:
thread = threading.Thread(target=self.reconnect_port) thread = threading.Thread(target=self.reconnect_port)
@ -273,7 +273,7 @@ class RNodeInterface(Interface):
def open_port(self): def open_port(self):
if not self.use_ble: 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( self.serial = self.pyserial.Serial(
port = self.port, port = self.port,
baudrate = self.speed, baudrate = self.speed,
@ -335,22 +335,22 @@ class RNodeInterface(Interface):
RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR) RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR)
if not self.detected: 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() self.serial.close()
else: else:
if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52: if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52:
self.display = True 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) RNS.log("Configuring RNode interface...", RNS.LOG_VERBOSE)
self.initRadio() self.initRadio()
if (self.validateRadioState()): if (self.validateRadioState()):
self.interface_ready = True 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) sleep(0.3)
self.online = True self.online = True
else: 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("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR)
RNS.log("Aborting RNode startup", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
self.serial.close() self.serial.close()
@ -373,27 +373,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]) 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) written = self.serial.write(kiss_command)
if written != len(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): def leave(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def enable_external_framebuffer(self):
if self.display != None: if self.display != None:
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def disable_external_framebuffer(self):
if self.display != None: if self.display != None:
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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_PIXEL_WIDTH = 64
FB_BITS_PER_PIXEL = 1 FB_BITS_PER_PIXEL = 1
@ -417,13 +417,13 @@ class RNodeInterface(Interface):
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def hard_reset(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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); sleep(2.25);
def setFrequency(self): def setFrequency(self):
@ -436,7 +436,7 @@ class RNodeInterface(Interface):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FREQUENCY])+data+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setBandwidth(self):
c1 = self.bandwidth >> 24 c1 = self.bandwidth >> 24
@ -448,28 +448,28 @@ class RNodeInterface(Interface):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_BANDWIDTH])+data+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setTXPower(self):
txp = bytes([self.txpower]) txp = bytes([self.txpower])
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_TXPOWER])+txp+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setSpreadingFactor(self):
sf = bytes([self.sf]) sf = bytes([self.sf])
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_SF])+sf+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setCodingRate(self):
cr = bytes([self.cr]) cr = bytes([self.cr])
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_CR])+cr+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setSTALock(self):
if self.st_alock != None: if self.st_alock != None:
@ -481,7 +481,7 @@ class RNodeInterface(Interface):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setLTALock(self):
if self.lt_alock != None: if self.lt_alock != None:
@ -493,14 +493,14 @@ class RNodeInterface(Interface):
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def setRadioState(self, state):
self.state = state self.state = state
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def validate_firmware(self):
if (self.maj_version > RNodeInterface.REQUIRED_FW_VER_MAJ): if (self.maj_version > RNodeInterface.REQUIRED_FW_VER_MAJ):
@ -513,14 +513,14 @@ class RNodeInterface(Interface):
if self.firmware_ok: if self.firmware_ok:
return return
RNS.log("The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version), 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("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"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.log("Please update your RNode firmware with rnodeconf from https://github.com/markqvist/rnodeconfigutil/")
RNS.panic() RNS.panic()
def validateRadioState(self): 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 self.use_ble: if self.use_ble:
sleep(1.00) sleep(1.00)
else: else:
@ -557,7 +557,7 @@ class RNodeInterface(Interface):
try: try:
self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 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) 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: except:
self.bitrate = 0 self.bitrate = 0
@ -588,7 +588,7 @@ class RNodeInterface(Interface):
self.txb += datalen self.txb += datalen
if written != len(frame): 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: else:
self.queue(data) self.queue(data)
@ -654,7 +654,7 @@ class RNodeInterface(Interface):
command_buffer = command_buffer+bytes([byte]) command_buffer = command_buffer+bytes([byte])
if (len(command_buffer) == 4): if (len(command_buffer) == 4):
self.r_frequency = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] 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() self.updateBitrate()
elif (command == KISS.CMD_BANDWIDTH): elif (command == KISS.CMD_BANDWIDTH):
@ -670,26 +670,26 @@ class RNodeInterface(Interface):
command_buffer = command_buffer+bytes([byte]) command_buffer = command_buffer+bytes([byte])
if (len(command_buffer) == 4): if (len(command_buffer) == 4):
self.r_bandwidth = command_buffer[0] << 24 | command_buffer[1] << 16 | command_buffer[2] << 8 | command_buffer[3] 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() self.updateBitrate()
elif (command == KISS.CMD_TXPOWER): elif (command == KISS.CMD_TXPOWER):
self.r_txpower = byte 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): elif (command == KISS.CMD_SF):
self.r_sf = byte 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() self.updateBitrate()
elif (command == KISS.CMD_CR): elif (command == KISS.CMD_CR):
self.r_cr = byte 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() self.updateBitrate()
elif (command == KISS.CMD_RADIO_STATE): elif (command == KISS.CMD_RADIO_STATE):
self.r_state = byte self.r_state = byte
if self.r_state: if self.r_state:
pass pass
else: 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): elif (command == KISS.CMD_RADIO_LOCK):
self.r_lock = byte self.r_lock = byte
@ -767,7 +767,7 @@ class RNodeInterface(Interface):
if (len(command_buffer) == 2): if (len(command_buffer) == 2):
at = command_buffer[0] << 8 | command_buffer[1] at = command_buffer[0] << 8 | command_buffer[1]
self.r_st_alock = at/100.0 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): elif (command == KISS.CMD_LT_ALOCK):
if (byte == KISS.FESC): if (byte == KISS.FESC):
escape = True escape = True
@ -782,7 +782,7 @@ class RNodeInterface(Interface):
if (len(command_buffer) == 2): if (len(command_buffer) == 2):
at = command_buffer[0] << 8 | command_buffer[1] at = command_buffer[0] << 8 | command_buffer[1]
self.r_lt_alock = at/100.0 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): elif (command == KISS.CMD_STAT_CHTM):
if (byte == KISS.FESC): if (byte == KISS.FESC):
escape = True escape = True
@ -828,9 +828,9 @@ class RNodeInterface(Interface):
self.r_preamble_symbols = prs self.r_preamble_symbols = prs
self.r_premable_time_ms = prt self.r_premable_time_ms = prt
self.r_csma_slot_time_ms = cst 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(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(str(self)+" Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", 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(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 CSMA slot time is {self.r_csma_slot_time_ms}ms", RNS.LOG_DEBUG)
elif (command == KISS.CMD_STAT_BAT): elif (command == KISS.CMD_STAT_BAT):
if (byte == KISS.FESC): if (byte == KISS.FESC):
escape = True escape = True
@ -858,26 +858,26 @@ class RNodeInterface(Interface):
self.mcu = byte self.mcu = byte
elif (command == KISS.CMD_ERROR): elif (command == KISS.CMD_ERROR):
if (byte == KISS.ERROR_INITRADIO): if (byte == KISS.ERROR_INITRADIO):
RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) RNS.log(f"{self} hardware initialisation error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR)
raise IOError("Radio initialisation failure") raise OSError("Radio initialisation failure")
elif (byte == KISS.ERROR_TXFAILED): elif (byte == KISS.ERROR_TXFAILED):
RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) RNS.log(f"{self} hardware TX error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR)
raise IOError("Hardware transmit failure") raise OSError("Hardware transmit failure")
elif (byte == KISS.ERROR_MEMORY_LOW): 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"}) self.hw_errors.append({"error": KISS.ERROR_MEMORY_LOW, "description": "Memory exhausted on connected device"})
elif (byte == KISS.ERROR_MODEM_TIMEOUT): 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"}) self.hw_errors.append({"error": KISS.ERROR_MODEM_TIMEOUT, "description": "Modem communication timed out on connected device"})
else: else:
RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR)
raise IOError("Unknown hardware failure") raise OSError("Unknown hardware failure")
elif (command == KISS.CMD_RESET): elif (command == KISS.CMD_RESET):
if (byte == 0xF8): if (byte == 0xF8):
if self.platform == KISS.PLATFORM_ESP32: if self.platform == KISS.PLATFORM_ESP32:
if self.online: if self.online:
RNS.log("Detected reset while device was online, reinitialising device...", RNS.LOG_ERROR) 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): elif (command == KISS.CMD_READY):
self.process_queue() self.process_queue()
elif (command == KISS.CMD_DETECT): elif (command == KISS.CMD_DETECT):
@ -889,7 +889,7 @@ class RNodeInterface(Interface):
else: else:
time_since_last = int(time.time()*1000) - last_read_ms time_since_last = int(time.time()*1000) - last_read_ms
if len(data_buffer) > 0 and time_since_last > self.timeout: 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"" data_buffer = b""
in_frame = False in_frame = False
command = KISS.CMD_UNKNOWN command = KISS.CMD_UNKNOWN
@ -898,15 +898,15 @@ class RNodeInterface(Interface):
if self.id_interval != None and self.id_callsign != None: if self.id_interval != None and self.id_callsign != None:
if self.first_tx != None: if self.first_tx != None:
if time.time() > self.first_tx + self.id_interval: 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) self.processOutgoing(self.id_callsign)
sleep(0.08) sleep(0.08)
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -927,16 +927,16 @@ class RNodeInterface(Interface):
while not self.online and not self.detached: while not self.online and not self.detached:
try: try:
time.sleep(5) 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() self.open_port()
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
except Exception as e: 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 self.reconnecting = False
if self.online: if self.online:
RNS.log("Reconnected serial port for "+str(self)) RNS.log(f"Reconnected serial port for {self}")
def detach(self): def detach(self):
self.detached = True self.detached = True
@ -980,7 +980,7 @@ class RNodeInterface(Interface):
return data return data
def __str__(self): def __str__(self):
return "RNodeInterface["+str(self.name)+"]" return f"RNodeInterface[{self.name}]"
class BLEConnection(): class BLEConnection():
UART_SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" UART_SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"

View File

@ -241,14 +241,14 @@ class RNodeMultiInterface(Interface):
self.id_callsign = id_callsign.encode("utf-8") self.id_callsign = id_callsign.encode("utf-8")
self.id_interval = id_interval self.id_interval = id_interval
else: 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 self.validcfg = False
else: else:
self.id_interval = None self.id_interval = None
self.id_callsign = None self.id_callsign = None
if (not self.validcfg): 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): def start(self):
try: try:
@ -257,11 +257,11 @@ class RNodeMultiInterface(Interface):
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
else: else:
raise IOError("Could not open serial port") raise OSError("Could not open serial port")
except Exception as e: 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)
RNS.log("The contained exception was: "+str(e), 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) RNS.log("Reticulum will attempt to bring up this interface periodically", RNS.LOG_ERROR)
if not self.detached and not self.reconnecting: if not self.detached and not self.reconnecting:
thread = threading.Thread(target=self.reconnect_port) thread = threading.Thread(target=self.reconnect_port)
@ -269,7 +269,7 @@ class RNodeMultiInterface(Interface):
thread.start() thread.start()
def open_port(self): def open_port(self):
RNS.log("Opening serial port "+self.port+"...") RNS.log(f"Opening serial port {self.port}...")
self.serial = self.pyserial.Serial( self.serial = self.pyserial.Serial(
port = self.port, port = self.port,
baudrate = self.speed, baudrate = self.speed,
@ -296,13 +296,13 @@ class RNodeMultiInterface(Interface):
sleep(0.2) sleep(0.2)
if not self.detected: 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() self.serial.close()
else: else:
if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52: if self.platform == KISS.PLATFORM_ESP32 or self.platform == KISS.PLATFORM_NRF52:
self.display = True 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) RNS.log("Creating subinterfaces...", RNS.LOG_VERBOSE)
for subint in self.subint_config: for subint in self.subint_config:
subint_vport = int(subint[1]) subint_vport = int(subint[1])
@ -333,38 +333,38 @@ class RNodeMultiInterface(Interface):
interface.HW_MTU = self.HW_MTU interface.HW_MTU = self.HW_MTU
interface.detected = True interface.detected = True
RNS.Transport.interfaces.append(interface) 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 self.clients += 1
else: 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 self.online = True
def detect(self): 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]) 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) written = self.serial.write(kiss_command)
if written != len(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): def leave(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def enable_external_framebuffer(self):
if self.display != None: if self.display != None:
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def disable_external_framebuffer(self):
if self.display != None: if self.display != None:
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x00, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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_PIXEL_WIDTH = 64
FB_BITS_PER_PIXEL = 1 FB_BITS_PER_PIXEL = 1
@ -388,13 +388,13 @@ class RNodeMultiInterface(Interface):
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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): def hard_reset(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_RESET, 0xf8, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(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); sleep(2.25);
def setFrequency(self, frequency, interface): 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]) 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) written = self.serial.write(kiss_command)
if written != len(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 self.selected_index = interface.index
def setBandwidth(self, bandwidth, interface): 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]) 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) written = self.serial.write(kiss_command)
if written != len(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 self.selected_index = interface.index
def setTXPower(self, txpower, interface): 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]) 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) written = self.serial.write(kiss_command)
if written != len(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 self.selected_index = interface.index
def setSpreadingFactor(self, sf, interface): 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]) 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) written = self.serial.write(kiss_command)
if written != len(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 self.selected_index = interface.index
def setCodingRate(self, cr, interface): 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]) 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) written = self.serial.write(kiss_command)
if written != len(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 self.selected_index = interface.index
def setSTALock(self, st_alock, interface): 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]) 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) written = self.serial.write(kiss_command)
if written != len(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 self.selected_index = interface.index
def setLTALock(self, lt_alock, interface): 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]) 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) written = self.serial.write(kiss_command)
if written != len(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 self.selected_index = interface.index
def setRadioState(self, state, interface): 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]) 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) written = self.serial.write(kiss_command)
if written != len(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 self.selected_index = interface.index
def validate_firmware(self): def validate_firmware(self):
@ -489,8 +489,8 @@ class RNodeMultiInterface(Interface):
if self.firmware_ok: if self.firmware_ok:
return return
RNS.log("The firmware version of the connected RNode is "+str(self.maj_version)+"."+str(self.min_version), 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("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"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.log("Please update your RNode firmware with rnodeconf from https://github.com/markqvist/Reticulum/RNS/Utilities/rnodeconf.py")
RNS.panic() RNS.panic()
@ -506,7 +506,7 @@ class RNodeMultiInterface(Interface):
self.txb += len(data) self.txb += len(data)
if written != len(frame): 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): def received_announce(self, from_spawned=False):
if from_spawned: self.ia_freq_deque.append(time.time()) if from_spawned: self.ia_freq_deque.append(time.time())
@ -589,7 +589,7 @@ class RNodeMultiInterface(Interface):
command_buffer = command_buffer+bytes([byte]) command_buffer = command_buffer+bytes([byte])
if (len(command_buffer) == 4): 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] 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() self.subinterfaces[self.selected_index].updateBitrate()
elif (command == KISS.CMD_BANDWIDTH): elif (command == KISS.CMD_BANDWIDTH):
@ -605,20 +605,20 @@ class RNodeMultiInterface(Interface):
command_buffer = command_buffer+bytes([byte]) command_buffer = command_buffer+bytes([byte])
if (len(command_buffer) == 4): 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] 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() self.subinterfaces[self.selected_index].updateBitrate()
elif (command == KISS.CMD_TXPOWER): elif (command == KISS.CMD_TXPOWER):
txp = byte - 256 if byte > 127 else byte txp = byte - 256 if byte > 127 else byte
self.subinterfaces[self.selected_index].r_txpower = txp 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): elif (command == KISS.CMD_SF):
self.subinterfaces[self.selected_index].r_sf = byte 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() self.subinterfaces[self.selected_index].updateBitrate()
elif (command == KISS.CMD_CR): elif (command == KISS.CMD_CR):
self.subinterfaces[self.selected_index].r_cr = byte 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() self.subinterfaces[self.selected_index].updateBitrate()
elif (command == KISS.CMD_RADIO_STATE): elif (command == KISS.CMD_RADIO_STATE):
self.subinterfaces[self.selected_index].r_state = byte self.subinterfaces[self.selected_index].r_state = byte
@ -626,7 +626,7 @@ class RNodeMultiInterface(Interface):
pass pass
#RNS.log(str(self)+" Radio reporting state is online", RNS.LOG_DEBUG) #RNS.log(str(self)+" Radio reporting state is online", RNS.LOG_DEBUG)
else: 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): elif (command == KISS.CMD_RADIO_LOCK):
self.subinterfaces[self.selected_index].r_lock = byte self.subinterfaces[self.selected_index].r_lock = byte
@ -705,7 +705,7 @@ class RNodeMultiInterface(Interface):
if (len(command_buffer) == 2): if (len(command_buffer) == 2):
at = command_buffer[0] << 8 | command_buffer[1] at = command_buffer[0] << 8 | command_buffer[1]
self.subinterfaces[self.selected_index].r_st_alock = at/100.0 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): elif (command == KISS.CMD_LT_ALOCK):
if (byte == KISS.FESC): if (byte == KISS.FESC):
escape = True escape = True
@ -720,7 +720,7 @@ class RNodeMultiInterface(Interface):
if (len(command_buffer) == 2): if (len(command_buffer) == 2):
at = command_buffer[0] << 8 | command_buffer[1] at = command_buffer[0] << 8 | command_buffer[1]
self.subinterfaces[self.selected_index].r_lt_alock = at/100.0 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): elif (command == KISS.CMD_STAT_CHTM):
if (byte == KISS.FESC): if (byte == KISS.FESC):
escape = True escape = True
@ -766,9 +766,9 @@ class RNodeMultiInterface(Interface):
self.subinterfaces[self.selected_index].r_preamble_symbols = prs 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_premable_time_ms = prt
self.subinterfaces[self.selected_index].r_csma_slot_time_ms = cst 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(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(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(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(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 CSMA slot time is {self.subinterfaces[self.selected_index].r_csma_slot_time_ms}ms", RNS.LOG_DEBUG)
elif (command == KISS.CMD_RANDOM): elif (command == KISS.CMD_RANDOM):
self.r_random = byte self.r_random = byte
elif (command == KISS.CMD_PLATFORM): elif (command == KISS.CMD_PLATFORM):
@ -777,20 +777,20 @@ class RNodeMultiInterface(Interface):
self.mcu = byte self.mcu = byte
elif (command == KISS.CMD_ERROR): elif (command == KISS.CMD_ERROR):
if (byte == KISS.ERROR_INITRADIO): if (byte == KISS.ERROR_INITRADIO):
RNS.log(str(self)+" hardware initialisation error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) RNS.log(f"{self} hardware initialisation error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR)
raise IOError("Radio initialisation failure") raise OSError("Radio initialisation failure")
elif (byte == KISS.ERROR_TXFAILED): elif (byte == KISS.ERROR_TXFAILED):
RNS.log(str(self)+" hardware TX error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) RNS.log(f"{self} hardware TX error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR)
raise IOError("Hardware transmit failure") raise OSError("Hardware transmit failure")
else: else:
RNS.log(str(self)+" hardware error (code "+RNS.hexrep(byte)+")", RNS.LOG_ERROR) RNS.log(f"{self} hardware error (code {RNS.hexrep(byte)})", RNS.LOG_ERROR)
raise IOError("Unknown hardware failure") raise OSError("Unknown hardware failure")
elif (command == KISS.CMD_RESET): elif (command == KISS.CMD_RESET):
if (byte == 0xF8): if (byte == 0xF8):
if self.platform == KISS.PLATFORM_ESP32: if self.platform == KISS.PLATFORM_ESP32:
if self.online: if self.online:
RNS.log("Detected reset while device was online, reinitialising device...", RNS.LOG_ERROR) 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): elif (command == KISS.CMD_READY):
self.process_queue() self.process_queue()
elif (command == KISS.CMD_DETECT): elif (command == KISS.CMD_DETECT):
@ -808,7 +808,7 @@ class RNodeMultiInterface(Interface):
else: else:
time_since_last = int(time.time()*1000) - last_read_ms time_since_last = int(time.time()*1000) - last_read_ms
if len(data_buffer) > 0 and time_since_last > self.timeout: 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"" data_buffer = b""
in_frame = False in_frame = False
command = KISS.CMD_UNKNOWN command = KISS.CMD_UNKNOWN
@ -824,14 +824,14 @@ class RNodeMultiInterface(Interface):
self.subinterfaces[interface.index].processOutgoing(self.id_callsign) self.subinterfaces[interface.index].processOutgoing(self.id_callsign)
if interface_available: 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) sleep(0.08)
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -854,16 +854,16 @@ class RNodeMultiInterface(Interface):
while not self.online and not self.detached: while not self.online and not self.detached:
try: try:
time.sleep(5) 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() self.open_port()
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
except Exception as e: 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 self.reconnecting = False
if self.online: if self.online:
RNS.log("Reconnected serial port for "+str(self)) RNS.log(f"Reconnected serial port for {self}")
def detach(self): def detach(self):
self.detached = True self.detached = True
@ -890,7 +890,7 @@ class RNodeMultiInterface(Interface):
interface.process_queue() interface.process_queue()
def __str__(self): def __str__(self):
return "RNodeMultiInterface["+str(self.name)+"]" return f"RNodeMultiInterface[{self.name}]"
class RNodeSubInterface(Interface): class RNodeSubInterface(Interface):
LOW_FREQ_MIN = 137000000 LOW_FREQ_MIN = 137000000
@ -1019,42 +1019,42 @@ class RNodeSubInterface(Interface):
self.validcfg = True self.validcfg = True
if (self.interface_type == "SX126X" or self.interface_type == "SX127X"): if (self.interface_type == "SX126X" or self.interface_type == "SX127X"):
if (self.frequency < RNodeSubInterface.LOW_FREQ_MIN or self.frequency > RNodeSubInterface.LOW_FREQ_MAX): 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 self.validcfg = False
elif (self.interface_type == "SX128X"): elif (self.interface_type == "SX128X"):
if (self.frequency < RNodeSubInterface.HIGH_FREQ_MIN or self.frequency > RNodeSubInterface.HIGH_FREQ_MAX): 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 self.validcfg = False
else: 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 self.validcfg = False
if (self.txpower < -9 or self.txpower > 27): 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 self.validcfg = False
if (self.bandwidth < 7800 or self.bandwidth > 1625000): 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 self.validcfg = False
if (self.sf < 5 or self.sf > 12): 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 self.validcfg = False
if (self.cr < 5 or self.cr > 8): 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 self.validcfg = False
if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)): 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 self.validcfg = False
if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)): 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 self.validcfg = False
if (not self.validcfg): 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() self.configure_device()
@ -1068,15 +1068,15 @@ class RNodeSubInterface(Interface):
self.r_lock = None self.r_lock = None
sleep(2.0) 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() self.initRadio()
if (self.validateRadioState()): if (self.validateRadioState()):
self.interface_ready = True 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) sleep(0.3)
self.online = True self.online = True
else: 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("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR)
RNS.log("Aborting RNode startup", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
@ -1093,7 +1093,7 @@ class RNodeSubInterface(Interface):
self.state = KISS.RADIO_STATE_ON self.state = KISS.RADIO_STATE_ON
def validateRadioState(self): 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); sleep(0.25);
self.validcfg = True self.validcfg = True
@ -1123,7 +1123,7 @@ class RNodeSubInterface(Interface):
try: try:
self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000 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) 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: except:
self.bitrate = 0 self.bitrate = 0
@ -1162,4 +1162,4 @@ class RNodeSubInterface(Interface):
self.interface_ready = True self.interface_ready = True
def __str__(self): def __str__(self):
return self.parent_interface.name+"["+self.name+"]" return f"{self.parent_interface.name}[{self.name}]"

View File

@ -86,17 +86,17 @@ class SerialInterface(Interface):
try: try:
self.open_port() self.open_port()
except Exception as e: 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 raise e
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
else: else:
raise IOError("Could not open serial port") raise OSError("Could not open serial port")
def open_port(self): 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( self.serial = self.pyserial.Serial(
port = self.port, port = self.port,
baudrate = self.speed, baudrate = self.speed,
@ -118,7 +118,7 @@ class SerialInterface(Interface):
thread.daemon = True thread.daemon = True
thread.start() thread.start()
self.online = True 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): def processIncoming(self, data):
@ -132,7 +132,7 @@ class SerialInterface(Interface):
written = self.serial.write(data) written = self.serial.write(data)
self.txb += len(data) self.txb += len(data)
if written != 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): def readLoop(self):
@ -175,8 +175,8 @@ class SerialInterface(Interface):
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is now offline.", 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
@ -191,17 +191,17 @@ class SerialInterface(Interface):
while not self.online: while not self.online:
try: try:
time.sleep(5) 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() self.open_port()
if self.serial.is_open: if self.serial.is_open:
self.configure_device() self.configure_device()
except Exception as e: 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): def should_ingress_limit(self):
return False return False
def __str__(self): def __str__(self):
return "SerialInterface["+self.name+"]" return f"SerialInterface[{self.name}]"

View File

@ -180,25 +180,25 @@ class TCPClientInterface(Interface):
if self.socket != None: if self.socket != None:
if hasattr(self.socket, "close"): if hasattr(self.socket, "close"):
if callable(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 self.detached = True
try: try:
self.socket.shutdown(socket.SHUT_RDWR) self.socket.shutdown(socket.SHUT_RDWR)
except Exception as e: 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: try:
self.socket.close() self.socket.close()
except Exception as e: 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 self.socket = None
def connect(self, initial=False): def connect(self, initial=False):
try: try:
if initial: 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 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.settimeout(TCPClientInterface.INITIAL_CONNECT_TIMEOUT) self.socket.settimeout(TCPClientInterface.INITIAL_CONNECT_TIMEOUT)
@ -208,12 +208,12 @@ class TCPClientInterface(Interface):
self.online = True self.online = True
if initial: 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: except Exception as e:
if initial: if initial:
RNS.log("Initial connection for "+str(self)+" could not be established: "+str(e), RNS.LOG_ERROR) RNS.log(f"Initial connection for {self} could not be established: {e}", RNS.LOG_ERROR)
RNS.log("Leaving unconnected and retrying connection in "+str(TCPClientInterface.RECONNECT_WAIT)+" seconds.", RNS.LOG_ERROR) RNS.log(f"Leaving unconnected and retrying connection in {TCPClientInterface.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR)
return False return False
else: else:
@ -241,7 +241,7 @@ class TCPClientInterface(Interface):
attempts += 1 attempts += 1
if self.max_reconnect_tries != None and attempts > self.max_reconnect_tries: 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() self.teardown()
break break
@ -249,10 +249,10 @@ class TCPClientInterface(Interface):
self.connect() self.connect()
except Exception as e: 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: 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 self.reconnecting = False
thread = threading.Thread(target=self.read_loop) thread = threading.Thread(target=self.read_loop)
@ -263,7 +263,7 @@ class TCPClientInterface(Interface):
else: else:
RNS.log("Attempt to reconnect on a non-initiator TCP interface. This should not happen.", RNS.LOG_ERROR) 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): def processIncoming(self, data):
self.rxb += len(data) self.rxb += len(data)
@ -292,8 +292,8 @@ class TCPClientInterface(Interface):
self.parent_interface.txb += len(data) self.parent_interface.txb += len(data)
except Exception as e: except Exception as e:
RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) RNS.log(f"Exception occurred while transmitting via {self}, tearing down interface", 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.teardown() self.teardown()
@ -361,10 +361,10 @@ class TCPClientInterface(Interface):
else: else:
self.online = False self.online = False
if self.initiator and not self.detached: 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() self.reconnect()
else: 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() self.teardown()
break break
@ -372,7 +372,7 @@ class TCPClientInterface(Interface):
except Exception as e: except Exception as e:
self.online = False 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: if self.initiator:
RNS.log("Attempting to reconnect...", RNS.LOG_WARNING) RNS.log("Attempting to reconnect...", RNS.LOG_WARNING)
@ -382,12 +382,12 @@ class TCPClientInterface(Interface):
def teardown(self): def teardown(self):
if self.initiator and not self.detached: 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: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()
else: 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.online = False
self.OUT = False self.OUT = False
@ -402,7 +402,7 @@ class TCPClientInterface(Interface):
def __str__(self): 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): class TCPServerInterface(Interface):
@ -466,7 +466,7 @@ class TCPServerInterface(Interface):
def incoming_connection(self, handler): def incoming_connection(self, handler):
RNS.log("Accepting incoming TCP connection", RNS.LOG_VERBOSE) 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 = 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.OUT = self.OUT
spawned_interface.IN = self.IN spawned_interface.IN = self.IN
@ -501,7 +501,7 @@ class TCPServerInterface(Interface):
spawned_interface.mode = self.mode spawned_interface.mode = self.mode
spawned_interface.HW_MTU = self.HW_MTU spawned_interface.HW_MTU = self.HW_MTU
spawned_interface.online = True 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) RNS.Transport.interfaces.append(spawned_interface)
self.clients += 1 self.clients += 1
spawned_interface.read_loop() spawned_interface.read_loop()
@ -521,17 +521,17 @@ class TCPServerInterface(Interface):
if hasattr(self.server, "shutdown"): if hasattr(self.server, "shutdown"):
if callable(self.server.shutdown): if callable(self.server.shutdown):
try: try:
RNS.log("Detaching "+str(self), RNS.LOG_DEBUG) RNS.log(f"Detaching {self}", RNS.LOG_DEBUG)
self.server.shutdown() self.server.shutdown()
self.detached = True self.detached = True
self.server = None self.server = None
except Exception as e: 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): 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): class TCPInterfaceHandler(socketserver.BaseRequestHandler):

View File

@ -101,11 +101,11 @@ class UDPInterface(Interface):
self.txb += len(data) self.txb += len(data)
except Exception as e: 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): 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): class UDPInterfaceHandler(socketserver.BaseRequestHandler):
def __init__(self, callback, *args, **keys): def __init__(self, callback, *args, **keys):

View File

@ -24,5 +24,5 @@ import os
import glob import glob
import RNS.Interfaces.Android 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')] __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]

View File

@ -115,8 +115,8 @@ class Link:
link.destination = packet.destination link.destination = packet.destination
link.establishment_timeout = Link.ESTABLISHMENT_TIMEOUT_PER_HOP * max(1, packet.hops) + Link.KEEPALIVE link.establishment_timeout = Link.ESTABLISHMENT_TIMEOUT_PER_HOP * max(1, packet.hops) + Link.KEEPALIVE
link.establishment_cost += len(packet.raw) link.establishment_cost += len(packet.raw)
RNS.log("Validating link request "+RNS.prettyhexrep(link.link_id), RNS.LOG_VERBOSE) 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) 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.handshake()
link.attached_interface = packet.receiving_interface link.attached_interface = packet.receiving_interface
link.prove() link.prove()
@ -125,12 +125,12 @@ class Link:
link.last_inbound = time.time() link.last_inbound = time.time()
link.start_watchdog() 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 return link
except Exception as e: except Exception as e:
RNS.log("Validating link request failed", RNS.LOG_VERBOSE) RNS.log("Validating link request failed", RNS.LOG_VERBOSE)
RNS.log("exc: "+str(e)) RNS.log(f"exc: {e}")
return None return None
else: else:
@ -219,8 +219,8 @@ class Link:
self.start_watchdog() self.start_watchdog()
self.packet.send() self.packet.send()
self.had_outbound() self.had_outbound()
RNS.log("Link request "+RNS.prettyhexrep(self.link_id)+" sent to "+str(self.destination), RNS.LOG_DEBUG) 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) 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): def load_peer(self, peer_pub_bytes, peer_sig_pub_bytes):
@ -249,7 +249,7 @@ class Link:
context=self.get_context(), context=self.get_context(),
) )
else: 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): def prove(self):
@ -291,7 +291,7 @@ class Link:
if self.destination.identity.validate(signature, signed_data): if self.destination.identity.validate(signature, signed_data):
if self.status != Link.HANDSHAKE: 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.rtt = time.time() - self.request_time
self.attached_interface = packet.receiving_interface self.attached_interface = packet.receiving_interface
@ -300,7 +300,7 @@ class Link:
self.activated_at = time.time() self.activated_at = time.time()
self.last_proof = self.activated_at self.last_proof = self.activated_at
RNS.Transport.activate_link(self) 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: 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 self.establishment_rate = self.establishment_cost/self.rtt
@ -315,12 +315,12 @@ class Link:
thread.daemon = True thread.daemon = True
thread.start() thread.start()
else: 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: except Exception as e:
self.status = Link.CLOSED self.status = Link.CLOSED
RNS.log("An error ocurred while validating link request proof on "+str(self)+".", RNS.LOG_ERROR) RNS.log(f"An error ocurred while validating link request proof on {self}.", 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)
def identify(self, identity): def identify(self, identity):
@ -380,7 +380,7 @@ class Link:
else: else:
request_id = RNS.Identity.truncated_hash(packed_request) 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) request_resource = RNS.Resource(packed_request, self, request_id = request_id, is_response = False, timeout = timeout)
return RequestReceipt( return RequestReceipt(
@ -411,10 +411,10 @@ class Link:
if self.owner.callbacks.link_established != None: if self.owner.callbacks.link_established != None:
self.owner.callbacks.link_established(self) self.owner.callbacks.link_established(self)
except Exception as e: 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: 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() self.teardown()
def track_phy_stats(self, track): def track_phy_stats(self, track):
@ -563,7 +563,7 @@ class Link:
try: try:
self.callbacks.link_closed(self) self.callbacks.link_closed(self)
except Exception as e: 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): def start_watchdog(self):
@ -634,7 +634,7 @@ class Link:
if sleep_time == 0: if sleep_time == 0:
RNS.log("Warning! Link watchdog sleep time of 0!", RNS.LOG_ERROR) RNS.log("Warning! Link watchdog sleep time of 0!", RNS.LOG_ERROR)
if sleep_time == None or sleep_time < 0: 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() self.teardown()
sleep_time = 0.1 sleep_time = 0.1
@ -683,7 +683,7 @@ class Link:
allowed = True allowed = True
if allowed: 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: if len(inspect.signature(response_generator).parameters) == 5:
response = response_generator(path, request_data, request_id, self.__remote_identity, requested_at) response = response_generator(path, request_data, request_id, self.__remote_identity, requested_at)
elif len(inspect.signature(response_generator).parameters) == 6: 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) response_resource = RNS.Resource(packed_response, self, request_id = request_id, is_response = True)
else: else:
identity_string = str(self.get_remote_identity()) if self.get_remote_identity() != None else "<Unknown>" identity_string = str(self.get_remote_identity()) if self.get_remote_identity() != None else "<Unknown>"
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): def handle_response(self, request_id, response_data, response_size, response_transfer_size):
if self.status == Link.ACTIVE: if self.status == Link.ACTIVE:
@ -715,7 +715,7 @@ class Link:
pending_request.response_transfer_size += response_transfer_size pending_request.response_transfer_size += response_transfer_size
pending_request.response_received(response_data) pending_request.response_received(response_data)
except Exception as e: 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 break
@ -732,7 +732,7 @@ class Link:
self.handle_request(request_id, request_data) self.handle_request(request_id, request_data)
else: 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): def response_resource_concluded(self, resource):
if resource.status == RNS.Resource.COMPLETE: if resource.status == RNS.Resource.COMPLETE:
@ -743,7 +743,7 @@ class Link:
self.handle_response(request_id, response_data, resource.total_size, resource.size) self.handle_response(request_id, response_data, resource.total_size, resource.size)
else: 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: for pending_request in self.pending_requests:
if pending_request.request_id == resource.request_id: if pending_request.request_id == resource.request_id:
pending_request.request_timed_out(None) pending_request.request_timed_out(None)
@ -794,7 +794,7 @@ class Link:
packet.prove() packet.prove()
should_query = True should_query = True
except Exception as e: 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) self.__update_phy_stats(packet, query_shared=should_query)
@ -814,7 +814,7 @@ class Link:
try: try:
self.callbacks.remote_identified(self, self.__remote_identity) self.callbacks.remote_identified(self, self.__remote_identity)
except Exception as e: 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) self.__update_phy_stats(packet, query_shared=True)
@ -827,7 +827,7 @@ class Link:
self.handle_request(request_id, unpacked_request) self.handle_request(request_id, unpacked_request)
self.__update_phy_stats(packet, query_shared=True) self.__update_phy_stats(packet, query_shared=True)
except Exception as e: 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: elif packet.context == RNS.Packet.RESPONSE:
try: try:
@ -840,7 +840,7 @@ class Link:
self.handle_response(request_id, response_data, transfer_size, transfer_size) self.handle_response(request_id, response_data, transfer_size, transfer_size)
self.__update_phy_stats(packet, query_shared=True) self.__update_phy_stats(packet, query_shared=True)
except Exception as e: 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: elif packet.context == RNS.Packet.LRRTT:
if not self.initiator: if not self.initiator:
@ -883,7 +883,7 @@ class Link:
if self.callbacks.resource(resource_advertisement): if self.callbacks.resource(resource_advertisement):
RNS.Resource.accept(packet, self.callbacks.resource_concluded) RNS.Resource.accept(packet, self.callbacks.resource_concluded)
except Exception as e: 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: elif self.resource_strategy == Link.ACCEPT_ALL:
RNS.Resource.accept(packet, self.callbacks.resource_concluded) RNS.Resource.accept(packet, self.callbacks.resource_concluded)
@ -970,13 +970,13 @@ class Link:
try: try:
self.fernet = Fernet(self.derived_key) self.fernet = Fernet(self.derived_key)
except Exception as e: 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 raise e
return self.fernet.encrypt(plaintext) return self.fernet.encrypt(plaintext)
except Exception as e: 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 raise e
@ -988,7 +988,7 @@ class Link:
return self.fernet.decrypt(ciphertext) return self.fernet.decrypt(ciphertext)
except Exception as e: 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 return None
@ -1169,7 +1169,7 @@ class RequestReceipt():
def request_resource_concluded(self, resource): def request_resource_concluded(self, resource):
if resource.status == RNS.Resource.COMPLETE: 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: if self.started_at == None:
self.started_at = time.time() self.started_at = time.time()
self.status = RequestReceipt.DELIVERED self.status = RequestReceipt.DELIVERED
@ -1178,7 +1178,7 @@ class RequestReceipt():
response_timeout_thread.daemon = True response_timeout_thread.daemon = True
response_timeout_thread.start() response_timeout_thread.start()
else: 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.status = RequestReceipt.FAILED
self.concluded_at = time.time() self.concluded_at = time.time()
self.link.pending_requests.remove(self) self.link.pending_requests.remove(self)
@ -1187,7 +1187,7 @@ class RequestReceipt():
try: try:
self.callbacks.failed(self) self.callbacks.failed(self)
except Exception as e: 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): def __response_timeout_job(self):
@ -1208,7 +1208,7 @@ class RequestReceipt():
try: try:
self.callbacks.failed(self) self.callbacks.failed(self)
except Exception as e: 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): def response_resource_progress(self, resource):
@ -1229,7 +1229,7 @@ class RequestReceipt():
try: try:
self.callbacks.progress(self) self.callbacks.progress(self)
except Exception as e: 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: else:
resource.cancel() resource.cancel()
@ -1252,13 +1252,13 @@ class RequestReceipt():
try: try:
self.callbacks.progress(self) self.callbacks.progress(self)
except Exception as e: 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: if self.callbacks.response != None:
try: try:
self.callbacks.response(self) self.callbacks.response(self)
except Exception as e: 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): def get_request_id(self):
""" """

View File

@ -208,14 +208,14 @@ class Packet:
# Announce packets are not encrypted # Announce packets are not encrypted
self.ciphertext = self.data self.ciphertext = self.data
else: 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.header += bytes([self.context])
self.raw = self.header + self.ciphertext self.raw = self.header + self.ciphertext
if len(self.raw) > self.MTU: 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.packed = True
self.update_hash() self.update_hash()
@ -250,7 +250,7 @@ class Packet:
return True return True
except Exception as e: 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 return False
def send(self): def send(self):
@ -262,7 +262,7 @@ class Packet:
if not self.sent: if not self.sent:
if self.destination.type == RNS.Destination.LINK: if self.destination.type == RNS.Destination.LINK:
if self.destination.status == RNS.Link.CLOSED: 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: else:
self.destination.last_outbound = time.time() self.destination.last_outbound = time.time()
self.destination.tx += 1 self.destination.tx += 1
@ -280,7 +280,7 @@ class Packet:
return False return False
else: else:
raise IOError("Packet was already sent") raise OSError("Packet was already sent")
def resend(self): def resend(self):
""" """
@ -301,7 +301,7 @@ class Packet:
self.receipt = None self.receipt = None
return False return False
else: else:
raise IOError("Packet was not sent yet") raise OSError("Packet was not sent yet")
def prove(self, destination=None): def prove(self, destination=None):
if self.fromPacked and hasattr(self, "destination") and self.destination: if self.fromPacked and hasattr(self, "destination") and self.destination:
@ -419,8 +419,8 @@ class PacketReceipt:
try: try:
self.callbacks.delivery(self) self.callbacks.delivery(self)
except Exception as e: except Exception as e:
RNS.log("An error occurred while evaluating external delivery callback for "+str(link), RNS.LOG_ERROR) RNS.log(f"An error occurred while evaluating external delivery callback for {link}", 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) RNS.trace_exception(e)
return True return True
@ -465,7 +465,7 @@ class PacketReceipt:
try: try:
self.callbacks.delivery(self) self.callbacks.delivery(self)
except Exception as e: 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 return True
else: else:
@ -489,7 +489,7 @@ class PacketReceipt:
try: try:
self.callbacks.delivery(self) self.callbacks.delivery(self)
except Exception as e: 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 return True
else: else:

View File

@ -173,7 +173,7 @@ class Resource:
resource.window_flexibility = Resource.WINDOW_FLEXIBILITY resource.window_flexibility = Resource.WINDOW_FLEXIBILITY
resource.last_activity = time.time() 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.segment_index = adv.i
resource.total_segments = adv.l resource.total_segments = adv.l
if adv.l > 1: if adv.l > 1:
@ -195,7 +195,7 @@ class Resource:
try: try:
resource.link.callbacks.resource_started(resource) resource.link.callbacks.resource_started(resource)
except Exception as e: 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) resource.hashmap_update(0, resource.hashmap_raw)
@ -204,7 +204,7 @@ class Resource:
return resource return resource
else: 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 return None
except Exception as e: except Exception as e:
@ -308,7 +308,7 @@ class Resource:
if (auto_compress and len(self.uncompressed_data) <= Resource.AUTO_COMPRESS_MAX_SIZE): if (auto_compress and len(self.uncompressed_data) <= Resource.AUTO_COMPRESS_MAX_SIZE):
RNS.log("Compressing resource data...", RNS.LOG_DEBUG) RNS.log("Compressing resource data...", RNS.LOG_DEBUG)
self.compressed_data = bz2.compress(self.uncompressed_data) 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: else:
self.compressed_data = self.uncompressed_data self.compressed_data = self.uncompressed_data
@ -317,7 +317,7 @@ class Resource:
if (self.compressed_size < self.uncompressed_size and auto_compress): if (self.compressed_size < self.uncompressed_size and auto_compress):
saved_bytes = len(self.uncompressed_data) - len(self.compressed_data) 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 = b""
self.data += RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE] self.data += RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE]
@ -352,7 +352,7 @@ class Resource:
hashmap_ok = False hashmap_ok = False
while not hashmap_ok: while not hashmap_ok:
hashmap_computation_began = time.time() 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.random_hash = RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE]
self.hash = RNS.Identity.full_hash(data+self.random_hash) self.hash = RNS.Identity.full_hash(data+self.random_hash)
@ -388,7 +388,7 @@ class Resource:
self.hashmap += part.map_hash self.hashmap += part.map_hash
self.parts.append(part) 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: if advertise:
self.advertise() self.advertise()
@ -447,9 +447,9 @@ class Resource:
self.status = Resource.ADVERTISED self.status = Resource.ADVERTISED
self.retries_left = self.max_adv_retries self.retries_left = self.max_adv_retries
self.link.register_outgoing_resource(self) 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: 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() self.cancel()
return return
@ -487,7 +487,7 @@ class Resource:
self.adv_sent = self.last_activity self.adv_sent = self.last_activity
sleep_time = 0.001 sleep_time = 0.001
except Exception as e: 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() self.cancel()
@ -508,7 +508,7 @@ class Resource:
if sleep_time < 0: if sleep_time < 0:
if self.retries_left > 0: if self.retries_left > 0:
ms = "" if self.outstanding_parts == 1 else "s" 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: if self.window > self.window_min:
self.window -= 1 self.window -= 1
if self.window_max > self.window_min: if self.window_max > self.window_min:
@ -595,7 +595,7 @@ class Resource:
except Exception as e: except Exception as e:
RNS.log("Error while assembling received resource.", RNS.LOG_ERROR) 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.status = Resource.CORRUPT
self.link.resource_concluded(self) self.link.resource_concluded(self)
@ -606,7 +606,7 @@ class Resource:
try: try:
self.callback(self) self.callback(self)
except Exception as e: 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: try:
if hasattr(self.data, "close") and callable(self.data.close): if hasattr(self.data, "close") and callable(self.data.close):
@ -618,7 +618,7 @@ class Resource:
RNS.log("Error while cleaning up resource files, the contained exception was:", RNS.LOG_ERROR) RNS.log("Error while cleaning up resource files, the contained exception was:", RNS.LOG_ERROR)
RNS.log(str(e)) RNS.log(str(e))
else: 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): def prove(self):
@ -631,7 +631,7 @@ class Resource:
RNS.Transport.cache(proof_packet, force_cache=True) RNS.Transport.cache(proof_packet, force_cache=True)
except Exception as e: except Exception as e:
RNS.log("Could not send proof packet, cancelling resource", RNS.LOG_DEBUG) 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() self.cancel()
def __prepare_next_segment(self): def __prepare_next_segment(self):
@ -662,7 +662,7 @@ class Resource:
try: try:
self.callback(self) self.callback(self)
except Exception as e: 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: finally:
try: try:
if hasattr(self, "input_file"): if hasattr(self, "input_file"):
@ -670,7 +670,7 @@ class Resource:
self.input_file.close() self.input_file.close()
except Exception as e: 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: else:
# Otherwise we'll recursively create the # Otherwise we'll recursively create the
# next segment of the resource # next segment of the resource
@ -747,7 +747,7 @@ class Resource:
try: try:
self.__progress_callback(self) self.__progress_callback(self)
except Exception as e: 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 i += 1
@ -835,7 +835,7 @@ class Resource:
except Exception as e: except Exception as e:
RNS.log("Could not send resource request packet, cancelling resource", RNS.LOG_DEBUG) 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() self.cancel()
# Called on outgoing resource to make it send more data # Called on outgoing resource to make it send more data
@ -881,7 +881,7 @@ class Resource:
except Exception as e: except Exception as e:
RNS.log("Resource could not send parts, cancelling transfer!", RNS.LOG_DEBUG) 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() self.cancel()
if wants_more_hashmap: if wants_more_hashmap:
@ -920,7 +920,7 @@ class Resource:
self.last_activity = time.time() self.last_activity = time.time()
except Exception as e: except Exception as e:
RNS.log("Could not send resource HMU packet, cancelling resource", RNS.LOG_DEBUG) 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() self.cancel()
if self.sent_parts == len(self.parts): if self.sent_parts == len(self.parts):
@ -931,7 +931,7 @@ class Resource:
try: try:
self.__progress_callback(self) self.__progress_callback(self)
except Exception as e: 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): def cancel(self):
""" """
@ -945,7 +945,7 @@ class Resource:
cancel_packet = RNS.Packet(self.link, self.hash, context=RNS.Packet.RESOURCE_ICL) cancel_packet = RNS.Packet(self.link, self.hash, context=RNS.Packet.RESOURCE_ICL)
cancel_packet.send() cancel_packet.send()
except Exception as e: 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) self.link.cancel_outgoing_resource(self)
else: else:
self.link.cancel_incoming_resource(self) self.link.cancel_incoming_resource(self)
@ -955,7 +955,7 @@ class Resource:
self.link.resource_concluded(self) self.link.resource_concluded(self)
self.callback(self) self.callback(self)
except Exception as e: 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): def set_callback(self, callback):
self.callback = callback self.callback = callback
@ -1068,7 +1068,7 @@ class Resource:
return self.compressed return self.compressed
def __str__(self): 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: class ResourceAdvertisement:

View File

@ -204,20 +204,20 @@ class Reticulum:
else: else:
if os.path.isdir("/etc/reticulum") and os.path.isfile("/etc/reticulum/config"): if os.path.isdir("/etc/reticulum") and os.path.isfile("/etc/reticulum/config"):
Reticulum.configdir = "/etc/reticulum" Reticulum.configdir = "/etc/reticulum"
elif os.path.isdir(Reticulum.userdir+"/.config/reticulum") and os.path.isfile(Reticulum.userdir+"/.config/reticulum/config"): elif os.path.isdir(f"{Reticulum.userdir}/.config/reticulum") and os.path.isfile(f"{Reticulum.userdir}/.config/reticulum/config"):
Reticulum.configdir = Reticulum.userdir+"/.config/reticulum" Reticulum.configdir = f"{Reticulum.userdir}/.config/reticulum"
else: else:
Reticulum.configdir = Reticulum.userdir+"/.reticulum" Reticulum.configdir = f"{Reticulum.userdir}/.reticulum"
if logdest == RNS.LOG_FILE: if logdest == RNS.LOG_FILE:
RNS.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.configpath = f"{Reticulum.configdir}/config"
Reticulum.storagepath = Reticulum.configdir+"/storage" Reticulum.storagepath = f"{Reticulum.configdir}/storage"
Reticulum.cachepath = Reticulum.configdir+"/storage/cache" Reticulum.cachepath = f"{Reticulum.configdir}/storage/cache"
Reticulum.resourcepath = Reticulum.configdir+"/storage/resources" Reticulum.resourcepath = f"{Reticulum.configdir}/storage/resources"
Reticulum.identitypath = Reticulum.configdir+"/storage/identities" Reticulum.identitypath = f"{Reticulum.configdir}/storage/identities"
Reticulum.__transport_enabled = False Reticulum.__transport_enabled = False
Reticulum.__remote_management_enabled = False Reticulum.__remote_management_enabled = False
@ -267,17 +267,17 @@ class Reticulum:
try: try:
self.config = ConfigObj(self.configpath) self.config = ConfigObj(self.configpath)
except Exception as e: 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.log("Check your configuration file for errors!", RNS.LOG_ERROR)
RNS.panic() RNS.panic()
else: else:
RNS.log("Could not load config file, creating default configuration file...") RNS.log("Could not load config file, creating default configuration file...")
self.__create_default_config() 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) time.sleep(1.5)
self.__apply_config() 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() RNS.Identity.load_known_destinations()
@ -332,7 +332,7 @@ class Reticulum:
RNS.Transport.interfaces.append(interface) RNS.Transport.interfaces.append(interface)
self.is_shared_instance = True 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() self.__start_jobs()
except Exception as e: except Exception as e:
@ -354,10 +354,10 @@ class Reticulum:
Reticulum.__transport_enabled = False Reticulum.__transport_enabled = False
Reticulum.__remote_management_enabled = False Reticulum.__remote_management_enabled = False
Reticulum.__allow_probes = 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: except Exception as e:
RNS.log("Local shared instance appears to be running, but it could not be connected", RNS.LOG_ERROR) 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_shared_instance = False
self.is_standalone_instance = True self.is_standalone_instance = True
self.is_connected_to_shared_instance = False self.is_connected_to_shared_instance = False
@ -412,11 +412,11 @@ class Reticulum:
for hexhash in v: for hexhash in v:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(hexhash) != dest_len: 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: try:
allowed_hash = bytes.fromhex(hexhash) allowed_hash = bytes.fromhex(hexhash)
except Exception as e: 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: if not allowed_hash in RNS.Transport.remote_management_allowed:
RNS.Transport.remote_management_allowed.append(allowed_hash) RNS.Transport.remote_management_allowed.append(allowed_hash)
@ -659,7 +659,7 @@ class Reticulum:
interface.OUT = True interface.OUT = True
if interface_mode == Interface.Interface.MODE_ACCESS_POINT: 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.Interface.MODE_FULL
interface.mode = interface_mode interface.mode = interface_mode
@ -696,7 +696,7 @@ class Reticulum:
interface.OUT = True interface.OUT = True
if interface_mode == Interface.Interface.MODE_ACCESS_POINT: 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.Interface.MODE_FULL
interface.mode = interface_mode interface.mode = interface_mode
@ -733,7 +733,7 @@ class Reticulum:
interface.OUT = True interface.OUT = True
if interface_mode == Interface.Interface.MODE_ACCESS_POINT: 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.Interface.MODE_FULL
interface.mode = interface_mode interface.mode = interface_mode
@ -1030,17 +1030,17 @@ class Reticulum:
# if no subinterfaces are defined # if no subinterfaces are defined
if count == 0: if count == 0:
raise ValueError("No subinterfaces configured for "+name) raise ValueError(f"No subinterfaces configured for {name}")
# if no subinterfaces are enabled # if no subinterfaces are enabled
elif enabled_count == 0: 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_interval = int(c["id_interval"]) if "id_interval" in c else None
id_callsign = c["id_callsign"] if "id_callsign" 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 port = c["port"] if "port" in c else None
if port == None: if port == None:
raise ValueError("No port specified for "+name) raise ValueError(f"No port specified for {name}")
interface = RNodeMultiInterface.RNodeMultiInterface( interface = RNodeMultiInterface.RNodeMultiInterface(
RNS.Transport, RNS.Transport,
@ -1107,14 +1107,14 @@ class Reticulum:
interface.start() interface.start()
else: else:
RNS.log("Skipping disabled interface \""+name+"\"", RNS.LOG_DEBUG) RNS.log(f"Skipping disabled interface \"{name}\"", RNS.LOG_DEBUG)
except Exception as e: except Exception as e:
RNS.log("The interface \""+name+"\" could not be created. Check your configuration file for errors!", RNS.LOG_ERROR) RNS.log(f"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 contained exception was: {e}", RNS.LOG_ERROR)
RNS.panic() RNS.panic()
else: 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.panic()
RNS.log("System interfaces are ready", RNS.LOG_VERBOSE) RNS.log("System interfaces are ready", RNS.LOG_VERBOSE)
@ -1182,27 +1182,27 @@ class Reticulum:
for filename in os.listdir(self.resourcepath): for filename in os.listdir(self.resourcepath):
try: try:
if len(filename) == (RNS.Identity.HASHLENGTH//8)*2: if len(filename) == (RNS.Identity.HASHLENGTH//8)*2:
filepath = self.resourcepath + "/" + filename filepath = f"{self.resourcepath}/{filename}"
mtime = os.path.getmtime(filepath) mtime = os.path.getmtime(filepath)
age = now - mtime age = now - mtime
if age > Reticulum.RESOURCE_CACHE: if age > Reticulum.RESOURCE_CACHE:
os.unlink(filepath) os.unlink(filepath)
except Exception as e: 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 # Clean packet caches
for filename in os.listdir(self.cachepath): for filename in os.listdir(self.cachepath):
try: try:
if len(filename) == (RNS.Identity.HASHLENGTH//8)*2: if len(filename) == (RNS.Identity.HASHLENGTH//8)*2:
filepath = self.cachepath + "/" + filename filepath = f"{self.cachepath}/{filename}"
mtime = os.path.getmtime(filepath) mtime = os.path.getmtime(filepath)
age = now - mtime age = now - mtime
if age > RNS.Transport.DESTINATION_TIMEOUT: if age > RNS.Transport.DESTINATION_TIMEOUT:
os.unlink(filepath) os.unlink(filepath)
except Exception as e: 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): def __create_default_config(self):
self.config = ConfigObj(__default_rns_config__) self.config = ConfigObj(__default_rns_config__)
@ -1267,7 +1267,7 @@ class Reticulum:
rpc_connection.close() rpc_connection.close()
except Exception as e: 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): def get_interface_stats(self):
if self.is_connected_to_shared_instance: if self.is_connected_to_shared_instance:
@ -1297,7 +1297,7 @@ class Reticulum:
if hasattr(interface, "b32"): if hasattr(interface, "b32"):
if interface.b32 != None: if interface.b32 != None:
ifstats["i2p_b32"] = interface.b32+".b32.i2p" ifstats["i2p_b32"] = f"{interface.b32}.b32.i2p"
else: else:
ifstats["i2p_b32"] = None ifstats["i2p_b32"] = None
@ -1486,12 +1486,12 @@ class Reticulum:
if self.is_connected_to_shared_instance and hasattr(self, "_force_shared_instance_bitrate") and self._force_shared_instance_bitrate: 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 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 response += simulated_latency
return response return response
except Exception as e: 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 return RNS.Reticulum.DEFAULT_PER_HOP_TIMEOUT
else: else:

View File

@ -148,7 +148,7 @@ class Transport:
Transport.owner = reticulum_instance Transport.owner = reticulum_instance
if Transport.identity == None: 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): 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)
@ -159,7 +159,7 @@ class Transport:
else: else:
RNS.log("Loaded Transport Identity from storage", RNS.LOG_VERBOSE) 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 not Transport.owner.is_connected_to_shared_instance:
if os.path.isfile(packet_hashlist_path): if os.path.isfile(packet_hashlist_path):
try: try:
@ -167,7 +167,7 @@ class Transport:
Transport.packet_hashlist = umsgpack.unpackb(file.read()) Transport.packet_hashlist = umsgpack.unpackb(file.read())
file.close() file.close()
except Exception as e: 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 # Create transport-specific destinations
Transport.path_request_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, Transport.APP_NAME, "path", "request") 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.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_destinations.append(Transport.remote_management_destination)
Transport.control_hashes.append(Transport.remote_management_destination.hash) 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 Transport.jobs_running = False
thread = threading.Thread(target=Transport.jobloop, daemon=True) thread = threading.Thread(target=Transport.jobloop, daemon=True)
thread.start() thread.start()
if RNS.Reticulum.transport_enabled(): if RNS.Reticulum.transport_enabled():
destination_table_path = RNS.Reticulum.storagepath+"/destination_table" destination_table_path = f"{RNS.Reticulum.storagepath}/destination_table"
tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels" tunnel_table_path = f"{RNS.Reticulum.storagepath}/tunnels"
if os.path.isfile(destination_table_path) and not Transport.owner.is_connected_to_shared_instance: if os.path.isfile(destination_table_path) and not Transport.owner.is_connected_to_shared_instance:
serialised_destinations = [] serialised_destinations = []
@ -223,9 +223,9 @@ class Transport:
# increased hop-count. # increased hop-count.
announce_packet.hops += 1 announce_packet.hops += 1
Transport.destination_table[destination_hash] = [timestamp, received_from, hops, expires, random_blobs, receiving_interface, announce_packet] 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: 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: if announce_packet == None:
RNS.log("The announce packet could not be loaded from cache", RNS.LOG_DEBUG) RNS.log("The announce packet could not be loaded from cache", RNS.LOG_DEBUG)
if receiving_interface == None: if receiving_interface == None:
@ -236,10 +236,10 @@ class Transport:
else: else:
specifier = "entries" 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: 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: if os.path.isfile(tunnel_table_path) and not Transport.owner.is_connected_to_shared_instance:
serialised_tunnels = [] serialised_tunnels = []
@ -284,21 +284,21 @@ class Transport:
else: else:
specifier = "entries" 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: 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(): 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 = RNS.Destination(Transport.identity, RNS.Destination.IN, RNS.Destination.SINGLE, Transport.APP_NAME, "probe")
Transport.probe_destination.accepts_links(False) Transport.probe_destination.accepts_links(False)
Transport.probe_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) Transport.probe_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
Transport.probe_destination.announce() 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: else:
Transport.probe_destination = None 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() Transport.start_time = time.time()
# Sort interfaces according to bitrate # Sort interfaces according to bitrate
@ -354,7 +354,7 @@ class Transport:
last_path_request = Transport.path_requests[link.destination.hash] last_path_request = Transport.path_requests[link.destination.hash]
if time.time() - last_path_request > Transport.PATH_REQUEST_MI: 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: if not link.destination.hash in path_requests:
blocked_if = None blocked_if = None
path_requests[link.destination.hash] = blocked_if path_requests[link.destination.hash] = blocked_if
@ -388,7 +388,7 @@ class Transport:
for destination_hash in Transport.announce_table: for destination_hash in Transport.announce_table:
announce_entry = Transport.announce_table[destination_hash] announce_entry = Transport.announce_table[destination_hash]
if announce_entry[2] > Transport.PATHFINDER_R: 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) completed_announces.append(destination_hash)
else: else:
if time.time() > announce_entry[1]: if time.time() > announce_entry[1]:
@ -420,9 +420,9 @@ class Transport:
new_packet.hops = announce_entry[4] new_packet.hops = announce_entry[4]
if block_rebroadcasts: 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: 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) outgoing.append(new_packet)
@ -490,14 +490,14 @@ class Transport:
# If the path has been invalidated between the time of # If the path has been invalidated between the time of
# making the link request and now, try to rediscover it # making the link request and now, try to rediscover it
if not Transport.has_path(link_entry[6]): 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 path_request_conditions =True
# If this link request was originated from a local client # If this link request was originated from a local client
# attempt to rediscover a path to the destination, if this # attempt to rediscover a path to the destination, if this
# has not already happened recently. # has not already happened recently.
elif not path_request_throttle and lr_taken_hops == 0: 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 path_request_conditions = True
# If the link destination was previously only 1 hop # 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 # In that case, try to discover a new path, and mark
# the old one as unresponsive. # the old one as unresponsive.
elif not path_request_throttle and Transport.hops_to(link_entry[6]) == 1: 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 path_request_conditions = True
blocked_if = link_entry[4] blocked_if = link_entry[4]
@ -528,7 +528,7 @@ class Transport:
# changed. In that case, we try to discover a new path, # changed. In that case, we try to discover a new path,
# and mark the old one as potentially unresponsive. # and mark the old one as potentially unresponsive.
elif not path_request_throttle and lr_taken_hops == 1: 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 path_request_conditions = True
blocked_if = link_entry[4] blocked_if = link_entry[4]
@ -561,10 +561,10 @@ class Transport:
if time.time() > destination_expiry: if time.time() > destination_expiry:
stale_paths.append(destination_hash) 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: elif not attached_interface in Transport.interfaces:
stale_paths.append(destination_hash) 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 # Cull the pending discovery path requests table
stale_discovery_path_requests = [] stale_discovery_path_requests = []
@ -573,7 +573,7 @@ class Transport:
if time.time() > entry["timeout"]: if time.time() > entry["timeout"]:
stale_discovery_path_requests.append(destination_hash) 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 # Cull the tunnel table
stale_tunnels = [] stale_tunnels = []
@ -584,7 +584,7 @@ class Transport:
expires = tunnel_entry[3] expires = tunnel_entry[3]
if time.time() > expires: if time.time() > expires:
stale_tunnels.append(tunnel_id) 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: else:
stale_tunnel_paths = [] stale_tunnel_paths = []
tunnel_paths = tunnel_entry[2] tunnel_paths = tunnel_entry[2]
@ -593,7 +593,7 @@ class Transport:
if time.time() > tunnel_path_entry[0] + Transport.DESTINATION_TIMEOUT: if time.time() > tunnel_path_entry[0] + Transport.DESTINATION_TIMEOUT:
stale_tunnel_paths.append(tunnel_path) 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: for tunnel_path in stale_tunnel_paths:
tunnel_paths.pop(tunnel_path) tunnel_paths.pop(tunnel_path)
@ -602,9 +602,9 @@ class Transport:
if ti > 0: if ti > 0:
if ti == 1: if ti == 1:
RNS.log("Removed "+str(ti)+" tunnel path", RNS.LOG_EXTREME) RNS.log(f"Removed {ti} tunnel path", RNS.LOG_EXTREME)
else: else:
RNS.log("Removed "+str(ti)+" tunnel paths", RNS.LOG_EXTREME) RNS.log(f"Removed {ti} tunnel paths", RNS.LOG_EXTREME)
i = 0 i = 0
for truncated_packet_hash in stale_reverse_entries: for truncated_packet_hash in stale_reverse_entries:
@ -613,9 +613,9 @@ class Transport:
if i > 0: if i > 0:
if i == 1: 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: 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 i = 0
for link_id in stale_links: for link_id in stale_links:
@ -624,9 +624,9 @@ class Transport:
if i > 0: if i > 0:
if i == 1: if i == 1:
RNS.log("Released "+str(i)+" link", RNS.LOG_EXTREME) RNS.log(f"Released {i} link", RNS.LOG_EXTREME)
else: else:
RNS.log("Released "+str(i)+" links", RNS.LOG_EXTREME) RNS.log(f"Released {i} links", RNS.LOG_EXTREME)
i = 0 i = 0
for destination_hash in stale_paths: for destination_hash in stale_paths:
@ -635,9 +635,9 @@ class Transport:
if i > 0: if i > 0:
if i == 1: if i == 1:
RNS.log("Removed "+str(i)+" path", RNS.LOG_EXTREME) RNS.log(f"Removed {i} path", RNS.LOG_EXTREME)
else: else:
RNS.log("Removed "+str(i)+" paths", RNS.LOG_EXTREME) RNS.log(f"Removed {i} paths", RNS.LOG_EXTREME)
i = 0 i = 0
for destination_hash in stale_discovery_path_requests: for destination_hash in stale_discovery_path_requests:
@ -646,9 +646,9 @@ class Transport:
if i > 0: if i > 0:
if i == 1: 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: 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 i = 0
for tunnel_id in stale_tunnels: for tunnel_id in stale_tunnels:
@ -657,9 +657,9 @@ class Transport:
if i > 0: if i > 0:
if i == 1: if i == 1:
RNS.log("Removed "+str(i)+" tunnel", RNS.LOG_EXTREME) RNS.log(f"Removed {i} tunnel", RNS.LOG_EXTREME)
else: else:
RNS.log("Removed "+str(i)+" tunnels", RNS.LOG_EXTREME) RNS.log(f"Removed {i} tunnels", RNS.LOG_EXTREME)
i = 0 i = 0
for destination_hash in stale_path_states: for destination_hash in stale_path_states:
@ -668,9 +668,9 @@ class Transport:
if i > 0: if i > 0:
if i == 1: 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: 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() Transport.tables_last_culled = time.time()
@ -686,7 +686,7 @@ class Transport:
except Exception as e: except Exception as e:
RNS.log("An exception occurred while running Transport jobs.", RNS.LOG_ERROR) 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 Transport.jobs_running = False
@ -749,7 +749,7 @@ class Transport:
interface.processOutgoing(raw) interface.processOutgoing(raw)
except Exception as e: 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 @staticmethod
def outbound(packet): def outbound(packet):
@ -857,7 +857,7 @@ class Transport:
if packet.packet_type == RNS.Packet.ANNOUNCE: if packet.packet_type == RNS.Packet.ANNOUNCE:
if packet.attached_interface == None: if packet.attached_interface == None:
if interface.mode == RNS.Interfaces.Interface.Interface.MODE_ACCESS_POINT: 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 should_transmit = False
elif interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING: 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"): if from_interface == None or not hasattr(from_interface, "mode"):
should_transmit = False should_transmit = False
if from_interface == None: 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"): 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: else:
if from_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING: 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 should_transmit = False
elif from_interface.mode == RNS.Interfaces.Interface.Interface.MODE_BOUNDARY: 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 should_transmit = False
elif interface.mode == RNS.Interfaces.Interface.Interface.MODE_BOUNDARY: 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"): if from_interface == None or not hasattr(from_interface, "mode"):
should_transmit = False should_transmit = False
if from_interface == None: 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"): 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: else:
if from_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING: 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 should_transmit = False
else: else:
@ -959,23 +959,23 @@ class Transport:
timer.start() timer.start()
if wait_time < 1: 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: 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)) 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: else:
wait_time = max(interface.announce_allowed_at - time.time(), 0) wait_time = max(interface.announce_allowed_at - time.time(), 0)
if wait_time < 1: 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: 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)) 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: else:
pass pass
@ -1013,7 +1013,7 @@ class Transport:
# Filter packets intended for other transport instances # Filter packets intended for other transport instances
if packet.transport_id != None and packet.packet_type != RNS.Packet.ANNOUNCE: if packet.transport_id != None and packet.packet_type != RNS.Packet.ANNOUNCE:
if packet.transport_id != Transport.identity.hash: 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 return False
if packet.context == RNS.Packet.KEEPALIVE: if packet.context == RNS.Packet.KEEPALIVE:
@ -1032,7 +1032,7 @@ class Transport:
if packet.destination_type == RNS.Destination.PLAIN: if packet.destination_type == RNS.Destination.PLAIN:
if packet.packet_type != RNS.Packet.ANNOUNCE: if packet.packet_type != RNS.Packet.ANNOUNCE:
if packet.hops > 1: 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 return False
else: else:
return True return True
@ -1043,7 +1043,7 @@ class Transport:
if packet.destination_type == RNS.Destination.GROUP: if packet.destination_type == RNS.Destination.GROUP:
if packet.packet_type != RNS.Packet.ANNOUNCE: if packet.packet_type != RNS.Packet.ANNOUNCE:
if packet.hops > 1: 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 return False
else: else:
return True return True
@ -1061,7 +1061,7 @@ class Transport:
RNS.log("Dropped invalid announce packet", RNS.LOG_DEBUG) RNS.log("Dropped invalid announce packet", RNS.LOG_DEBUG)
return False 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 return False
@staticmethod @staticmethod
@ -1316,7 +1316,7 @@ class Transport:
# TODO: There should probably be some kind of REJECT # TODO: There should probably be some kind of REJECT
# mechanism here, to signal to the source that their # mechanism here, to signal to the source that their
# expected path failed. # 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 # Link transport handling. Directs packets according
# to entries in the link tables # to entries in the link tables
@ -1391,17 +1391,17 @@ class Transport:
announce_entry = Transport.announce_table[packet.destination_hash] announce_entry = Transport.announce_table[packet.destination_hash]
if packet.hops-1 == announce_entry[4]: 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 announce_entry[6] += 1
if announce_entry[6] >= Transport.LOCAL_REBROADCASTS_MAX: 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: if packet.destination_hash in Transport.announce_table:
Transport.announce_table.pop(packet.destination_hash) Transport.announce_table.pop(packet.destination_hash)
if packet.hops-1 == announce_entry[4]+1 and announce_entry[2] > 0: if packet.hops-1 == announce_entry[4]+1 and announce_entry[2] > 0:
now = time.time() now = time.time()
if now < announce_entry[1]: 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) Transport.announce_table.pop(packet.destination_hash)
else: else:
@ -1458,7 +1458,7 @@ class Transport:
if not random_blob in random_blobs: if not random_blob in random_blobs:
# TODO: Check that this ^ approach actually # TODO: Check that this ^ approach actually
# works under all circumstances # 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) Transport.mark_path_unknown_state(packet.destination_hash)
should_add = True should_add = True
else: else:
@ -1469,7 +1469,7 @@ class Transport:
# this announce before, update the path table. # this announce before, update the path table.
if (announce_emitted > path_announce_emitted): if (announce_emitted > path_announce_emitted):
if not random_blob in random_blobs: 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) Transport.mark_path_unknown_state(packet.destination_hash)
should_add = True should_add = True
else: else:
@ -1481,7 +1481,7 @@ class Transport:
# allow updating the path table to this one. # allow updating the path table to this one.
elif announce_emitted == path_announce_emitted: elif announce_emitted == path_announce_emitted:
if Transport.path_is_unresponsive(packet.destination_hash): 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 should_add = True
else: else:
should_add = False should_add = False
@ -1551,7 +1551,7 @@ class Transport:
# Insert announce into announce table for retransmission # Insert announce into announce table for retransmission
if rate_blocked: 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: else:
if Transport.from_local_client(packet): if Transport.from_local_client(packet):
@ -1648,9 +1648,9 @@ class Transport:
pr_entry = Transport.discovery_path_requests[packet.destination_hash] pr_entry = Transport.discovery_path_requests[packet.destination_hash]
attached_interface = pr_entry["requesting_interface"] 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_identity = RNS.Identity.recall(packet.destination_hash)
announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown"); announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown");
announce_destination.hash = packet.destination_hash 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] destination_table_entry = [now, received_from, announce_hops, expires, random_blobs, packet.receiving_interface, packet]
Transport.destination_table[packet.destination_hash] = destination_table_entry 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 # If the receiving interface is a tunnel, we add the
# announce to the tunnels table # announce to the tunnels table
@ -1685,7 +1685,7 @@ class Transport:
paths[packet.destination_hash] = destination_table_entry paths[packet.destination_hash] = destination_table_entry
expires = time.time() + Transport.DESTINATION_TIMEOUT expires = time.time() + Transport.DESTINATION_TIMEOUT
tunnel_entry[3] = expires 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 # Call externally registered callbacks from apps
# wanting to know when an announce arrives # wanting to know when an announce arrives
@ -1720,7 +1720,7 @@ class Transport:
) )
except Exception as e: except Exception as e:
RNS.log("Error while processing external announce callback.", RNS.LOG_ERROR) 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) RNS.trace_exception(e)
# Handling for link requests to local destinations # Handling for link requests to local destinations
@ -1773,7 +1773,7 @@ class Transport:
if destination.callbacks.proof_requested(packet): if destination.callbacks.proof_requested(packet):
packet.prove() packet.prove()
except Exception as e: 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 # Handling for proofs and link-request proofs
elif packet.packet_type == RNS.Packet.PROOF: elif packet.packet_type == RNS.Packet.PROOF:
@ -1794,7 +1794,7 @@ class Transport:
signature = packet.data[:RNS.Identity.SIGLENGTH//8] signature = packet.data[:RNS.Identity.SIGLENGTH//8]
if peer_identity.validate(signature, signed_data): 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 = packet.raw[0:1]
new_raw += struct.pack("!B", packet.hops) new_raw += struct.pack("!B", packet.hops)
new_raw += packet.raw[2:] new_raw += packet.raw[2:]
@ -1802,10 +1802,10 @@ class Transport:
Transport.transmit(link_entry[4], new_raw) Transport.transmit(link_entry[4], new_raw)
else: 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: 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: else:
RNS.log("Link request proof received on wrong interface, not transporting it.", RNS.LOG_DEBUG) RNS.log("Link request proof received on wrong interface, not transporting it.", RNS.LOG_DEBUG)
@ -1854,7 +1854,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: 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) reverse_entry = Transport.reverse_table.pop(packet.destination_hash)
if packet.receiving_interface == reverse_entry[1]: 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 = packet.raw[0:1]
new_raw += struct.pack("!B", packet.hops) new_raw += struct.pack("!B", packet.hops)
new_raw += packet.raw[2:] new_raw += packet.raw[2:]
@ -1922,19 +1922,19 @@ class Transport:
except Exception as e: except Exception as e:
RNS.log("An error occurred while validating tunnel establishment packet.", RNS.LOG_DEBUG) 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 @staticmethod
def handle_tunnel(tunnel_id, interface): def handle_tunnel(tunnel_id, interface):
expires = time.time() + Transport.DESTINATION_TIMEOUT expires = time.time() + Transport.DESTINATION_TIMEOUT
if not tunnel_id in Transport.tunnels: 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 = {} paths = {}
tunnel_entry = [tunnel_id, interface, paths, expires] tunnel_entry = [tunnel_id, interface, paths, expires]
interface.tunnel_id = tunnel_id interface.tunnel_id = tunnel_id
Transport.tunnels[tunnel_id] = tunnel_entry Transport.tunnels[tunnel_id] = tunnel_entry
else: 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 = Transport.tunnels[tunnel_id]
tunnel_entry[1] = interface tunnel_entry[1] = interface
tunnel_entry[3] = expires tunnel_entry[3] = expires
@ -1959,21 +1959,21 @@ class Transport:
if announce_hops <= old_hops or time.time() > old_expires: if announce_hops <= old_hops or time.time() > old_expires:
should_add = True should_add = True
else: 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: else:
if time.time() < expires: if time.time() < expires:
should_add = True should_add = True
else: 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: if should_add:
Transport.destination_table[destination_hash] = new_entry 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: else:
deprecated_paths.append(destination_hash) deprecated_paths.append(destination_hash)
for deprecated_path in deprecated_paths: 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) paths.pop(deprecated_path)
@staticmethod @staticmethod
@ -1997,7 +1997,7 @@ class Transport:
@staticmethod @staticmethod
def register_link(link): 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: if link.initiator:
Transport.pending_links.append(link) Transport.pending_links.append(link)
else: else:
@ -2005,10 +2005,10 @@ class Transport:
@staticmethod @staticmethod
def activate_link(link): 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 in Transport.pending_links:
if link.status != RNS.Link.ACTIVE: 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.pending_links.remove(link)
Transport.active_links.append(link) Transport.active_links.append(link)
link.status = RNS.Link.ACTIVE link.status = RNS.Link.ACTIVE
@ -2070,18 +2070,18 @@ class Transport:
if packet.receiving_interface != None: if packet.receiving_interface != None:
interface_reference = str(packet.receiving_interface) 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.write(umsgpack.packb([packet.raw, interface_reference]))
file.close() file.close()
except Exception as e: 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 @staticmethod
def get_cached_packet(packet_hash): def get_cached_packet(packet_hash):
try: try:
packet_hash = RNS.hexrep(packet_hash, delimit=False) 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): if os.path.isfile(path):
file = open(path, "rb") file = open(path, "rb")
@ -2100,7 +2100,7 @@ class Transport:
return None return None
except Exception as e: except Exception as e:
RNS.log("Exception occurred while getting cached packet.", RNS.LOG_ERROR) 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 @staticmethod
def cache_request_packet(packet): def cache_request_packet(packet):
@ -2290,12 +2290,12 @@ class Transport:
queued_announces = True if len(on_interface.announce_queue) > 0 else False queued_announces = True if len(on_interface.announce_queue) > 0 else False
if queued_announces: 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 return
else: else:
now = time.time() now = time.time()
if now < on_interface.announce_allowed_at: 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 return
else: else:
tx_time = ((len(path_request_data)+RNS.Reticulum.HEADER_MINSIZE)*8) / on_interface.bitrate tx_time = ((len(path_request_data)+RNS.Reticulum.HEADER_MINSIZE)*8) / on_interface.bitrate
@ -2319,8 +2319,8 @@ class Transport:
return response return response
except Exception as e: except Exception as e:
RNS.log("An error occurred while processing remote status request from "+str(remote_identity), RNS.LOG_ERROR) RNS.log(f"An error occurred while processing remote status request from {remote_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)
return None return None
@ -2355,8 +2355,8 @@ class Transport:
return response return response
except Exception as e: except Exception as e:
RNS.log("An error occurred while processing remote status request from "+str(remote_identity), RNS.LOG_ERROR) RNS.log(f"An error occurred while processing remote status request from {remote_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)
return None return None
@ -2402,13 +2402,13 @@ class Transport:
) )
else: 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: 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: 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 @staticmethod
def path_request(destination_hash, is_from_local_client, attached_interface, requestor_transport_id=None, tag=None): def path_request(destination_hash, is_from_local_client, attached_interface, requestor_transport_id=None, tag=None):
@ -2418,11 +2418,11 @@ class Transport:
if RNS.Reticulum.transport_enabled() and attached_interface.mode in RNS.Interfaces.Interface.Interface.DISCOVER_PATHS_FOR: if RNS.Reticulum.transport_enabled() and attached_interface.mode in RNS.Interfaces.Interface.Interface.DISCOVER_PATHS_FOR:
should_search_for_unknown = True should_search_for_unknown = True
interface_str = " on "+str(attached_interface) interface_str = f" on {attached_interface}"
else: else:
interface_str = "" 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 destination_exists_on_local_client = False
if len(Transport.local_client_interfaces) > 0: if len(Transport.local_client_interfaces) > 0:
@ -2436,7 +2436,7 @@ class Transport:
local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None) local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None)
if local_destination != None: if local_destination != None:
local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface) 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): elif (RNS.Reticulum.transport_enabled() or is_from_local_client) and (destination_hash in Transport.destination_table):
packet = Transport.destination_table[destination_hash][6] packet = Transport.destination_table[destination_hash][6]
@ -2454,9 +2454,9 @@ class Transport:
# inefficient. There is probably a better way. Doing # inefficient. There is probably a better way. Doing
# path invalidation here would decrease the network # path invalidation here would decrease the network
# convergence time. Maybe just drop it? # 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: 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() now = time.time()
retries = Transport.PATHFINDER_R retries = Transport.PATHFINDER_R
@ -2468,7 +2468,7 @@ class Transport:
retransmit_timeout = now retransmit_timeout = now
else: else:
if Transport.is_local_client_interface(Transport.next_hop_interface(destination_hash)): 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 retransmit_timeout = now
else: else:
@ -2495,7 +2495,7 @@ class Transport:
elif is_from_local_client: elif is_from_local_client:
# Forward path request on all interfaces # Forward path request on all interfaces
# except the local client # 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() request_tag = RNS.Identity.get_random_hash()
for interface in Transport.interfaces: for interface in Transport.interfaces:
if not interface == attached_interface: if not interface == attached_interface:
@ -2503,11 +2503,11 @@ class Transport:
elif should_search_for_unknown: elif should_search_for_unknown:
if destination_hash in Transport.discovery_path_requests: 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: else:
# Forward path request on all interfaces # Forward path request on all interfaces
# except the requestor interface # 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 } 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 Transport.discovery_path_requests[destination_hash] = pr_entry
@ -2520,12 +2520,12 @@ class Transport:
elif not is_from_local_client and len(Transport.local_client_interfaces) > 0: elif not is_from_local_client and len(Transport.local_client_interfaces) > 0:
# Forward the path request on all local # Forward the path request on all local
# client interfaces # 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: for interface in Transport.local_client_interfaces:
Transport.request_path(destination_hash, on_interface=interface) Transport.request_path(destination_hash, on_interface=interface)
else: 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 @staticmethod
def from_local_client(packet): def from_local_client(packet):
@ -2577,7 +2577,7 @@ class Transport:
try: try:
interface.detach() interface.detach()
except Exception as e: 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 @staticmethod
def shared_connection_disappeared(): def shared_connection_disappeared():
@ -2613,10 +2613,10 @@ class Transport:
if na == 1: if na == 1:
na_str = "1 announce" na_str = "1 announce"
else: else:
na_str = str(na)+" announces" na_str = f"{na} announces"
interface.announce_queue = [] 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 @staticmethod
@ -2649,20 +2649,20 @@ class Transport:
else: else:
RNS.log("Saving packet hashlist to storage...", RNS.LOG_DEBUG) 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 = open(packet_hashlist_path, "wb")
file.write(umsgpack.packb(Transport.packet_hashlist)) file.write(umsgpack.packb(Transport.packet_hashlist))
file.close() file.close()
save_time = time.time() - save_start save_time = time.time() - save_start
if save_time < 1: if save_time < 1:
time_str = str(round(save_time*1000,2))+"ms" time_str = f"{round(save_time * 1000, 2)}ms"
else: else:
time_str = str(round(save_time,2))+"s" time_str = f"{round(save_time, 2)}s"
RNS.log("Saved packet hashlist in "+time_str, RNS.LOG_DEBUG) RNS.log(f"Saved packet hashlist in {time_str}", RNS.LOG_DEBUG)
except Exception as e: 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 Transport.saving_packet_hashlist = False
@ -2719,20 +2719,20 @@ class Transport:
Transport.cache(de[6], force_cache=True) 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 = open(destination_table_path, "wb")
file.write(umsgpack.packb(serialised_destinations)) file.write(umsgpack.packb(serialised_destinations))
file.close() file.close()
save_time = time.time() - save_start save_time = time.time() - save_start
if save_time < 1: if save_time < 1:
time_str = str(round(save_time*1000,2))+"ms" time_str = f"{round(save_time * 1000, 2)}ms"
else: else:
time_str = str(round(save_time,2))+"s" time_str = f"{round(save_time, 2)}s"
RNS.log("Saved "+str(len(serialised_destinations))+" path table entries in "+time_str, RNS.LOG_DEBUG) RNS.log(f"Saved {len(serialised_destinations)} path table entries in {time_str}", RNS.LOG_DEBUG)
except Exception as e: 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 Transport.saving_path_table = False
@ -2797,19 +2797,19 @@ class Transport:
serialised_tunnel = [tunnel_id, interface_hash, serialised_paths, expires] serialised_tunnel = [tunnel_id, interface_hash, serialised_paths, expires]
serialised_tunnels.append(serialised_tunnel) serialised_tunnels.append(serialised_tunnel)
tunnels_path = RNS.Reticulum.storagepath+"/tunnels" tunnels_path = f"{RNS.Reticulum.storagepath}/tunnels"
file = open(tunnels_path, "wb") file = open(tunnels_path, "wb")
file.write(umsgpack.packb(serialised_tunnels)) file.write(umsgpack.packb(serialised_tunnels))
file.close() file.close()
save_time = time.time() - save_start save_time = time.time() - save_start
if save_time < 1: if save_time < 1:
time_str = str(round(save_time*1000,2))+"ms" time_str = f"{round(save_time * 1000, 2)}ms"
else: else:
time_str = str(round(save_time,2))+"s" time_str = f"{round(save_time, 2)}s"
RNS.log("Saved "+str(len(serialised_tunnels))+" tunnel table entries in "+time_str, RNS.LOG_DEBUG) RNS.log(f"Saved {len(serialised_tunnels)} tunnel table entries in {time_str}", RNS.LOG_DEBUG)
except Exception as e: 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 Transport.saving_tunnel_table = False

View File

@ -23,5 +23,5 @@
import os import os
import glob 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')] __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]

View File

@ -59,7 +59,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
if jail != None: if jail != None:
fetch_jail = os.path.abspath(os.path.expanduser(jail)) 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)
if save != None: if save != None:
sp = os.path.abspath(os.path.expanduser(save)) sp = os.path.abspath(os.path.expanduser(save))
@ -73,9 +73,9 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
RNS.log("Output directory not found", RNS.LOG_ERROR) RNS.log("Output directory not found", RNS.LOG_ERROR)
exit(3) exit(3)
RNS.log("Saving received files in \""+save_path+"\"", RNS.LOG_VERBOSE) RNS.log(f"Saving received files in \"{save_path}\"", RNS.LOG_VERBOSE)
identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}"
if os.path.isfile(identity_path): if os.path.isfile(identity_path):
identity = RNS.Identity.from_file(identity_path) identity = RNS.Identity.from_file(identity_path)
@ -87,8 +87,8 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "receive") destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "receive")
if display_identity: if display_identity:
print("Identity : "+str(identity)) print(f"Identity : {identity}")
print("Listening on : "+RNS.prettyhexrep(destination.hash)) print(f"Listening on : {RNS.prettyhexrep(destination.hash)}")
exit(0) exit(0)
if disable_auth: if disable_auth:
@ -98,14 +98,14 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
try: try:
allowed_file_name = "allowed_identities" allowed_file_name = "allowed_identities"
allowed_file = None allowed_file = None
if os.path.isfile(os.path.expanduser("/etc/rncp/"+allowed_file_name)): if os.path.isfile(os.path.expanduser(f"/etc/rncp/{allowed_file_name}")):
allowed_file = os.path.expanduser("/etc/rncp/"+allowed_file_name) allowed_file = os.path.expanduser(f"/etc/rncp/{allowed_file_name}")
elif os.path.isfile(os.path.expanduser("~/.config/rncp/"+allowed_file_name)): elif os.path.isfile(os.path.expanduser(f"~/.config/rncp/{allowed_file_name}")):
allowed_file = os.path.expanduser("~/.config/rncp/"+allowed_file_name) allowed_file = os.path.expanduser(f"~/.config/rncp/{allowed_file_name}")
elif os.path.isfile(os.path.expanduser("~/.rncp/"+allowed_file_name)): elif os.path.isfile(os.path.expanduser(f"~/.rncp/{allowed_file_name}")):
allowed_file = os.path.expanduser("~/.rncp/"+allowed_file_name) allowed_file = os.path.expanduser(f"~/.rncp/{allowed_file_name}")
if allowed_file != None: if allowed_file != None:
af = open(allowed_file, "r") af = open(allowed_file)
al = af.read().replace("\r", "").split("\n") al = af.read().replace("\r", "").split("\n")
ali = [] ali = []
for a in al: for a in al:
@ -122,16 +122,16 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
else: else:
ms = "ies" 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: 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: if allowed != None:
for a in allowed: for a in allowed:
try: try:
if len(a) != dest_len: 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: try:
destination_hash = bytes.fromhex(a) destination_hash = bytes.fromhex(a)
allowed_identity_hashes.append(destination_hash) allowed_identity_hashes.append(destination_hash)
@ -165,11 +165,11 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
target_link = link target_link = link
if not os.path.isfile(file_path): 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 return False
else: else:
if target_link != None: 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() temp_file = TemporaryFile()
real_file = open(file_path, "rb") real_file = open(file_path, "rb")
@ -199,7 +199,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
else: else:
destination.register_request_handler("fetch_file", response_generator=fetch_request, allow=RNS.Destination.ALLOW_LIST, allowed_list=allowed_identity_hashes) 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: if announce >= 0:
def job(): def job():
@ -250,16 +250,16 @@ def receive_resource_callback(resource):
def receive_resource_started(resource): def receive_resource_started(resource):
if resource.link.get_remote_identity(): 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: else:
id_str = "" 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): def receive_resource_concluded(resource):
global save_path global save_path
if resource.status == RNS.Resource.COMPLETE: if resource.status == RNS.Resource.COMPLETE:
print(str(resource)+" completed") print(f"{resource} completed")
if resource.total_size > 4: if resource.total_size > 4:
filename_len = int.from_bytes(resource.data.read(2), "big") filename_len = int.from_bytes(resource.data.read(2), "big")
@ -277,7 +277,7 @@ def receive_resource_concluded(resource):
full_save_path = saved_filename full_save_path = saved_filename
while os.path.isfile(full_save_path): while os.path.isfile(full_save_path):
counter += 1 counter += 1
full_save_path = saved_filename+"."+str(counter) full_save_path = f"{saved_filename}.{counter}"
file = open(full_save_path, "wb") file = open(full_save_path, "wb")
file.write(resource.data.read()) file.write(resource.data.read())
@ -348,7 +348,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination) != dest_len: 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: try:
destination_hash = bytes.fromhex(destination) destination_hash = bytes.fromhex(destination)
except Exception as e: except Exception as e:
@ -359,11 +359,11 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel) 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): if os.path.isfile(identity_path):
identity = RNS.Identity.from_file(identity_path) identity = RNS.Identity.from_file(identity_path)
if identity == None: 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) exit(2)
else: else:
identity = None identity = None
@ -376,9 +376,9 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
if not RNS.Transport.has_path(destination_hash): if not RNS.Transport.has_path(destination_hash):
RNS.Transport.request_path(destination_hash) RNS.Transport.request_path(destination_hash)
if silent: if silent:
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested") print(f"Path to {RNS.prettyhexrep(destination_hash)} requested")
else: else:
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=es) print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=es)
sys.stdout.flush() sys.stdout.flush()
i = 0 i = 0
@ -387,7 +387,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: while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout:
if not silent: if not silent:
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
@ -399,9 +399,9 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
exit(1) exit(1)
else: else:
if silent: if silent:
print("Establishing link with "+RNS.prettyhexrep(destination_hash)) print(f"Establishing link with {RNS.prettyhexrep(destination_hash)}")
else: else:
print(f"{erase_str}Establishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=es) print(f"{erase_str}Establishing link with {RNS.prettyhexrep(destination_hash)} ", end=es)
listener_identity = RNS.Identity.recall(destination_hash) listener_identity = RNS.Identity.recall(destination_hash)
listener_destination = RNS.Destination( listener_destination = RNS.Destination(
@ -416,15 +416,15 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout: while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout:
if not silent: if not silent:
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
if not RNS.Transport.has_path(destination_hash): if not RNS.Transport.has_path(destination_hash):
if silent: if silent:
print("Could not establish link with "+RNS.prettyhexrep(destination_hash)) print(f"Could not establish link with {RNS.prettyhexrep(destination_hash)}")
else: else:
print(f"{erase_str}Could not establish link with "+RNS.prettyhexrep(destination_hash)) print(f"{erase_str}Could not establish link with {RNS.prettyhexrep(destination_hash)}")
exit(1) exit(1)
else: else:
if silent: if silent:
@ -481,7 +481,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
full_save_path = saved_filename full_save_path = saved_filename
while os.path.isfile(full_save_path): while os.path.isfile(full_save_path):
counter += 1 counter += 1
full_save_path = saved_filename+"."+str(counter) full_save_path = f"{saved_filename}.{counter)"
file = open(full_save_path, "wb") file = open(full_save_path, "wb")
file.write(resource.data.read()) file.write(resource.data.read())
@ -507,19 +507,19 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
while not request_resolved: while not request_resolved:
if not silent: if not silent:
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
if request_status == "fetch_not_allowed": if request_status == "fetch_not_allowed":
if not silent: print(f"{erase_str}", end="") if not silent: print(f"{erase_str}", 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() link.teardown()
time.sleep(0.15) time.sleep(0.15)
exit(0) exit(0)
elif request_status == "not_found": elif request_status == "not_found":
if not silent: print(f"{erase_str}", end="") if not silent: print(f"{erase_str}", 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() link.teardown()
time.sleep(0.15) time.sleep(0.15)
exit(0) exit(0)
@ -570,9 +570,9 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
exit(1) exit(1)
else: else:
if silent: if silent:
print(str(file)+" fetched from "+RNS.prettyhexrep(destination_hash)) print(f"{file} fetched from {RNS.prettyhexrep(destination_hash)}")
else: else:
print("\n"+str(file)+" fetched from "+RNS.prettyhexrep(destination_hash)) print(f"\n{file} fetched from {RNS.prettyhexrep(destination_hash)}")
link.teardown() link.teardown()
time.sleep(0.15) time.sleep(0.15)
exit(0) exit(0)
@ -590,7 +590,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination) != dest_len: 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: try:
destination_hash = bytes.fromhex(destination) destination_hash = bytes.fromhex(destination)
except Exception as e: except Exception as e:
@ -625,11 +625,11 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel) 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): if os.path.isfile(identity_path):
identity = RNS.Identity.from_file(identity_path) identity = RNS.Identity.from_file(identity_path)
if identity == None: 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) exit(2)
else: else:
identity = None identity = None
@ -642,9 +642,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
if not RNS.Transport.has_path(destination_hash): if not RNS.Transport.has_path(destination_hash):
RNS.Transport.request_path(destination_hash) RNS.Transport.request_path(destination_hash)
if silent: if silent:
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested") print(f"Path to {RNS.prettyhexrep(destination_hash)} requested")
else: else:
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=es) print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=es)
sys.stdout.flush() sys.stdout.flush()
i = 0 i = 0
@ -653,7 +653,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: while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout:
if not silent: if not silent:
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
@ -665,9 +665,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
exit(1) exit(1)
else: else:
if silent: if silent:
print("Establishing link with "+RNS.prettyhexrep(destination_hash)) print(f"Establishing link with {RNS.prettyhexrep(destination_hash)}")
else: else:
print(f"{erase_str}Establishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=es) print(f"{erase_str}Establishing link with {RNS.prettyhexrep(destination_hash)} ", end=es)
receiver_identity = RNS.Identity.recall(destination_hash) receiver_identity = RNS.Identity.recall(destination_hash)
receiver_destination = RNS.Destination( receiver_destination = RNS.Destination(
@ -682,21 +682,21 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout: while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout:
if not silent: if not silent:
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
if time.time() > estab_timeout: if time.time() > estab_timeout:
if silent: if silent:
print("Link establishment with "+RNS.prettyhexrep(destination_hash)+" timed out") print(f"Link establishment with {RNS.prettyhexrep(destination_hash)} timed out")
else: else:
print(f"{erase_str}Link establishment with "+RNS.prettyhexrep(destination_hash)+" timed out") print(f"{erase_str}Link establishment with {RNS.prettyhexrep(destination_hash)} timed out")
exit(1) exit(1)
elif not RNS.Transport.has_path(destination_hash): elif not RNS.Transport.has_path(destination_hash):
if silent: if silent:
print("No path found to "+RNS.prettyhexrep(destination_hash)) print(f"No path found to {RNS.prettyhexrep(destination_hash)}")
else: else:
print(f"{erase_str}No path found to "+RNS.prettyhexrep(destination_hash)) print(f"{erase_str}No path found to {RNS.prettyhexrep(destination_hash)}")
exit(1) exit(1)
else: else:
if silent: if silent:
@ -711,16 +711,16 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
while resource.status < RNS.Resource.TRANSFERRING: while resource.status < RNS.Resource.TRANSFERRING:
if not silent: if not silent:
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
if resource.status > RNS.Resource.COMPLETE: if resource.status > RNS.Resource.COMPLETE:
if silent: if silent:
print("File was not accepted by "+RNS.prettyhexrep(destination_hash)) print(f"File was not accepted by {RNS.prettyhexrep(destination_hash)}")
else: else:
print(f"{erase_str}File was not accepted by "+RNS.prettyhexrep(destination_hash)) print(f"{erase_str}File was not accepted by {RNS.prettyhexrep(destination_hash)}")
exit(1) exit(1)
else: else:
if silent: if silent:
@ -743,9 +743,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
ss = size_str(speed, "b") ss = size_str(speed, "b")
stat_str = f"{percent}% - {cs} of {ts} - {ss}ps{phy_str}" stat_str = f"{percent}% - {cs} of {ts} - {ss}ps{phy_str}"
if not done: if not done:
print(f"{erase_str}Transferring file "+syms[i]+" "+stat_str, end=es) print(f"{erase_str}Transferring file {syms[i]} {stat_str}", end=es)
else: else:
print(f"{erase_str}Transfer complete "+stat_str, end=es) print(f"{erase_str}Transfer complete {stat_str}", end=es)
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
return i return i
@ -765,9 +765,9 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
exit(1) exit(1)
else: else:
if silent: if silent:
print(str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash)) print(f"{file_path} copied to {RNS.prettyhexrep(destination_hash)}")
else: else:
print("\n"+str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash)) print(f"\n{file_path} copied to {RNS.prettyhexrep(destination_hash)}")
link.teardown() link.teardown()
time.sleep(0.25) time.sleep(0.25)
real_file.close() real_file.close()
@ -795,7 +795,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("-w", action="store", metavar="seconds", type=float, help="sender timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT)
parser.add_argument('-P', '--phy-rates', action='store_true', default=False, help="display physical layer transfer rates") parser.add_argument('-P', '--phy-rates', action='store_true', default=False, help="display physical layer transfer rates")
# parser.add_argument("--limit", action="store", metavar="files", type=float, help="maximum number of files to accept", default=None) # 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() args = parser.parse_args()
@ -869,12 +869,12 @@ def size_str(num, suffix='B'):
for unit in units: for unit in units:
if abs(num) < 1000.0: if abs(num) < 1000.0:
if unit == "": if unit == "":
return "%.0f %s%s" % (num, unit, suffix) return f"{num:.0f} {unit}{suffix}"
else: else:
return "%.2f %s%s" % (num, unit, suffix) return f"{num:.2f} {unit}{suffix}"
num /= 1000.0 num /= 1000.0
return "%.2f%s%s" % (num, last_unit, suffix) return f"{num:.2f}{last_unit}{suffix}"
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -43,14 +43,14 @@ def spin(until=None, msg=None, timeout=None):
if timeout != None: if timeout != None:
timeout = time.time()+timeout timeout = time.time()+timeout
print(msg+" ", end=" ") print(f"{msg} ", end=" ")
while (timeout == None or time.time()<timeout) and not until(): while (timeout == None or time.time()<timeout) and not until():
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
print("\r"+" "*len(msg)+" \r", end="") print(f"\r{' ' * len(msg)} \r", end="")
if timeout != None and time.time() > timeout: if timeout != None and time.time() > timeout:
return False 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", "--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("-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() args = parser.parse_args()
@ -124,30 +124,30 @@ def main():
else: else:
identity_bytes = bytes.fromhex(args.import_str) identity_bytes = bytes.fromhex(args.import_str)
except Exception as e: except Exception as e:
print("Invalid identity data specified for import: "+str(e)) print(f"Invalid identity data specified for import: {e}")
exit(41) exit(41)
try: try:
identity = RNS.Identity.from_bytes(identity_bytes) identity = RNS.Identity.from_bytes(identity_bytes)
except Exception as e: 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) exit(42)
RNS.log("Identity imported") RNS.log("Identity imported")
if args.base64: 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: 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: 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 identity.prv:
if args.print_private: if args.print_private:
if args.base64: 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: 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: 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: else:
RNS.log("Private Key : Hidden") RNS.log("Private Key : Hidden")
@ -156,13 +156,13 @@ def main():
wp = os.path.expanduser(args.write) wp = os.path.expanduser(args.write)
if not os.path.isfile(wp) or args.force: if not os.path.isfile(wp) or args.force:
identity.to_file(wp) identity.to_file(wp)
RNS.log("Wrote imported identity to "+str(args.write)) RNS.log(f"Wrote imported identity to {args.write}")
else: else:
print("File "+str(wp)+" already exists, not overwriting") print(f"File {wp} already exists, not overwriting")
exit(43) exit(43)
except Exception as e: 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(44)
exit(0) exit(0)
@ -189,16 +189,16 @@ def main():
if args.generate: if args.generate:
identity = RNS.Identity() identity = RNS.Identity()
if not args.force and os.path.isfile(args.generate): 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) exit(3)
else: else:
try: try:
identity.to_file(args.generate) 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) exit(0)
except Exception as e: except Exception as e:
RNS.log("An error ocurred while saving the generated Identity.", RNS.LOG_ERROR) 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) exit(4)
identity = None identity = None
@ -210,24 +210,24 @@ def main():
if identity == None: if identity == None:
if not args.request: 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) RNS.log("You can query the network for unknown Identities with the -R option.", RNS.LOG_ERROR)
exit(5) exit(5)
else: else:
RNS.Transport.request_path(destination_hash) RNS.Transport.request_path(destination_hash)
def spincheck(): def spincheck():
return RNS.Identity.recall(destination_hash) != None 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(): if not spincheck():
RNS.log("Identity request timed out", RNS.LOG_ERROR) RNS.log("Identity request timed out", RNS.LOG_ERROR)
exit(6) exit(6)
else: else:
identity = RNS.Identity.recall(destination_hash) 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: 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: except Exception as e:
@ -243,7 +243,7 @@ def main():
else: else:
try: try:
identity = RNS.Identity.from_file(identity_str) 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: except Exception as e:
RNS.log("Could not decode Identity from specified file") RNS.log("Could not decode Identity from specified file")
@ -261,15 +261,15 @@ def main():
aspects = aspects[1:] aspects = aspects[1:]
if identity.pub != None: if identity.pub != None:
destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects) 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(f"The {args.hash} destination for this Identity is {RNS.prettyhexrep(destination.hash)}")
RNS.log("The full destination specifier is "+str(destination)) RNS.log(f"The full destination specifier is {destination}")
time.sleep(0.25) time.sleep(0.25)
exit(0) exit(0)
else: else:
raise KeyError("No public key known") raise KeyError("No public key known")
except Exception as e: except Exception as e:
RNS.log("An error ocurred while attempting to send the announce.", RNS.LOG_ERROR) 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) exit(0)
@ -284,39 +284,39 @@ def main():
aspects = aspects[1:] aspects = aspects[1:]
if identity.prv != None: if identity.prv != None:
destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, app_name, *aspects) destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, app_name, *aspects)
RNS.log("Created destination "+str(destination)) RNS.log(f"Created destination {destination}")
RNS.log("Announcing destination "+RNS.prettyhexrep(destination.hash)) RNS.log(f"Announcing destination {RNS.prettyhexrep(destination.hash)}")
destination.announce() destination.announce()
time.sleep(0.25) time.sleep(0.25)
exit(0) exit(0)
else: else:
destination = RNS.Destination(identity, RNS.Destination.OUT, RNS.Destination.SINGLE, app_name, *aspects) 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(f"The {args.announce} destination for this Identity is {RNS.prettyhexrep(destination.hash)}")
RNS.log("The full destination specifier is "+str(destination)) RNS.log(f"The full destination specifier is {destination}")
RNS.log("Cannot announce this destination, since the private key is not held") RNS.log("Cannot announce this destination, since the private key is not held")
time.sleep(0.25) time.sleep(0.25)
exit(33) exit(33)
except Exception as e: except Exception as e:
RNS.log("An error ocurred while attempting to send the announce.", RNS.LOG_ERROR) 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) exit(0)
if args.print_identity: if args.print_identity:
if args.base64: 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: 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: 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 identity.prv:
if args.print_private: if args.print_private:
if args.base64: 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: 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: 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: else:
RNS.log("Private Key : Hidden") RNS.log("Private Key : Hidden")
exit(0) exit(0)
@ -324,11 +324,11 @@ def main():
if args.export: if args.export:
if identity.prv: if identity.prv:
if args.base64: 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: 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: 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: else:
RNS.log("Identity doesn't hold a private key, cannot export") RNS.log("Identity doesn't hold a private key, cannot export")
exit(50) exit(50)
@ -336,28 +336,28 @@ def main():
exit(0) exit(0)
if args.validate: if args.validate:
if not args.read and args.validate.lower().endswith("."+SIG_EXT): if not args.read and args.validate.lower().endswith(f".{SIG_EXT}"):
args.read = str(args.validate).replace("."+SIG_EXT, "") args.read = str(args.validate).replace(f".{SIG_EXT}", "")
if not os.path.isfile(args.validate): 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) exit(10)
if not os.path.isfile(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(11) exit(11)
data_input = None data_input = None
if args.read: if args.read:
if not os.path.isfile(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) exit(12)
else: else:
try: try:
data_input = open(args.read, "rb") data_input = open(args.read, "rb")
except Exception as e: except Exception as e:
RNS.log("Could not open input file for reading", RNS.LOG_ERROR) 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) exit(13)
# TODO: Actually expand this to a good solution # TODO: Actually expand this to a good solution
@ -368,28 +368,28 @@ def main():
data_output = None data_output = None
if args.encrypt and not args.write and not args.stdout and args.read: 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): 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("."+ENCRYPT_EXT, "") args.write = str(args.read).replace(f".{ENCRYPT_EXT}", "")
if args.sign and identity.prv == None: if args.sign and identity.prv == None:
RNS.log("Specified Identity does not hold a private key. Cannot sign.", RNS.LOG_ERROR) RNS.log("Specified Identity does not hold a private key. Cannot sign.", RNS.LOG_ERROR)
exit(14) exit(14)
if args.sign and not args.write and not args.stdout and args.read: 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 args.write:
if not args.force and os.path.isfile(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) exit(15)
else: else:
try: try:
data_output = open(args.write, "wb") data_output = open(args.write, "wb")
except Exception as e: except Exception as e:
RNS.log("Could not open output file for writing", RNS.LOG_ERROR) 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) exit(15)
# TODO: Actually expand this to a good solution # TODO: Actually expand this to a good solution
@ -414,7 +414,7 @@ def main():
exit(18) exit(18)
if not args.stdout: if not args.stdout:
RNS.log("Signing "+str(args.read)) RNS.log(f"Signing {args.read}")
try: try:
data_output.write(identity.sign(data_input.read())) data_output.write(identity.sign(data_input.read()))
@ -423,13 +423,13 @@ def main():
if not args.stdout: if not args.stdout:
if args.read: 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) exit(0)
except Exception as e: except Exception as e:
if not args.stdout: if not args.stdout:
RNS.log("An error ocurred while encrypting data.", RNS.LOG_ERROR) 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: try:
data_output.close() data_output.close()
except: except:
@ -453,8 +453,8 @@ def main():
try: try:
sig_input = open(args.validate, "rb") sig_input = open(args.validate, "rb")
except Exception as e: except Exception as e:
RNS.log("An error ocurred while opening "+str(args.validate)+".", RNS.LOG_ERROR) RNS.log(f"An error ocurred while opening {args.validate}.", 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(21) exit(21)
@ -464,17 +464,17 @@ def main():
if not validated: if not validated:
if not args.stdout: 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) exit(22)
else: else:
if not args.stdout: 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) exit(0)
except Exception as e: except Exception as e:
if not args.stdout: if not args.stdout:
RNS.log("An error ocurred while validating signature.", RNS.LOG_ERROR) 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: try:
data_output.close() data_output.close()
except: except:
@ -497,7 +497,7 @@ def main():
exit(25) exit(25)
if not args.stdout: if not args.stdout:
RNS.log("Encrypting "+str(args.read)) RNS.log(f"Encrypting {args.read}")
try: try:
more_data = True more_data = True
@ -511,13 +511,13 @@ def main():
data_input.close() data_input.close()
if not args.stdout: if not args.stdout:
if args.read: 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) exit(0)
except Exception as e: except Exception as e:
if not args.stdout: if not args.stdout:
RNS.log("An error ocurred while encrypting data.", RNS.LOG_ERROR) 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: try:
data_output.close() data_output.close()
except: except:
@ -544,7 +544,7 @@ def main():
exit(29) exit(29)
if not args.stdout: if not args.stdout:
RNS.log("Decrypting "+str(args.read)+"...") RNS.log(f"Decrypting {args.read}...")
try: try:
more_data = True more_data = True
@ -564,13 +564,13 @@ def main():
data_input.close() data_input.close()
if not args.stdout: if not args.stdout:
if args.read: 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) exit(0)
except Exception as e: except Exception as e:
if not args.stdout: if not args.stdout:
RNS.log("An error ocurred while decrypting data.", RNS.LOG_ERROR) 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: try:
data_output.close() data_output.close()
except: except:

View File

@ -48,7 +48,7 @@ def main():
parser.add_argument('-v', '--verbose', action='count', default=0) parser.add_argument('-v', '--verbose', action='count', default=0)
parser.add_argument('-q', '--quiet', 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("--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() args = parser.parse_args()

File diff suppressed because one or more lines are too long

View File

@ -35,7 +35,7 @@ def connect_remote(destination_hash, auth_identity, timeout, no_output = False):
global remote_link, reticulum global remote_link, reticulum
if not RNS.Transport.has_path(destination_hash): if not RNS.Transport.has_path(destination_hash):
if not no_output: 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() sys.stdout.flush()
RNS.Transport.request_path(destination_hash) RNS.Transport.request_path(destination_hash)
pr_time = time.time() pr_time = time.time()
@ -88,7 +88,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(remote) != dest_len: 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: try:
identity_hash = bytes.fromhex(remote) identity_hash = bytes.fromhex(remote)
remote_hash = RNS.Destination.hash_from_name_and_identity("rnstransport.remote.management", identity_hash) 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)) identity = RNS.Identity.from_file(os.path.expanduser(management_identity))
if identity == None: 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: try:
connect_remote(remote_hash, identity, remote_timeout, no_output) connect_remote(remote_hash, identity, remote_timeout, no_output)
@ -118,7 +118,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: 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: try:
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e: except Exception as e:
@ -166,7 +166,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
m_str = " " m_str = " "
else: else:
m_str = "s" 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: if destination_hash != None and displayed == 0:
print("No path known") print("No path known")
@ -178,7 +178,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: 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: try:
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e: except Exception as e:
@ -242,21 +242,21 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
else: else:
s_str = "s" 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: else:
rv_str = "" rv_str = ""
if entry["blocked_until"] > time.time(): if entry["blocked_until"] > time.time():
bli = time.time()-(int(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: else:
bl_str = "" 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: 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)) print(str(e))
if destination_hash != None and displayed == 0: if destination_hash != None and displayed == 0:
@ -283,7 +283,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: 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: try:
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e: except Exception as e:
@ -293,9 +293,9 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
sys.exit(1) sys.exit(1)
if reticulum.drop_path(destination_hash): if reticulum.drop_path(destination_hash):
print("Dropped path to "+RNS.prettyhexrep(destination_hash)) print(f"Dropped path to {RNS.prettyhexrep(destination_hash)}")
else: 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) sys.exit(1)
elif drop_via: elif drop_via:
@ -308,7 +308,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: 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: try:
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e: except Exception as e:
@ -318,9 +318,9 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
sys.exit(1) sys.exit(1)
if reticulum.drop_all_via(destination_hash): 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: 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) sys.exit(1)
else: else:
@ -333,7 +333,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: 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: try:
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e: 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): if not RNS.Transport.has_path(destination_hash):
RNS.Transport.request_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() sys.stdout.flush()
i = 0 i = 0
@ -352,7 +352,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
limit = time.time()+timeout limit = time.time()+timeout
while not RNS.Transport.has_path(destination_hash) and time.time()<limit: while not RNS.Transport.has_path(destination_hash) and time.time()<limit:
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
@ -371,7 +371,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
else: else:
ms = "" ms = ""
print("\rPath found, destination "+RNS.prettyhexrep(destination_hash)+" is "+str(hops)+" hop"+ms+" away via "+next_hop+" on "+next_hop_interface) print(f'\rPath found, destination {RNS.prettyhexrep(destination_hash)} is {hops} hop{ms} away via {next_hop} on {next_hop_interface}')
else: else:
print("\r \rPath not found") print("\r \rPath not found")
sys.exit(1) sys.exit(1)
@ -392,7 +392,7 @@ def main():
parser.add_argument( parser.add_argument(
"--version", "--version",
action="version", action="version",
version="rnpath {version}".format(version=__version__) version=f"rnpath {__version__}"
) )
parser.add_argument( parser.add_argument(
@ -547,26 +547,26 @@ def pretty_date(time=False):
return '' return ''
if day_diff == 0: if day_diff == 0:
if second_diff < 10: if second_diff < 10:
return str(second_diff) + " seconds" return f"{second_diff} seconds"
if second_diff < 60: if second_diff < 60:
return str(second_diff) + " seconds" return f"{second_diff} seconds"
if second_diff < 120: if second_diff < 120:
return "1 minute" return "1 minute"
if second_diff < 3600: if second_diff < 3600:
return str(int(second_diff / 60)) + " minutes" return f"{int(second_diff / 60)} minutes"
if second_diff < 7200: if second_diff < 7200:
return "an hour" return "an hour"
if second_diff < 86400: if second_diff < 86400:
return str(int(second_diff / 3600)) + " hours" return f"{int(second_diff / 3600)} hours"
if day_diff == 1: if day_diff == 1:
return "1 day" return "1 day"
if day_diff < 7: if day_diff < 7:
return str(day_diff) + " days" return f"{day_diff} days"
if day_diff < 31: if day_diff < 31:
return str(int(day_diff / 7)) + " weeks" return f"{int(day_diff / 7)} weeks"
if day_diff < 365: if day_diff < 365:
return str(int(day_diff / 30)) + " months" return f"{int(day_diff / 30)} months"
return str(int(day_diff / 365)) + " years" return f"{int(day_diff / 365)} years"
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -49,7 +49,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len: 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: try:
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e: except Exception as e:
@ -70,7 +70,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
if not RNS.Transport.has_path(destination_hash): if not RNS.Transport.has_path(destination_hash):
RNS.Transport.request_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() sys.stdout.flush()
_timeout = time.time() + (timeout or DEFAULT_TIMEOUT+reticulum.get_first_hop_timeout(destination_hash)) _timeout = time.time() + (timeout or DEFAULT_TIMEOUT+reticulum.get_first_hop_timeout(destination_hash))
@ -78,7 +78,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
syms = "⢄⢂⢁⡁⡈⡐⡠" syms = "⢄⢂⢁⡁⡈⡐⡠"
while not RNS.Transport.has_path(destination_hash) and not time.time() > _timeout: while not RNS.Transport.has_path(destination_hash) and not time.time() > _timeout:
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) 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 = RNS.Packet(request_destination, os.urandom(size))
probe.pack() probe.pack()
except OSError: 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) exit(3)
receipt = probe.send() receipt = probe.send()
@ -115,19 +115,19 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
if more_output: if more_output:
nhd = reticulum.get_next_hop(destination_hash) nhd = reticulum.get_next_hop(destination_hash)
via_str = " via "+RNS.prettyhexrep(nhd) if nhd != None else "" via_str = f" 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 "" 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 more = via_str+if_str
else: else:
more = "" 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)) _timeout = time.time() + (timeout or DEFAULT_TIMEOUT+reticulum.get_first_hop_timeout(destination_hash))
i = 0 i = 0
while receipt.status == RNS.PacketReceipt.SENT and not time.time() > _timeout: while receipt.status == RNS.PacketReceipt.SENT and not time.time() > _timeout:
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) 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() rtt = receipt.get_rtt()
if (rtt >= 1): if (rtt >= 1):
rtt = round(rtt, 3) rtt = round(rtt, 3)
rttstring = str(rtt)+" seconds" rttstring = f"{rtt} seconds"
else: else:
rtt = round(rtt*1000, 3) rtt = round(rtt*1000, 3)
rttstring = str(rtt)+" milliseconds" rttstring = f"{rtt} milliseconds"
reception_stats = "" reception_stats = ""
if reticulum.is_connected_to_shared_instance: 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) reception_q = reticulum.get_packet_q(receipt.proof_packet.packet_hash)
if reception_rssi != None: if reception_rssi != None:
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += " [SNR "+str(reception_snr)+" dB]" reception_stats += f" [SNR {reception_snr} dB]"
if reception_q != None: if reception_q != None:
reception_stats += " [Link Quality "+str(reception_q)+"%]" reception_stats += f" [Link Quality {reception_q}%]"
else: else:
if receipt.proof_packet != None: if receipt.proof_packet != None:
if receipt.proof_packet.rssi != 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: 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( print(
"Valid reply from "+ f"Valid reply from {RNS.prettyhexrep(receipt.destination.hash)}\nRound-trip time is {rttstring} over {hops} hop{ms}{reception_stats}\n"
RNS.prettyhexrep(receipt.destination.hash)+
"\nRound-trip time is "+rttstring+
" over "+str(hops)+" hop"+ms+
reception_stats+"\n"
) )
else: 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("-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("-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("-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("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) parser.add_argument("destination_hash", nargs="?", default=None, help="hexadecimal hash of the destination", type=str)

View File

@ -40,9 +40,9 @@ def program_setup(configdir, verbosity = 0, quietness = 0, service = False):
reticulum = RNS.Reticulum(configdir=configdir, verbosity=targetverbosity, logdest=targetlogdest) reticulum = RNS.Reticulum(configdir=configdir, verbosity=targetverbosity, logdest=targetlogdest)
if reticulum.is_connected_to_shared_instance: 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: 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: while True:
time.sleep(1) time.sleep(1)
@ -55,7 +55,7 @@ def main():
parser.add_argument('-q', '--quiet', action='count', default=0) 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('-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("--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() args = parser.parse_args()

View File

@ -42,12 +42,12 @@ def size_str(num, suffix='B'):
for unit in units: for unit in units:
if abs(num) < 1000.0: if abs(num) < 1000.0:
if unit == "": if unit == "":
return "%.0f %s%s" % (num, unit, suffix) return f"{num:.0f} {unit}{suffix}"
else: else:
return "%.2f %s%s" % (num, unit, suffix) return f"{num:.2f} {unit}{suffix}"
num /= 1000.0 num /= 1000.0
return "%.2f%s%s" % (num, last_unit, suffix) return f"{num:.2f}{last_unit}{suffix}"
request_result = None request_result = None
request_concluded = False request_concluded = False
@ -144,7 +144,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(remote) != dest_len: 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: try:
identity_hash = bytes.fromhex(remote) identity_hash = bytes.fromhex(remote)
destination_hash = RNS.Destination.hash_from_name_and_identity("rnstransport.remote.management", identity_hash) 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: if "ifac_netname" in ifstat and ifstat["ifac_netname"] != None:
print(" Network : {nn}".format(nn=ifstat["ifac_netname"])) print(" Network : {nn}".format(nn=ifstat["ifac_netname"]))
print(" Status : {ss}".format(ss=ss)) print(f" Status : {ss}")
if clients != None and clients_string != "": if clients != None and clients_string != "":
print(" "+clients_string) print(" "+clients_string)
if not (name.startswith("Shared Instance[") or name.startswith("TCPInterface[Client") or name.startswith("LocalInterface[")): 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: if "bitrate" in ifstat and ifstat["bitrate"] != None:
print(" Rate : {ss}".format(ss=speed_str(ifstat["bitrate"]))) print(" Rate : {ss}".format(ss=speed_str(ifstat["bitrate"])))
@ -489,10 +489,10 @@ def speed_str(num, suffix='bps'):
for unit in units: for unit in units:
if abs(num) < 1000.0: if abs(num) < 1000.0:
return "%3.2f %s%s" % (num, unit, suffix) return f"{num:3.2f} {unit}{suffix}"
num /= 1000.0 num /= 1000.0
return "%.2f %s%s" % (num, last_unit, suffix) return f"{num:.2f} {last_unit}{suffix}"
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -42,7 +42,7 @@ allowed_identity_hashes = []
def prepare_identity(identity_path): def prepare_identity(identity_path):
global identity global identity
if identity_path == None: 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): if os.path.isfile(identity_path):
identity = RNS.Identity.from_file(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") destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "execute")
if print_identity: if print_identity:
print("Identity : "+str(identity)) print(f"Identity : {identity}")
print("Listening on : "+RNS.prettyhexrep(destination.hash)) print(f"Listening on : {RNS.prettyhexrep(destination.hash)}")
exit(0) exit(0)
if disable_auth: if disable_auth:
@ -74,7 +74,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(a) != dest_len: 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: try:
destination_hash = bytes.fromhex(a) destination_hash = bytes.fromhex(a)
allowed_identity_hashes.append(destination_hash) 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, 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: if not disable_announce:
destination.announce() destination.announce()
@ -114,16 +114,16 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed
def command_link_established(link): def command_link_established(link):
link.set_remote_identified_callback(initiator_identified) link.set_remote_identified_callback(initiator_identified)
link.set_link_closed_callback(command_link_closed) 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): def command_link_closed(link):
RNS.log("Command link "+str(link)+" closed") RNS.log(f"Command link {link} closed")
def initiator_identified(link, identity): def initiator_identified(link, identity):
global allow_all 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: 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() link.teardown()
def execute_received_command(path, data, request_id, remote_identity, requested_at): 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 stdin = data[4] # Data passed to stdin
if remote_identity != None: 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: else:
RNS.log("Executing command ["+command+"] for unknown requestor") RNS.log(f"Executing command [{command}] for unknown requestor")
result = [ result = [
False, # 0: Command was executed False, # 0: Command was executed
@ -178,7 +178,7 @@ def execute_received_command(path, data, request_id, remote_identity, requested_
pass pass
if timeout != None and time.time() > result[6]+timeout: 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.terminate()
process.wait() process.wait()
if process.poll() != None: if process.poll() != None:
@ -219,9 +219,9 @@ def execute_received_command(path, data, request_id, remote_identity, requested_
return result return result
if remote_identity != None: 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: 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 return result
@ -231,14 +231,14 @@ def spin(until=None, msg=None, timeout=None):
if timeout != None: if timeout != None:
timeout = time.time()+timeout timeout = time.time()+timeout
print(msg+" ", end=" ") print(f"{msg} ", end=" ")
while (timeout == None or time.time()<timeout) and not until(): while (timeout == None or time.time()<timeout) and not until():
time.sleep(0.1) time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="") print(f"\b\b{syms[i]} ", end="")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
print("\r"+" "*len(msg)+" \r", end="") print(f"\r{' ' * len(msg)} \r", end="")
if timeout != None and time.time() > timeout: if timeout != None and time.time() > timeout:
return False return False
@ -259,8 +259,8 @@ def spin_stat(until=None, timeout=None):
time.sleep(0.1) time.sleep(0.1)
prg = current_progress prg = current_progress
percent = round(prg * 100.0, 1) 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" stat_str = f"{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=" ") print(f'\r \rReceiving result {syms[i]} {stat_str}', end=" ")
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
@ -303,7 +303,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
try: try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2 dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination) != dest_len: 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: try:
destination_hash = bytes.fromhex(destination) destination_hash = bytes.fromhex(destination)
except Exception as e: 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): if not RNS.Transport.has_path(destination_hash):
RNS.Transport.request_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") print("Path not found")
exit(242) exit(242)
@ -339,8 +339,8 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
link = RNS.Link(listener_destination) link = RNS.Link(listener_destination)
link.did_identify = False link.did_identify = False
if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg="Establishing link with "+RNS.prettyhexrep(destination_hash), timeout=timeout): if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg=f"Establishing link with {RNS.prettyhexrep(destination_hash)}", timeout=timeout):
print("Could not establish link with "+RNS.prettyhexrep(destination_hash)) print(f"Could not establish link with {RNS.prettyhexrep(destination_hash)}")
exit(243) exit(243)
if not noid and not link.did_identify: 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 ---") print("\n--- End of remote output, rnx done ---")
if started != None and concluded != None: if started != None and concluded != None:
cmd_duration = round(concluded - started, 3) 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 total_size = request_receipt.response_size
if request_receipt.request_size != None: if request_receipt.request_size != None:
@ -453,27 +453,27 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
if transfer_duration == 1: if transfer_duration == 1:
tdstr = " in 1 second" tdstr = " in 1 second"
elif transfer_duration < 10: elif transfer_duration < 10:
tdstr = " in "+str(transfer_duration)+" seconds" tdstr = f" in {transfer_duration} seconds"
else: 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 outlen != None and stdout != None:
if len(stdout) < outlen: if len(stdout) < outlen:
tstr = ", "+str(len(stdout))+" bytes displayed" tstr = f", {len(stdout)} bytes displayed"
else: else:
tstr = "" 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 errlen != None and stderr != None:
if len(stderr) < errlen: if len(stderr) < errlen:
tstr = ", "+str(len(stderr))+" bytes displayed" tstr = f", {len(stderr)} bytes displayed"
else: else:
tstr = "" tstr = ""
print("Remote wrote "+str(errlen)+" bytes to stderr"+tstr) print(f"Remote wrote {errlen} bytes to stderr{tstr}")
else: else:
if stdout != None and len(stdout) > 0: if stdout != None and len(stdout) > 0:
@ -487,9 +487,9 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
sys.stderr.flush() sys.stderr.flush()
print("\nOutput truncated before being returned:") print("\nOutput truncated before being returned:")
if len(stdout) != 0 and len(stdout) < outlen: 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: 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: else:
print("Remote could not execute command") print("Remote could not execute command")
if interactive: 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("--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("--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("--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() args = parser.parse_args()
@ -593,7 +593,7 @@ def main():
while True: while True:
try: try:
cstr = str(code) if code and code != 0 else "" cstr = str(code) if code and code != 0 else ""
prompt = cstr+"> " prompt = f"{cstr}> "
print(prompt,end="") print(prompt,end="")
# cmdbuf = b"" # cmdbuf = b""
@ -661,12 +661,12 @@ def size_str(num, suffix='B'):
for unit in units: for unit in units:
if abs(num) < 1000.0: if abs(num) < 1000.0:
if unit == "": if unit == "":
return "%.0f %s%s" % (num, unit, suffix) return f"{num:.0f} {unit}{suffix}"
else: else:
return "%.2f %s%s" % (num, unit, suffix) return f"{num:.2f} {unit}{suffix}"
num /= 1000.0 num /= 1000.0
return "%.2f%s%s" % (num, last_unit, suffix) return f"{num:.2f}{last_unit}{suffix}"
def pretty_time(time, verbose=False): def pretty_time(time, verbose=False):
days = int(time // (24 * 3600)) days = int(time // (24 * 3600))
@ -684,16 +684,16 @@ def pretty_time(time, verbose=False):
components = [] components = []
if days > 0: 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: 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: 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: 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 i = 0
tstr = "" tstr = ""

View File

@ -147,7 +147,7 @@ def rand():
def trace_exception(e): def trace_exception(e):
import traceback import traceback
exception_info = "".join(traceback.TracebackException.from_exception(e).format()) 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) log(exception_info, LOG_ERROR)
def hexrep(data, delimit=True): def hexrep(data, delimit=True):
@ -159,12 +159,12 @@ def hexrep(data, delimit=True):
delimiter = ":" delimiter = ":"
if not delimit: if not delimit:
delimiter = "" delimiter = ""
hexrep = delimiter.join("{:02x}".format(c) for c in data) hexrep = delimiter.join(f"{c:02x}" for c in data)
return hexrep return hexrep
def prettyhexrep(data): def prettyhexrep(data):
delimiter = "" delimiter = ""
hexrep = "<"+delimiter.join("{:02x}".format(c) for c in data)+">" hexrep = "<"+delimiter.join(f"{c:02x}" for c in data)+">"
return hexrep return hexrep
def prettyspeed(num, suffix="b"): def prettyspeed(num, suffix="b"):
@ -182,12 +182,12 @@ def prettysize(num, suffix='B'):
for unit in units: for unit in units:
if abs(num) < 1000.0: if abs(num) < 1000.0:
if unit == "": if unit == "":
return "%.0f %s%s" % (num, unit, suffix) return f"{num:.0f} {unit}{suffix}"
else: else:
return "%.2f %s%s" % (num, unit, suffix) return f"{num:.2f} {unit}{suffix}"
num /= 1000.0 num /= 1000.0
return "%.2f%s%s" % (num, last_unit, suffix) return f"{num:.2f}{last_unit}{suffix}"
def prettyfrequency(hz, suffix="Hz"): def prettyfrequency(hz, suffix="Hz"):
num = hz*1e6 num = hz*1e6
@ -196,10 +196,10 @@ def prettyfrequency(hz, suffix="Hz"):
for unit in units: for unit in units:
if abs(num) < 1000.0: if abs(num) < 1000.0:
return "%.2f %s%s" % (num, unit, suffix) return f"{num:.2f} {unit}{suffix}"
num /= 1000.0 num /= 1000.0
return "%.2f%s%s" % (num, last_unit, suffix) return f"{num:.2f}{last_unit}{suffix}"
def prettydistance(m, suffix="m"): def prettydistance(m, suffix="m"):
num = m*1e6 num = m*1e6
@ -212,10 +212,10 @@ def prettydistance(m, suffix="m"):
if unit == "c": divisor = 100 if unit == "c": divisor = 100
if abs(num) < divisor: if abs(num) < divisor:
return "%.2f %s%s" % (num, unit, suffix) return f"{num:.2f} {unit}{suffix}"
num /= divisor num /= divisor
return "%.2f %s%s" % (num, last_unit, suffix) return f"{num:.2f} {last_unit}{suffix}"
def prettytime(time, verbose=False, compact=False): def prettytime(time, verbose=False, compact=False):
days = int(time // (24 * 3600)) days = int(time // (24 * 3600))

View File

@ -1,5 +1,5 @@
import os import os
import glob 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')] __all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]

View File

@ -129,7 +129,7 @@ def getObj(s):
global compiler global compiler
if compiler is None: if compiler is None:
import compiler import compiler
s = "a=" + s s = f"a={s}"
p = compiler.parse(s) p = compiler.parse(s)
return p.getChildren()[1].getChildren()[0].getChildren()[1] return p.getChildren()[1].getChildren()[0].getChildren()[1]
@ -138,7 +138,7 @@ class UnknownType(Exception):
pass pass
class Builder(object): class Builder:
def build(self, o): def build(self, o):
if m is None: if m is None:
@ -261,7 +261,7 @@ class InterpolationLoopError(InterpolationError):
def __init__(self, option): def __init__(self, option):
InterpolationError.__init__( InterpolationError.__init__(
self, self,
'interpolation loop detected in value "%s".' % option) f'interpolation loop detected in value "{option}".')
class RepeatSectionError(ConfigObjError): class RepeatSectionError(ConfigObjError):
@ -274,7 +274,7 @@ class RepeatSectionError(ConfigObjError):
class MissingInterpolationOption(InterpolationError): class MissingInterpolationOption(InterpolationError):
"""A value specified for interpolation was missing.""" """A value specified for interpolation was missing."""
def __init__(self, option): def __init__(self, option):
msg = 'missing option "%s" in interpolation.' % option msg = f'missing option "{option}" in interpolation.'
InterpolationError.__init__(self, msg) InterpolationError.__init__(self, msg)
@ -283,7 +283,7 @@ class UnreprError(ConfigObjError):
class InterpolationEngine(object): class InterpolationEngine:
""" """
A helper class to help perform string interpolation. A helper class to help perform string interpolation.
@ -336,7 +336,7 @@ class InterpolationEngine(object):
replacement = recursive_interpolate(k, v, s, backtrail) replacement = recursive_interpolate(k, v, s, backtrail)
# Replace the matched string with its final value # Replace the matched string with its final value
start, end = match.span() start, end = match.span()
value = ''.join((value[:start], replacement, value[end:])) value = f"{value[:start]}{replacement}{value[end:]}"
new_search_start = start + len(replacement) new_search_start = start + len(replacement)
# Pick up the next interpolation key, if any, for next time # Pick up the next interpolation key, if any, for next time
# through the while loop # through the while loop
@ -553,11 +553,11 @@ class Section(dict):
"""Fetch the item and do string interpolation.""" """Fetch the item and do string interpolation."""
val = dict.__getitem__(self, key) val = dict.__getitem__(self, key)
if self.main.interpolation: if self.main.interpolation:
if isinstance(val, six.string_types): if isinstance(val, str):
return self._interpolate(key, val) return self._interpolate(key, val)
if isinstance(val, list): if isinstance(val, list):
def _check(entry): def _check(entry):
if isinstance(entry, six.string_types): if isinstance(entry, str):
return self._interpolate(key, entry) return self._interpolate(key, entry)
return entry return entry
new = [_check(entry) for entry in val] 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 ``unrepr`` must be set when setting a value to a dictionary, without
creating a new sub-section. creating a new sub-section.
""" """
if not isinstance(key, six.string_types): if not isinstance(key, str):
raise ValueError('The key "%s" is not a string.' % key) raise ValueError(f'The key "{key}" is not a string.')
# add the comment # add the comment
if key not in self.comments: if key not in self.comments:
@ -614,14 +614,14 @@ class Section(dict):
if key not in self: if key not in self:
self.scalars.append(key) self.scalars.append(key)
if not self.main.stringify: if not self.main.stringify:
if isinstance(value, six.string_types): if isinstance(value, str):
pass pass
elif isinstance(value, (list, tuple)): elif isinstance(value, (list, tuple)):
for entry in value: for entry in value:
if not isinstance(entry, six.string_types): if not isinstance(entry, str):
raise TypeError('Value is not a string "%s".' % entry) raise TypeError(f'Value is not a string "{entry}".')
else: else:
raise TypeError('Value is not a string "%s".' % value) raise TypeError(f'Value is not a string "{value}".')
dict.__setitem__(self, key, value) dict.__setitem__(self, key, value)
@ -728,7 +728,7 @@ class Section(dict):
def iterkeys(self): def iterkeys(self):
"""D.iterkeys() -> an iterator over the keys of D""" """D.iterkeys() -> an iterator over the keys of D"""
return iter((self.scalars + self.sections)) return iter(self.scalars + self.sections)
__iter__ = iterkeys __iter__ = iterkeys
@ -745,7 +745,7 @@ class Section(dict):
return self[key] return self[key]
except MissingInterpolationOption: except MissingInterpolationOption:
return dict.__getitem__(self, key) 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)]) for key in (self.scalars + self.sections)])
__str__ = __repr__ __str__ = __repr__
@ -823,7 +823,7 @@ class Section(dict):
elif oldkey in self.sections: elif oldkey in self.sections:
the_list = self.sections the_list = self.sections
else: else:
raise KeyError('Key "%s" not found.' % oldkey) raise KeyError(f'Key "{oldkey}" not found.')
pos = the_list.index(oldkey) pos = the_list.index(oldkey)
# #
val = self[oldkey] val = self[oldkey]
@ -959,13 +959,13 @@ class Section(dict):
return False return False
else: else:
try: try:
if not isinstance(val, six.string_types): if not isinstance(val, str):
# TODO: Why do we raise a KeyError here? # TODO: Why do we raise a KeyError here?
raise KeyError() raise KeyError()
else: else:
return self.main._bools[val.lower()] return self.main._bools[val.lower()]
except KeyError: 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): def as_int(self, key):
@ -1210,7 +1210,7 @@ class ConfigObj(Section):
# TODO: check the values too. # TODO: check the values too.
for entry in options: for entry in options:
if entry not in OPTION_DEFAULTS: 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()): for entry, value in list(OPTION_DEFAULTS.items()):
if entry not in options: if entry not in options:
options[entry] = value options[entry] = value
@ -1230,14 +1230,14 @@ class ConfigObj(Section):
def _load(self, infile, configspec): def _load(self, infile, configspec):
if isinstance(infile, six.string_types): if isinstance(infile, str):
self.filename = infile self.filename = infile
if os.path.isfile(infile): if os.path.isfile(infile):
with open(infile, 'rb') as h: with open(infile, 'rb') as h:
content = h.readlines() or [] content = h.readlines() or []
elif self.file_error: elif self.file_error:
# raise an error if the file doesn't exist # 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: else:
# file doesn't already exist # file doesn't already exist
if self.create_empty: if self.create_empty:
@ -1298,15 +1298,15 @@ class ConfigObj(Section):
break break
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] content = [line.rstrip('\r\n') for line in content]
self._parse(content) self._parse(content)
# if we had any errors, now is the time to raise them # if we had any errors, now is the time to raise them
if self._errors: 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: 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) error = ConfigObjError(msg)
else: else:
error = self._errors[0] error = self._errors[0]
@ -1363,9 +1363,7 @@ class ConfigObj(Section):
return self[key] return self[key]
except MissingInterpolationOption: except MissingInterpolationOption:
return dict.__getitem__(self, key) return dict.__getitem__(self, key)
return ('ConfigObj({%s})' % return ('ConfigObj({%s})' % ', '.join([f'{key!r}: {_getval(key)!r}' for key in (self.scalars + self.sections)]))
', '.join([('%s: %s' % (repr(key), repr(_getval(key))))
for key in (self.scalars + self.sections)]))
def _handle_bom(self, infile): def _handle_bom(self, infile):
@ -1403,7 +1401,7 @@ class ConfigObj(Section):
else: else:
line = infile line = infile
if isinstance(line, six.text_type): if isinstance(line, str):
# it's already decoded and there's no need to do anything # it's already decoded and there's no need to do anything
# else, just use the _decode utility method to handle # else, just use the _decode utility method to handle
# listifying appropriately # listifying appropriately
@ -1448,7 +1446,7 @@ class ConfigObj(Section):
# No encoding specified - so we need to check for UTF8/UTF16 # No encoding specified - so we need to check for UTF8/UTF16
for BOM, (encoding, final_encoding) in list(BOMS.items()): 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 # didn't specify a BOM, or it's not a bytestring
continue continue
else: else:
@ -1464,9 +1462,9 @@ class ConfigObj(Section):
else: else:
infile = newline infile = newline
# UTF-8 # UTF-8
if isinstance(infile, six.text_type): if isinstance(infile, str):
return infile.splitlines(True) return infile.splitlines(True)
elif isinstance(infile, six.binary_type): elif isinstance(infile, bytes):
return infile.decode('utf-8').splitlines(True) return infile.decode('utf-8').splitlines(True)
else: else:
return self._decode(infile, 'utf-8') return self._decode(infile, 'utf-8')
@ -1479,7 +1477,7 @@ class ConfigObj(Section):
# returning a bytestring is fine # returning a bytestring is fine
return self._decode(infile, None) return self._decode(infile, None)
# No BOM discovered and no encoding specified, default to UTF-8 # 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) return infile.decode('utf-8').splitlines(True)
else: else:
return self._decode(infile, 'utf-8') return self._decode(infile, 'utf-8')
@ -1487,7 +1485,7 @@ class ConfigObj(Section):
def _a_to_u(self, aString): def _a_to_u(self, aString):
"""Decode ASCII strings to unicode if a self.encoding is specified.""" """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) return aString.decode(self.encoding)
else: else:
return aString return aString
@ -1499,9 +1497,9 @@ class ConfigObj(Section):
if is a string, it also needs converting to a list. 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) return infile.splitlines(True)
if isinstance(infile, six.binary_type): if isinstance(infile, bytes):
# NOTE: Could raise a ``UnicodeDecodeError`` # NOTE: Could raise a ``UnicodeDecodeError``
if encoding: if encoding:
return infile.decode(encoding).splitlines(True) return infile.decode(encoding).splitlines(True)
@ -1510,7 +1508,7 @@ class ConfigObj(Section):
if encoding: if encoding:
for i, line in enumerate(infile): 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: The isinstance test here handles mixed lists of unicode/string
# NOTE: But the decode will break on any non-string values # NOTE: But the decode will break on any non-string values
# NOTE: Or could raise a ``UnicodeDecodeError`` # NOTE: Or could raise a ``UnicodeDecodeError``
@ -1520,7 +1518,7 @@ class ConfigObj(Section):
def _decode_element(self, line): def _decode_element(self, line):
"""Decode element to unicode if necessary.""" """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) return line.decode(self.default_encoding)
else: else:
return line return line
@ -1532,7 +1530,7 @@ class ConfigObj(Section):
Used by ``stringify`` within validate, to turn non-string values Used by ``stringify`` within validate, to turn non-string values
into strings. into strings.
""" """
if not isinstance(value, six.string_types): if not isinstance(value, str):
# intentially 'str' because it's just whatever the "normal" # intentially 'str' because it's just whatever the "normal"
# string type is for the python version we're dealing with # string type is for the python version we're dealing with
return str(value) return str(value)
@ -1627,7 +1625,7 @@ class ConfigObj(Section):
mat = self._keyword.match(line) mat = self._keyword.match(line)
if mat is None: if mat is None:
self._handle_error( 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) ParseError, infile, cur_index)
else: else:
# is a keyword value # is a keyword value
@ -1735,7 +1733,7 @@ class ConfigObj(Section):
""" """
line = infile[cur_index] line = infile[cur_index]
cur_index += 1 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) error = ErrorClass(message, cur_index, line)
if self.raise_errors: if self.raise_errors:
# raise the error - parsing stops here # raise the error - parsing stops here
@ -1783,16 +1781,16 @@ class ConfigObj(Section):
if not value: if not value:
return ',' return ','
elif len(value) == 1: 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) return ', '.join([self._quote(val, multiline=False)
for val in value]) for val in value])
if not isinstance(value, six.string_types): if not isinstance(value, str):
if self.stringify: if self.stringify:
# intentially 'str' because it's just whatever the "normal" # intentially 'str' because it's just whatever the "normal"
# string type is for the python version we're dealing with # string type is for the python version we're dealing with
value = str(value) value = str(value)
else: else:
raise TypeError('Value "%s" is not a string.' % value) raise TypeError(f'Value "{value}" is not a string.')
if not value: if not value:
return '""' return '""'
@ -1809,7 +1807,7 @@ class ConfigObj(Section):
# for normal values either single or double quotes will do # for normal values either single or double quotes will do
elif '\n' in value: elif '\n' in value:
# will only happen if multiline is off - e.g. '\n' in key # 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 elif ((value[0] not in wspace_plus) and
(value[-1] not in wspace_plus) and (value[-1] not in wspace_plus) and
(',' not in value)): (',' not in value)):
@ -1828,7 +1826,7 @@ class ConfigObj(Section):
def _get_single_quote(self, value): def _get_single_quote(self, value):
if ("'" in value) and ('"' in 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: elif '"' in value:
quot = squot quot = squot
else: else:
@ -1838,7 +1836,7 @@ class ConfigObj(Section):
def _get_triple_quote(self, value): def _get_triple_quote(self, value):
if (value.find('"""') != -1) and (value.find("'''") != -1): 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: if value.find('"""') == -1:
quot = tdquot quot = tdquot
else: else:
@ -1943,9 +1941,9 @@ class ConfigObj(Section):
except ConfigObjError as e: except ConfigObjError as e:
# FIXME: Should these errors have a reference # FIXME: Should these errors have a reference
# to the already parsed ConfigObj ? # to the already parsed ConfigObj ?
raise ConfigspecError('Parsing configspec failed: %s' % e) raise ConfigspecError(f'Parsing configspec failed: {e}')
except IOError as e: except OSError as e:
raise IOError('Reading configspec failed: %s' % e) raise OSError(f'Reading configspec failed: {e}')
self.configspec = configspec self.configspec = configspec
@ -1986,20 +1984,12 @@ class ConfigObj(Section):
val = self._decode_element(self._quote(this_entry)) val = self._decode_element(self._quote(this_entry))
else: else:
val = repr(this_entry) val = repr(this_entry)
return '%s%s%s%s%s' % (indent_string, return f"{indent_string}{self._decode_element(self._quote(entry, multiline=False))}{self._a_to_u(' = ')}{val}{self._decode_element(comment)}"
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): def _write_marker(self, indent_string, depth, entry, comment):
"""Write a section marker line""" """Write a section marker line"""
return '%s%s%s%s%s' % (indent_string, 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)}"
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): def _handle_comment(self, comment):
@ -2111,7 +2101,7 @@ class ConfigObj(Section):
if not output.endswith(newline): if not output.endswith(newline):
output += newline output += newline
if isinstance(output, six.binary_type): if isinstance(output, bytes):
output_bytes = output output_bytes = output
else: else:
output_bytes = output.encode(self.encoding or output_bytes = output.encode(self.encoding or
@ -2284,7 +2274,7 @@ class ConfigObj(Section):
out[entry] = False out[entry] = False
else: else:
ret_false = False 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) out[entry] = validator.baseErrorClass(msg)
for entry in incorrect_sections: for entry in incorrect_sections:
ret_true = False ret_true = False
@ -2292,7 +2282,7 @@ class ConfigObj(Section):
out[entry] = False out[entry] = False
else: else:
ret_false = False 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) out[entry] = validator.baseErrorClass(msg)
# Missing sections will have been created as empty ones when the # 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 This method raises a ``ReloadError`` if the ConfigObj doesn't have
a filename attribute pointing to a file. a filename attribute pointing to a file.
""" """
if not isinstance(self.filename, six.string_types): if not isinstance(self.filename, str):
raise ReloadError() raise ReloadError()
filename = self.filename filename = self.filename
@ -2372,7 +2362,7 @@ class ConfigObj(Section):
class SimpleVal(object): class SimpleVal:
""" """
A simple validator. A simple validator.
Can be used to check that all members expected are present. Can be used to check that all members expected are present.

View File

@ -11,7 +11,7 @@ def parse_reply(data):
try: try:
msg = sam.Message(data.decode().strip()) msg = sam.Message(data.decode().strip())
logger.debug("SAM reply: "+str(msg)) logger.debug(f"SAM reply: {msg}")
except: except:
raise ConnectionAbortedError("Invalid SAM response") 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 :param options: (optional) A dict object with i2cp options
:return: A (reader, writer) pair :return: A (reader, writer) pair
""" """
logger.debug("Creating session {}".format(session_name)) logger.debug(f"Creating session {session_name}")
if destination: if destination:
if type(destination) == sam.Destination: if type(destination) == sam.Destination:
destination = destination destination = destination
@ -101,7 +101,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
else: else:
dest_string = sam.TRANSIENT_DESTINATION 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) reader, writer = await get_sam_socket(sam_address, loop)
writer.write(sam.session_create( writer.write(sam.session_create(
@ -113,7 +113,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
destination = sam.Destination( destination = sam.Destination(
reply["DESTINATION"], has_private_key=True) reply["DESTINATION"], has_private_key=True)
logger.debug(destination.base32) logger.debug(destination.base32)
logger.debug("Session created {}".format(session_name)) logger.debug(f"Session created {session_name}")
return (reader, writer) return (reader, writer)
else: else:
writer.close() writer.close()
@ -129,7 +129,7 @@ async def stream_connect(session_name, destination,
:param loop: (optional) Event loop instance :param loop: (optional) Event loop instance
:return: A (reader, writer) pair :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"): if isinstance(destination, str) and not destination.endswith(".i2p"):
destination = sam.Destination(destination) destination = sam.Destination(destination)
elif isinstance(destination, str): elif isinstance(destination, str):
@ -140,7 +140,7 @@ async def stream_connect(session_name, destination,
silent="false")) silent="false"))
reply = parse_reply(await reader.readline()) reply = parse_reply(await reader.readline())
if reply.ok: if reply.ok:
logger.debug("Stream connected {}".format(session_name)) logger.debug(f"Stream connected {session_name}")
return (reader, writer) return (reader, writer)
else: else:
writer.close() writer.close()

View File

@ -23,7 +23,7 @@ TRANSIENT_DESTINATION = "TRANSIENT"
VALID_BASE32_ADDRESS = re.compile(r"^([a-zA-Z0-9]{52}).b32.i2p$") 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})$") VALID_BASE64_ADDRESS = re.compile(r"^([a-zA-Z0-9-~=]{516,528})$")
class Message(object): class Message:
"""Parse SAM message to an object""" """Parse SAM message to an object"""
def __init__(self, s): def __init__(self, s):
self.opts = {} self.opts = {}
@ -51,34 +51,30 @@ class Message(object):
# SAM request messages # SAM request messages
def hello(min_version, max_version): def hello(min_version, max_version):
return "HELLO VERSION MIN={} MAX={}\n".format(min_version, return f"HELLO VERSION MIN={min_version} MAX={max_version}\n".encode()
max_version).encode()
def session_create(style, session_id, destination, options=""): def session_create(style, session_id, destination, options=""):
return "SESSION CREATE STYLE={} ID={} DESTINATION={} {}\n".format( return f"SESSION CREATE STYLE={style} ID={session_id} DESTINATION={destination} {options}\n".encode()
style, session_id, destination, options).encode()
def stream_connect(session_id, destination, silent="false"): def stream_connect(session_id, destination, silent="false"):
return "STREAM CONNECT ID={} DESTINATION={} SILENT={}\n".format( return f"STREAM CONNECT ID={session_id} DESTINATION={destination} SILENT={silent}\n".encode()
session_id, destination, silent).encode()
def stream_accept(session_id, silent="false"): 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=""): def stream_forward(session_id, port, options=""):
return "STREAM FORWARD ID={} PORT={} {}\n".format( return f"STREAM FORWARD ID={session_id} PORT={port} {options}\n".encode()
session_id, port, options).encode()
def naming_lookup(name): 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): 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 """I2P destination
https://geti2p.net/spec/common-structures#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): def __init__(self, data=None, path=None, has_private_key=False):
#: Binary destination #: Binary destination
self.data = bytes() self.data = b''
#: Base64 encoded destination #: Base64 encoded destination
self.base64 = "" self.base64 = ""
#: :class:`RNS.vendor.i2plib.PrivateKey` instance or None #: :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) self.base64 = data if type(data) == str else i2p_b64encode(data)
def __repr__(self): def __repr__(self):
return "<Destination: {}>".format(self.base32) return f"<Destination: {self.base32}>"
@property @property
def base32(self): def base32(self):
@ -131,7 +127,7 @@ class Destination(object):
desthash = sha256(self.data).digest() desthash = sha256(self.data).digest()
return b32encode(desthash).decode()[:52].lower() return b32encode(desthash).decode()[:52].lower()
class PrivateKey(object): class PrivateKey:
"""I2P private key """I2P private key
https://geti2p.net/spec/common-structures#keysandcert https://geti2p.net/spec/common-structures#keysandcert

View File

@ -18,7 +18,7 @@ async def proxy_data(reader, writer):
break break
writer.write(data) writer.write(data)
except Exception as e: except Exception as e:
logger.debug('proxy_data_task exception {}'.format(e)) logger.debug(f'proxy_data_task exception {e}')
finally: finally:
try: try:
writer.close() writer.close()
@ -26,7 +26,7 @@ async def proxy_data(reader, writer):
pass pass
logger.debug('close connection') logger.debug('close connection')
class I2PTunnel(object): class I2PTunnel:
"""Base I2P Tunnel object, not to be used directly """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.
@ -141,8 +141,7 @@ class ServerTunnel(I2PTunnel):
# data and dest may come in one chunk # 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()) remote_destination = sam.Destination(dest.decode())
logger.debug("{} client connected: {}.b32.i2p".format( logger.debug(f"{self.session_name} client connected: {remote_destination.base32}.b32.i2p")
self.session_name, remote_destination.base32))
except Exception as e: except Exception as e:
self.status["exception"] = e self.status["exception"] = e

View File

@ -38,5 +38,5 @@ def generate_session_id(length=6):
"""Generate random session id""" """Generate random session id"""
rand = random.SystemRandom() rand = random.SystemRandom()
sid = [rand.choice(string.ascii_letters) for _ in range(length)] sid = [rand.choice(string.ascii_letters) for _ in range(length)]
return "reticulum-" + "".join(sid) return f"reticulum-{''.join(sid)}"

View File

@ -28,6 +28,6 @@ if os.name == "nt":
elif os.name == "posix": elif os.name == "posix":
from RNS.vendor.ifaddr._posix import get_adapters from RNS.vendor.ifaddr._posix import get_adapters
else: else:
raise RuntimeError("Unsupported Operating System: %s" % os.name) raise RuntimeError(f"Unsupported Operating System: {os.name}")
__all__ = ['Adapter', 'IP', 'get_adapters'] __all__ = ['Adapter', 'IP', 'get_adapters']

View File

@ -79,7 +79,7 @@ def get_adapters(include_unconfigured: bool = False) -> Iterable[shared.Adapter]
prefixlen = shared.ipv6_prefixlength(ipaddress.IPv6Address(netmaskStr)) prefixlen = shared.ipv6_prefixlength(ipaddress.IPv6Address(netmaskStr))
else: else:
assert netmask is not None, f'sockaddr_to_ip({addr[0].ifa_netmask}) returned None' 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 prefixlen = ipaddress.IPv4Network(netmaskStr).prefixlen
ip = shared.IP(ip_addr, prefixlen, name) ip = shared.IP(ip_addr, prefixlen, name)
add_ip(name, ip) add_ip(name, ip)

View File

@ -26,7 +26,7 @@ import platform
from typing import List, Optional, Tuple, Union from typing import List, Optional, Tuple, Union
class Adapter(object): class Adapter:
""" """
Represents a network interface device controller (NIC), such as a Represents a network interface device controller (NIC), such as a
network card. An adapter can have multiple IPs. network card. An adapter can have multiple IPs.
@ -58,9 +58,7 @@ class Adapter(object):
self.index = index self.index = index
def __repr__(self) -> str: def __repr__(self) -> str:
return "Adapter(name={name}, nice_name={nice_name}, ips={ips}, index={index})".format( return f"Adapter(name={self.name!r}, nice_name={self.nice_name!r}, ips={self.ips!r}, index={self.index!r})"
name=repr(self.name), nice_name=repr(self.nice_name), ips=repr(self.ips), index=repr(self.index)
)
# Type of an IPv4 address (a string in "xxx.xxx.xxx.xxx" format) # Type of an IPv4 address (a string in "xxx.xxx.xxx.xxx" format)
@ -70,7 +68,7 @@ _IPv4Address = str
_IPv6Address = Tuple[str, int, int] _IPv6Address = Tuple[str, int, int]
class IP(object): class IP:
""" """
Represents an IP address of an adapter. Represents an IP address of an adapter.
""" """
@ -112,9 +110,7 @@ class IP(object):
return isinstance(self.ip, tuple) return isinstance(self.ip, tuple)
def __repr__(self) -> str: def __repr__(self) -> str:
return "IP(ip={ip}, network_prefix={network_prefix}, nice_name={nice_name})".format( return f"IP(ip={self.ip!r}, network_prefix={self.network_prefix!r}, nice_name={self.nice_name!r})"
ip=repr(self.ip), network_prefix=repr(self.network_prefix), nice_name=repr(self.nice_name)
)
if platform.system() == "Darwin" or "BSD" in platform.system(): if platform.system() == "Darwin" or "BSD" in platform.system():

View File

@ -40,7 +40,7 @@ def ifaddresses(ifname) -> dict:
for ip in a.ips: for ip in a.ips:
t = {} t = {}
if ip.is_IPv4: 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["addr"] = ip.ip
t["prefix"] = ip.network_prefix t["prefix"] = ip.network_prefix
t["broadcast"] = str(net.broadcast_address) t["broadcast"] = str(net.broadcast_address)

55
RNS/vendor/six.py vendored
View File

@ -20,7 +20,6 @@
"""Utilities for writing code that runs on Python 2 and 3""" """Utilities for writing code that runs on Python 2 and 3"""
from __future__ import absolute_import
import functools import functools
import itertools import itertools
@ -57,7 +56,7 @@ else:
MAXSIZE = int((1 << 31) - 1) MAXSIZE = int((1 << 31) - 1)
else: else:
# It's possible to have sizeof(long) != sizeof(Py_ssize_t). # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
class X(object): class X:
def __len__(self): def __len__(self):
return 1 << 31 return 1 << 31
@ -88,7 +87,7 @@ def _import_module(name):
return sys.modules[name] return sys.modules[name]
class _LazyDescr(object): class _LazyDescr:
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
@ -108,7 +107,7 @@ class _LazyDescr(object):
class MovedModule(_LazyDescr): class MovedModule(_LazyDescr):
def __init__(self, name, old, new=None): def __init__(self, name, old, new=None):
super(MovedModule, self).__init__(name) super().__init__(name)
if PY3: if PY3:
if new is None: if new is None:
new = name new = name
@ -129,7 +128,7 @@ class MovedModule(_LazyDescr):
class _LazyModule(types.ModuleType): class _LazyModule(types.ModuleType):
def __init__(self, name): def __init__(self, name):
super(_LazyModule, self).__init__(name) super().__init__(name)
self.__doc__ = self.__class__.__doc__ self.__doc__ = self.__class__.__doc__
def __dir__(self): def __dir__(self):
@ -144,7 +143,7 @@ class _LazyModule(types.ModuleType):
class MovedAttribute(_LazyDescr): class MovedAttribute(_LazyDescr):
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): 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 PY3:
if new_mod is None: if new_mod is None:
new_mod = name new_mod = name
@ -166,7 +165,7 @@ class MovedAttribute(_LazyDescr):
return getattr(module, self.attr) return getattr(module, self.attr)
class _SixMetaPathImporter(object): class _SixMetaPathImporter:
""" """
A meta path importer to import six.moves and its submodules. A meta path importer to import six.moves and its submodules.
@ -181,10 +180,10 @@ class _SixMetaPathImporter(object):
def _add_module(self, mod, *fullnames): def _add_module(self, mod, *fullnames):
for fullname in 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): 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): def find_module(self, fullname, path=None):
if fullname in self.known_modules: if fullname in self.known_modules:
@ -200,7 +199,7 @@ class _SixMetaPathImporter(object):
try: try:
return self.known_modules[fullname] return self.known_modules[fullname]
except KeyError: 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): def load_module(self, fullname):
try: try:
@ -312,9 +311,9 @@ _moved_attributes = [
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
"tkinter.simpledialog"), "tkinter.simpledialog"),
MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), MovedModule("urllib_parse", f"{__name__}.moves.urllib_parse", "urllib.parse"),
MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), MovedModule("urllib_error", f"{__name__}.moves.urllib_error", "urllib.error"),
MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), MovedModule("urllib", f"{__name__}.moves.urllib", f"{__name__}.moves.urllib"),
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
@ -328,12 +327,12 @@ if sys.platform == "win32":
for attr in _moved_attributes: for attr in _moved_attributes:
setattr(_MovedItems, attr.name, attr) setattr(_MovedItems, attr.name, attr)
if isinstance(attr, MovedModule): if isinstance(attr, MovedModule):
_importer._add_module(attr, "moves." + attr.name) _importer._add_module(attr, f"moves.{attr.name}")
del attr del attr
_MovedItems._moved_attributes = _moved_attributes _MovedItems._moved_attributes = _moved_attributes
moves = _MovedItems(__name__ + ".moves") moves = _MovedItems(f"{__name__}.moves")
_importer._add_module(moves, "moves") _importer._add_module(moves, "moves")
@ -375,7 +374,7 @@ del attr
Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes 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") "moves.urllib_parse", "moves.urllib.parse")
@ -395,7 +394,7 @@ del attr
Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes 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") "moves.urllib_error", "moves.urllib.error")
@ -447,7 +446,7 @@ del attr
Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes 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") "moves.urllib_request", "moves.urllib.request")
@ -468,7 +467,7 @@ del attr
Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes 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") "moves.urllib_response", "moves.urllib.response")
@ -486,7 +485,7 @@ del attr
Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes 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") "moves.urllib_robotparser", "moves.urllib.robotparser")
@ -503,7 +502,7 @@ class Module_six_moves_urllib(types.ModuleType):
def __dir__(self): def __dir__(self):
return ['parse', 'error', 'request', 'response', 'robotparser'] 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") "moves.urllib")
@ -520,7 +519,7 @@ def remove_move(name):
try: try:
del moves.__dict__[name] del moves.__dict__[name]
except KeyError: except KeyError:
raise AttributeError("no such move, %r" % (name,)) raise AttributeError(f"no such move, {name!r}")
if PY3: if PY3:
@ -576,7 +575,7 @@ else:
def create_unbound_method(func, cls): def create_unbound_method(func, cls):
return types.MethodType(func, None, cls) return types.MethodType(func, None, cls)
class Iterator(object): class Iterator:
def next(self): def next(self):
return type(self).__next__(self) return type(self).__next__(self)
@ -910,7 +909,7 @@ def ensure_binary(s, encoding='utf-8', errors='strict'):
return s return s
if isinstance(s, text_type): if isinstance(s, text_type):
return s.encode(encoding, errors) 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'): 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): elif PY3 and isinstance(s, binary_type):
return s.decode(encoding, errors) return s.decode(encoding, errors)
elif not isinstance(s, (text_type, binary_type)): 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 return s
@ -952,7 +951,7 @@ def ensure_text(s, encoding='utf-8', errors='strict'):
elif isinstance(s, text_type): elif isinstance(s, text_type):
return s return s
else: else:
raise TypeError("not expecting type '%s'" % type(s)) raise TypeError(f"not expecting type '{type(s)}'")
def python_2_unicode_compatible(klass): def python_2_unicode_compatible(klass):
@ -965,9 +964,7 @@ def python_2_unicode_compatible(klass):
""" """
if PY2: if PY2:
if '__str__' not in klass.__dict__: if '__str__' not in klass.__dict__:
raise ValueError("@python_2_unicode_compatible cannot be applied " raise ValueError(f"@python_2_unicode_compatible cannot be applied to {klass.__name__} because it doesn't define __str__().")
"to %s because it doesn't define __str__()." %
klass.__name__)
klass.__unicode__ = klass.__str__ klass.__unicode__ = klass.__str__
klass.__str__ = lambda self: self.__unicode__().encode('utf-8') klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
return klass return klass

View File

@ -52,7 +52,7 @@ import io
if sys.version_info[0:2] >= (3, 3): if sys.version_info[0:2] >= (3, 3):
from collections.abc import Hashable from collections.abc import Hashable
else: else:
from collections import Hashable from collections.abc import Hashable
__version__ = "2.7.1" __version__ = "2.7.1"
"Module version string" "Module version string"
@ -66,7 +66,7 @@ version = (2, 7, 1)
############################################################################## ##############################################################################
# Extension type for application-defined types and data # Extension type for application-defined types and data
class Ext(object): class Ext:
""" """
The Ext class facilitates creating a serializable extension object to store The Ext class facilitates creating a serializable extension object to store
an application-defined type and data byte array. an application-defined type and data byte array.
@ -100,7 +100,7 @@ class Ext(object):
if not isinstance(type, int): if not isinstance(type, int):
raise TypeError("ext type is not type integer") raise TypeError("ext type is not type integer")
elif not (-2**7 <= type <= 2**7 - 1): 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 # Check data is type bytes or str
elif sys.version_info[0] == 3 and not isinstance(data, bytes): elif sys.version_info[0] == 3 and not isinstance(data, bytes):
raise TypeError("ext data is not type \'bytes\'") raise TypeError("ext data is not type \'bytes\'")
@ -127,8 +127,8 @@ class Ext(object):
""" """
String representation of this Ext object. String representation of this Ext object.
""" """
s = "Ext Object (Type: {:d}, Data: ".format(self.type) s = f"Ext Object (Type: {self.type}, Data: "
s += " ".join(["0x{:02}".format(ord(self.data[i:i + 1])) s += " ".join([f"0x{ord(self.data[i:i + 1]):02}"
for i in xrange(min(len(self.data), 8))]) for i in xrange(min(len(self.data), 8))])
if len(self.data) > 8: if len(self.data) > 8:
s += " ..." s += " ..."
@ -177,11 +177,11 @@ def ext_serializable(ext_type):
if not isinstance(ext_type, int): if not isinstance(ext_type, int):
raise TypeError("Ext type is not type integer") raise TypeError("Ext type is not type integer")
elif not (-2**7 <= ext_type <= 2**7 - 1): 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: 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: 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_type_to_class[ext_type] = cls
_ext_class_to_type[cls] = ext_type _ext_class_to_type[cls] = ext_type
@ -495,7 +495,7 @@ def _pack2(obj, fp, **options):
try: try:
_pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options)
except AttributeError: 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): elif isinstance(obj, bool):
_pack_boolean(obj, fp, options) _pack_boolean(obj, fp, options)
elif isinstance(obj, (int, long)): elif isinstance(obj, (int, long)):
@ -525,7 +525,7 @@ def _pack2(obj, fp, **options):
_pack_ext(ext_handlers[t](obj), fp, options) _pack_ext(ext_handlers[t](obj), fp, options)
else: else:
raise UnsupportedTypeException( raise UnsupportedTypeException(
"unsupported type: {:s}".format(str(type(obj)))) f"unsupported type: {type(obj)}")
elif _ext_class_to_type: elif _ext_class_to_type:
# Linear search for superclass # Linear search for superclass
t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) 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: try:
_pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options)
except AttributeError: 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: else:
raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) raise UnsupportedTypeException(f"unsupported type: {type(obj)}")
else: 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 # Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type
@ -582,7 +582,7 @@ def _pack3(obj, fp, **options):
try: try:
_pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options) _pack_ext(Ext(_ext_class_to_type[obj.__class__], obj.packb()), fp, options)
except AttributeError: 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): elif isinstance(obj, bool):
_pack_boolean(obj, fp, options) _pack_boolean(obj, fp, options)
elif isinstance(obj, int): elif isinstance(obj, int):
@ -612,7 +612,7 @@ def _pack3(obj, fp, **options):
_pack_ext(ext_handlers[t](obj), fp, options) _pack_ext(ext_handlers[t](obj), fp, options)
else: else:
raise UnsupportedTypeException( raise UnsupportedTypeException(
"unsupported type: {:s}".format(str(type(obj)))) f"unsupported type: {type(obj)}")
elif _ext_class_to_type: elif _ext_class_to_type:
# Linear search for superclass # Linear search for superclass
t = next((t for t in _ext_class_to_type if isinstance(obj, t)), None) 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: try:
_pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options) _pack_ext(Ext(_ext_class_to_type[t], obj.packb()), fp, options)
except AttributeError: 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: else:
raise UnsupportedTypeException("unsupported type: {:s}".format(str(type(obj)))) raise UnsupportedTypeException(f"unsupported type: {type(obj)}")
else: else:
raise UnsupportedTypeException( raise UnsupportedTypeException(
"unsupported type: {:s}".format(str(type(obj)))) f"unsupported type: {type(obj)}")
def _packb2(obj, **options): def _packb2(obj, **options):
@ -737,21 +737,21 @@ def _unpack_integer(code, fp, options):
return struct.unpack(">I", _read_except(fp, 4))[0] return struct.unpack(">I", _read_except(fp, 4))[0]
elif code == b'\xcf': elif code == b'\xcf':
return struct.unpack(">Q", _read_except(fp, 8))[0] 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): def _unpack_reserved(code, fp, options):
if code == b'\xc1': if code == b'\xc1':
raise ReservedCodeException( raise ReservedCodeException(
"encountered reserved code: 0x{:02x}".format(ord(code))) f"encountered reserved code: 0x{ord(code):02x}")
raise Exception( 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): def _unpack_nil(code, fp, options):
if code == b'\xc0': if code == b'\xc0':
return None 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): def _unpack_boolean(code, fp, options):
@ -759,7 +759,7 @@ def _unpack_boolean(code, fp, options):
return False return False
elif code == b'\xc3': elif code == b'\xc3':
return True 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): 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] return struct.unpack(">f", _read_except(fp, 4))[0]
elif code == b'\xcb': elif code == b'\xcb':
return struct.unpack(">d", _read_except(fp, 8))[0] 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): def _unpack_string(code, fp, options):
@ -780,7 +780,7 @@ def _unpack_string(code, fp, options):
elif code == b'\xdb': elif code == b'\xdb':
length = struct.unpack(">I", _read_except(fp, 4))[0] length = struct.unpack(">I", _read_except(fp, 4))[0]
else: 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 # Always return raw bytes in compatibility mode
global compatibility global compatibility
@ -804,7 +804,7 @@ def _unpack_binary(code, fp, options):
elif code == b'\xc6': elif code == b'\xc6':
length = struct.unpack(">I", _read_except(fp, 4))[0] length = struct.unpack(">I", _read_except(fp, 4))[0]
else: 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) return _read_except(fp, length)
@ -827,7 +827,7 @@ def _unpack_ext(code, fp, options):
elif code == b'\xc9': elif code == b'\xc9':
length = struct.unpack(">I", _read_except(fp, 4))[0] length = struct.unpack(">I", _read_except(fp, 4))[0]
else: 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_type = struct.unpack("b", _read_except(fp, 1))[0]
ext_data = _read_except(fp, length) ext_data = _read_except(fp, length)
@ -842,7 +842,7 @@ def _unpack_ext(code, fp, options):
try: try:
return _ext_type_to_class[ext_type].unpackb(ext_data) return _ext_type_to_class[ext_type].unpackb(ext_data)
except AttributeError: 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 # Timestamp extension
if ext_type == -1: 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 microseconds = struct.unpack(">I", ext_data[0:4])[0] // 1000
else: else:
raise UnsupportedTimestampException( 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, return _epoch + datetime.timedelta(seconds=seconds,
microseconds=microseconds) microseconds=microseconds)
@ -882,10 +882,10 @@ def _unpack_array(code, fp, options):
elif code == b'\xdd': elif code == b'\xdd':
length = struct.unpack(">I", _read_except(fp, 4))[0] length = struct.unpack(">I", _read_except(fp, 4))[0]
else: 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'): 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)] return [_unpack(fp, options) for i in xrange(length)]
@ -904,7 +904,7 @@ def _unpack_map(code, fp, options):
elif code == b'\xdf': elif code == b'\xdf':
length = struct.unpack(">I", _read_except(fp, 4))[0] length = struct.unpack(">I", _read_except(fp, 4))[0]
else: 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() d = {} if not options.get('use_ordered_dict') else collections.OrderedDict()
for _ in xrange(length): for _ in xrange(length):
@ -916,10 +916,10 @@ def _unpack_map(code, fp, options):
k = _deep_list_to_tuple(k) k = _deep_list_to_tuple(k)
elif not isinstance(k, Hashable): elif not isinstance(k, Hashable):
raise UnhashableKeyException( raise UnhashableKeyException(
"encountered unhashable key: \"{:s}\" ({:s})".format(str(k), str(type(k)))) f"encountered unhashable key: \"{k}\" ({type(k)})")
elif k in d: elif k in d:
raise DuplicateKeyException( raise DuplicateKeyException(
"encountered duplicate key: \"{:s}\" ({:s})".format(str(k), str(type(k)))) f"encountered duplicate key: \"{k}\" ({type(k)})")
# Unpack value # Unpack value
v = _unpack(fp, options) v = _unpack(fp, options)
@ -928,7 +928,7 @@ def _unpack_map(code, fp, options):
d[k] = v d[k] = v
except TypeError: except TypeError:
raise UnhashableKeyException( raise UnhashableKeyException(
"encountered unhashable key: \"{:s}\"".format(str(k))) f"encountered unhashable key: \"{k}\"")
return d return d

View File

@ -13,12 +13,12 @@ project = 'Reticulum Network Stack'
copyright = '2023, Mark Qvist' copyright = '2023, Mark Qvist'
author = 'Mark Qvist' author = 'Mark Qvist'
exec(open("../../RNS/_version.py", "r").read()) exec(open("../../RNS/_version.py").read())
version = __version__ version = __version__
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
import RNS import RNS
release = RNS._version.__version__+" beta" release = f"{RNS._version.__version__} beta"
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------
extensions = [ extensions = [

View File

@ -9,14 +9,14 @@ if '--pure' in sys.argv:
sys.argv.remove('--pure') sys.argv.remove('--pure')
print("Building pure-python wheel") print("Building pure-python wheel")
exec(open("RNS/_version.py", "r").read()) exec(open("RNS/_version.py").read())
with open("README.md", "r") as fh: with open("README.md") as fh:
long_description = fh.read() long_description = fh.read()
if pure_python: if pure_python:
pkg_name = "rnspure" pkg_name = "rnspure"
requirements = [] requirements = []
long_description = long_description.replace("</p>", "</p>"+pure_notice) long_description = long_description.replace("</p>", f"</p>{pure_notice}")
else: else:
pkg_name = "rns" pkg_name = "rns"
requirements = ['cryptography>=3.4.7', 'pyserial>=3.5'] requirements = ['cryptography>=3.4.7', 'pyserial>=3.5']

View File

@ -145,7 +145,7 @@ class SystemMessage(MessageBase):
MSGTYPE = 0xf000 MSGTYPE = 0xf000
def pack(self) -> bytes: def pack(self) -> bytes:
return bytes() return b''
def unpack(self, raw): def unpack(self, raw):
pass pass
@ -160,7 +160,7 @@ class ProtocolHarness(contextlib.AbstractContextManager):
def cleanup(self): def cleanup(self):
self.channel._shutdown() 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: __traceback: types.TracebackType) -> bool:
# self._log.debug(f"__exit__({__exc_type}, {__exc_value}, {__traceback})") # self._log.debug(f"__exit__({__exc_type}, {__exc_value}, {__traceback})")
self.cleanup() self.cleanup()
@ -431,7 +431,7 @@ class TestChannel(unittest.TestCase):
self.assertEqual(len(data), count) self.assertEqual(len(data), count)
read_finished = False read_finished = False
result = bytes() result = b''
def read_thread(): def read_thread():
nonlocal read_finished, result nonlocal read_finished, result

View File

@ -11,22 +11,22 @@ class TestSHA256(unittest.TestCase):
def test_empty(self): def test_empty(self):
self.assertEqual( self.assertEqual(
self.f(''.encode("utf-8")), self.f(b''),
bytes.fromhex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")) bytes.fromhex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"))
def test_less_than_block_length(self): def test_less_than_block_length(self):
self.assertEqual( self.assertEqual(
self.f('abc'.encode("utf-8")), self.f(b'abc'),
bytes.fromhex("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")) bytes.fromhex("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"))
def test_block_length(self): def test_block_length(self):
self.assertEqual( self.assertEqual(
self.f('a'.encode("utf-8")*64), self.f(b'a'*64),
bytes.fromhex("ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb")) bytes.fromhex("ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb"))
def test_several_blocks(self): def test_several_blocks(self):
self.assertEqual( self.assertEqual(
self.f('a'.encode("utf-8")*1000000), self.f(b'a'*1000000),
bytes.fromhex("cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")) bytes.fromhex("cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"))
def test_random_blocks(self): def test_random_blocks(self):
@ -49,10 +49,10 @@ class TestSHA256(unittest.TestCase):
if (i%1000 == 0): if (i%1000 == 0):
gbytes = round(b/1000000000,3) gbytes = round(b/1000000000,3)
mbps = round((b*8/1000000)/(time.time()-start), 2) 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: if not ok:
print("Failed at round "+str(i)) print(f"Failed at round {i}")
else: else:
print("SHA-256 test OK") print("SHA-256 test OK")
@ -65,25 +65,25 @@ class TestSHA512(unittest.TestCase):
def test_empty(self): def test_empty(self):
self.assertEqual( self.assertEqual(
self.f(''.encode("utf-8")), self.f(b''),
bytes.fromhex( bytes.fromhex(
'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce'+ 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce'+
'47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e')) '47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e'))
def test_less_than_block_length(self): def test_less_than_block_length(self):
self.assertEqual(self.f('abc'.encode("utf-8")), self.assertEqual(self.f(b'abc'),
bytes.fromhex( bytes.fromhex(
'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a'+ 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a'+
'2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f')) '2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f'))
def test_block_length(self): def test_block_length(self):
self.assertEqual(self.f('a'.encode("utf-8")*128), self.assertEqual(self.f(b'a'*128),
bytes.fromhex( bytes.fromhex(
'b73d1929aa615934e61a871596b3f3b33359f42b8175602e89f7e06e5f658a24'+ 'b73d1929aa615934e61a871596b3f3b33359f42b8175602e89f7e06e5f658a24'+
'3667807ed300314b95cacdd579f3e33abdfbe351909519a846d465c59582f321')) '3667807ed300314b95cacdd579f3e33abdfbe351909519a846d465c59582f321'))
def test_several_blocks(self): def test_several_blocks(self):
self.assertEqual(self.f('a'.encode("utf-8")*1000000), self.assertEqual(self.f(b'a'*1000000),
bytes.fromhex( bytes.fromhex(
'e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb'+ 'e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb'+
'de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b')) 'de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b'))
@ -108,10 +108,10 @@ class TestSHA512(unittest.TestCase):
if (i%1000 == 0): if (i%1000 == 0):
gbytes = round(b/1000000000,3) gbytes = round(b/1000000000,3)
mbps = round((b*8/1000000)/(time.time()-start), 2) 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: if not ok:
print("Failed at round "+str(i)) print(f"Failed at round {i}")
else: else:
print("SHA-512 test OK") print("SHA-512 test OK")

View File

@ -62,8 +62,8 @@ class TestIdentity(unittest.TestCase):
tmdev = tmax - tmin tmdev = tmax - tmin
mpct = (tmax/tmed)*100 mpct = (tmax/tmed)*100
print("Random messages:") 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(f" Signature timing min/avg/med/max/mdev: {round(tmin, 3)}/{round(tmean, 3)}/{round(tmed, 3)}/{round(tmax, 3)}/{round(tmdev, 3)}")
print(" Max deviation from median: "+str(round(mpct, 1))+"%") print(f" Max deviation from median: {round(mpct, 1)}%")
print() print()
id1 = RNS.Identity() id1 = RNS.Identity()
@ -85,8 +85,8 @@ class TestIdentity(unittest.TestCase):
tmdev = tmax - tmin tmdev = tmax - tmin
mpct = (tmax/tmed)*100 mpct = (tmax/tmed)*100
print("All 0xff messages:") 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(f" Signature timing min/avg/med/max/mdev: {round(tmin, 3)}/{round(tmean, 3)}/{round(tmed, 3)}/{round(tmax, 3)}/{round(tmdev, 3)}")
print(" Max deviation from median: "+str(round(mpct, 1))+"%") print(f" Max deviation from median: {round(mpct, 1)}%")
print() print()
id1 = RNS.Identity() id1 = RNS.Identity()
@ -108,8 +108,8 @@ class TestIdentity(unittest.TestCase):
tmdev = tmax - tmin tmdev = tmax - tmin
mpct = (tmax/tmed)*100 mpct = (tmax/tmed)*100
print("All 0x00 messages:") 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(f" Signature timing min/avg/med/max/mdev: {round(tmin, 3)}/{round(tmean, 3)}/{round(tmed, 3)}/{round(tmax, 3)}/{round(tmdev, 3)}")
print(" Max deviation from median: "+str(round(mpct, 1))+"%") print(f" Max deviation from median: {round(mpct, 1)}%")
print() print()
b = 0 b = 0
@ -127,7 +127,7 @@ class TestIdentity(unittest.TestCase):
self.assertEqual(True, id2.validate(signature, msg)) self.assertEqual(True, id2.validate(signature, msg))
t += time.time() - start 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): for i in range(1, 500):
mlen = 16*1024 mlen = 16*1024
@ -142,7 +142,7 @@ class TestIdentity(unittest.TestCase):
self.assertEqual(True, id2.validate(signature, msg)) self.assertEqual(True, id2.validate(signature, msg))
t += time.time() - start 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): def test_2_encrypt(self):
@ -176,8 +176,8 @@ class TestIdentity(unittest.TestCase):
self.assertEqual(msg, decrypted) self.assertEqual(msg, decrypted)
d_t += time.time() - d_start d_t += time.time() - d_start
print("Encrypt chunks < MTU: "+self.size_str(b/e_t, "b")+"ps") print(f"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"Decrypt chunks < MTU: {self.size_str(b / d_t, 'b')}ps")
print("") print("")
# Test encrypt and decrypt of large chunks # Test encrypt and decrypt of large chunks
@ -203,8 +203,8 @@ class TestIdentity(unittest.TestCase):
self.assertEqual(msg, id1.decrypt(token)) self.assertEqual(msg, id1.decrypt(token))
d_t += time.time() - d_start d_t += time.time() - d_start
print("Encrypt "+self.size_str(mlen)+" chunks: "+self.size_str(b/e_t, "b")+"ps") print(f"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"Decrypt {self.size_str(mlen)} chunks: {self.size_str(b / d_t, 'b')}ps")
def size_str(self, num, suffix='B'): def size_str(self, num, suffix='B'):
units = ['','K','M','G','T','P','E','Z'] units = ['','K','M','G','T','P','E','Z']
@ -218,12 +218,12 @@ class TestIdentity(unittest.TestCase):
for unit in units: for unit in units:
if abs(num) < 1000.0: if abs(num) < 1000.0:
if unit == "": if unit == "":
return "%.0f %s%s" % (num, unit, suffix) return f"{num:.0f} {unit}{suffix}"
else: else:
return "%.2f %s%s" % (num, unit, suffix) return f"{num:.2f} {unit}{suffix}"
num /= 1000.0 num /= 1000.0
return "%.2f%s%s" % (num, last_unit, suffix) return f"{num:.2f}{last_unit}{suffix}"
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(verbosity=2) unittest.main(verbosity=2)

View File

@ -28,7 +28,7 @@ BUFFER_TEST_TARGET = 32000
def targets_job(caller): def targets_job(caller):
cmd = "python -c \"from tests.link import targets; targets()\"" 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() ppath = os.getcwd()
try: try:
@ -144,7 +144,7 @@ class TestLink(unittest.TestCase):
packet_size = RNS.Link.MDU packet_size = RNS.Link.MDU
pstart = time.time() 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): for i in range(0, num_packets):
time.sleep(0.003) time.sleep(0.003)
b += packet_size b += packet_size
@ -154,7 +154,7 @@ class TestLink(unittest.TestCase):
receipts.append(p.send()) receipts.append(p.send())
pr_t += time.time() - start 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=" ") print("Checking receipts...", end=" ")
all_ok = False all_ok = False
@ -175,11 +175,11 @@ class TestLink(unittest.TestCase):
if n_failed > 0: if n_failed > 0:
ns = "s" if n_failed != 1 else "" 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) self.assertEqual(all_ok, True)
print("OK!") 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() l1.teardown()
time.sleep(0.5) time.sleep(0.5)
@ -209,7 +209,7 @@ class TestLink(unittest.TestCase):
resource_timeout = 120 resource_timeout = 120
resource_size = 128 resource_size = 128
data = os.urandom(resource_size) 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) resource = RNS.Resource(data, l1, timeout=resource_timeout)
start = time.time() start = time.time()
@ -219,7 +219,7 @@ class TestLink(unittest.TestCase):
t = time.time() - start t = time.time() - start
self.assertEqual(resource.status, RNS.Resource.COMPLETE) 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() l1.teardown()
time.sleep(0.5) time.sleep(0.5)
@ -249,7 +249,7 @@ class TestLink(unittest.TestCase):
resource_timeout = 120 resource_timeout = 120
resource_size = 256*1000 resource_size = 256*1000
data = os.urandom(resource_size) 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) resource = RNS.Resource(data, l1, timeout=resource_timeout)
start = time.time() start = time.time()
@ -259,7 +259,7 @@ class TestLink(unittest.TestCase):
t = time.time() - start t = time.time() - start
self.assertEqual(resource.status, RNS.Resource.COMPLETE) 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() l1.teardown()
time.sleep(0.5) time.sleep(0.5)
@ -288,7 +288,7 @@ class TestLink(unittest.TestCase):
resource_timeout = 120 resource_timeout = 120
resource_size = 1000*1000 resource_size = 1000*1000
data = os.urandom(resource_size) 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) resource = RNS.Resource(data, l1, timeout=resource_timeout)
start = time.time() start = time.time()
@ -298,7 +298,7 @@ class TestLink(unittest.TestCase):
t = time.time() - start t = time.time() - start
self.assertEqual(resource.status, RNS.Resource.COMPLETE) 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() l1.teardown()
time.sleep(0.5) time.sleep(0.5)
@ -332,7 +332,7 @@ class TestLink(unittest.TestCase):
resource_timeout = 120 resource_timeout = 120
resource_size = 5*1000*1000 resource_size = 5*1000*1000
data = os.urandom(resource_size) 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) resource = RNS.Resource(data, l1, timeout=resource_timeout)
start = time.time() start = time.time()
@ -342,7 +342,7 @@ class TestLink(unittest.TestCase):
t = time.time() - start t = time.time() - start
self.assertEqual(resource.status, RNS.Resource.COMPLETE) 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() l1.teardown()
time.sleep(0.5) time.sleep(0.5)
@ -379,7 +379,7 @@ class TestLink(unittest.TestCase):
resource_timeout = 120 resource_timeout = 120
resource_size = 50*1000*1000 resource_size = 50*1000*1000
data = os.urandom(resource_size) 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) resource = RNS.Resource(data, l1, timeout=resource_timeout, callback=self.lr_callback)
start = time.time() start = time.time()
@ -389,7 +389,7 @@ class TestLink(unittest.TestCase):
t = time.time() - start t = time.time() - start
self.assertEqual(TestLink.large_resource_status, RNS.Resource.COMPLETE) 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() l1.teardown()
time.sleep(0.5) time.sleep(0.5)
@ -478,7 +478,7 @@ class TestLink(unittest.TestCase):
channel = l1.get_channel() channel = l1.get_channel()
buffer = RNS.Buffer.create_bidirectional_buffer(0, 0, channel, handle_data) 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() buffer.flush()
time.sleep(0.5) time.sleep(0.5)
@ -508,7 +508,7 @@ class TestLink(unittest.TestCase):
if local_bitrate is not None: if local_bitrate is not None:
local_interface.bitrate = local_bitrate local_interface.bitrate = local_bitrate
local_interface._force_bitrate = True 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 # TODO: Load this from public bytes only
id1 = RNS.Identity.from_bytes(bytes.fromhex(fixed_keys[0][0])) 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 # delay a reasonable time for link to come up at current bitrate
link_sleep = max(RNS.Link.MDU * 3 / local_interface.bitrate * 8, 2) link_sleep = max(RNS.Link.MDU * 3 / local_interface.bitrate * 8, 2)
timeout_at = time.time() + link_sleep 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: while l1.status != RNS.Link.ACTIVE and time.time() < timeout_at:
time.sleep(0.01) time.sleep(0.01)
@ -564,14 +564,14 @@ class TestLink(unittest.TestCase):
expected_rx_message = b"" expected_rx_message = b""
for i in range(0, len(message)): for i in range(0, len(message)):
if i > 0 and (i % StreamDataMessage.MAX_DATA_LEN) == 0: 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 += 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 # since the segments will be received at max length for a
# StreamDataMessage, the appended text will end up in a # StreamDataMessage, the appended text will end up in a
# separate packet. # 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.write(message)
buffer.flush() buffer.flush()
@ -621,12 +621,12 @@ class TestLink(unittest.TestCase):
for unit in units: for unit in units:
if abs(num) < 1000.0: if abs(num) < 1000.0:
if unit == "": if unit == "":
return "%.0f %s%s" % (num, unit, suffix) return f"{num:.0f} {unit}{suffix}"
else: else:
return "%.2f %s%s" % (num, unit, suffix) return f"{num:.2f} {unit}{suffix}"
num /= 1000.0 num /= 1000.0
return "%.2f%s%s" % (num, last_unit, suffix) return f"{num:.2f}{last_unit}{suffix}"
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(verbosity=1) unittest.main(verbosity=1)
@ -650,16 +650,16 @@ def targets(yp=False):
threads = yappi.get_thread_stats() threads = yappi.get_thread_stats()
for thread in threads: for thread in threads:
print( 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__ ) # 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: except Exception as e:
print("Error: "+str(e)) print(f"Error: {e}")
if hasattr(resource.link.attached_interface, "rxptime"): if hasattr(resource.link.attached_interface, "rxptime"):
rx_pr = (resource.link.attached_interface.rxb*8)/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): def link_established(link):
print("Link established") print("Link established")
@ -670,7 +670,7 @@ def targets(yp=False):
def handle_message(message): def handle_message(message):
if isinstance(message, MessageTest): if isinstance(message, MessageTest):
message.data = message.data + " back" message.data = f"{message.data} back"
channel.send(message) channel.send(message)
channel.register_message_type(MessageTest) channel.register_message_type(MessageTest)
@ -685,17 +685,17 @@ def targets(yp=False):
buffer_read_len += len(data) buffer_read_len += len(data)
response_data.append(data) response_data.append(data)
if data == "Hi there".encode("utf-8"): if data == b"Hi there":
RNS.log("Sending response") RNS.log("Sending response")
for data in response_data: for data in response_data:
buffer.write(data + " back at you".encode("utf-8")) buffer.write(data + b" back at you")
buffer.flush() buffer.flush()
buffer_read_len = 0 buffer_read_len = 0
if buffer_read_len == BUFFER_TEST_TARGET: if buffer_read_len == BUFFER_TEST_TARGET:
RNS.log("Sending response") RNS.log("Sending response")
for data in response_data: for data in response_data:
buffer.write(data + " back at you".encode("utf-8")) buffer.write(data + b" back at you")
buffer.flush() buffer.flush()
buffer_read_len = 0 buffer_read_len = 0
@ -745,7 +745,7 @@ def resource_profiling():
resource_timeout = 120 resource_timeout = 120
resource_size = 5*1000*1000 resource_size = 5*1000*1000
data = os.urandom(resource_size) data = os.urandom(resource_size)
print("Sending "+size_str(resource_size)+" resource...") print(f"Sending {size_str(resource_size)} resource...")
import yappi import yappi
yappi.start() yappi.start()
@ -759,22 +759,22 @@ def resource_profiling():
time.sleep(0.01) time.sleep(0.01)
t = time.time() - start 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") yappi.get_func_stats().save("sender_main_calls.data", type="pstat")
threads = yappi.get_thread_stats() threads = yappi.get_thread_stats()
for thread in threads: for thread in threads:
print( 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__ ) # 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 = yappi.convert2pstats(tstats)
# t_pstats.save("resource_tstat.data", type="pstat") # t_pstats.save("resource_tstat.data", type="pstat")
if hasattr(resource.link.attached_interface, "rxptime"): if hasattr(resource.link.attached_interface, "rxptime"):
rx_pr = (resource.link.attached_interface.rxb*8)/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() l1.teardown()
time.sleep(0.5) time.sleep(0.5)
@ -791,9 +791,9 @@ def size_str(num, suffix='B'):
for unit in units: for unit in units:
if abs(num) < 1000.0: if abs(num) < 1000.0:
if unit == "": if unit == "":
return "%.0f %s%s" % (num, unit, suffix) return f"{num:.0f} {unit}{suffix}"
else: else:
return "%.2f %s%s" % (num, unit, suffix) return f"{num:.2f} {unit}{suffix}"
num /= 1000.0 num /= 1000.0
return "%.2f%s%s" % (num, last_unit, suffix) return f"{num:.2f}{last_unit}{suffix}"