mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-22 13:40:19 +00:00
Compare commits
2 Commits
86d4028dc4
...
011448c22d
Author | SHA1 | Date | |
---|---|---|---|
|
011448c22d | ||
|
2a5a439921 |
@ -1214,7 +1214,7 @@ This beta release brings a range of improvements and bugfixes.
|
|||||||
- Improved documentation.
|
- Improved documentation.
|
||||||
- Improved request timeouts and handling.
|
- Improved request timeouts and handling.
|
||||||
- Improved link establishment.
|
- Improved link establishment.
|
||||||
- Improved resource transfer timing.
|
- Improved resource transfer timing.
|
||||||
|
|
||||||
**Fixed bugs**
|
**Fixed bugs**
|
||||||
- Fixed a race condition in inbound proof handling.
|
- Fixed a race condition in inbound proof handling.
|
||||||
|
@ -22,7 +22,7 @@ noble_gases = ["Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon", "Oganesso
|
|||||||
def program_setup(configpath):
|
def program_setup(configpath):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our example
|
# Randomly create a new identity for our example
|
||||||
identity = RNS.Identity()
|
identity = RNS.Identity()
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ def program_setup(configpath):
|
|||||||
|
|
||||||
# We register the announce handler with Reticulum
|
# We register the announce handler with Reticulum
|
||||||
RNS.Transport.register_announce_handler(announce_handler)
|
RNS.Transport.register_announce_handler(announce_handler)
|
||||||
|
|
||||||
# Everything's ready!
|
# Everything's ready!
|
||||||
# Let's hand over control to the announce loop
|
# Let's hand over control to the announce loop
|
||||||
announceLoop(destination_1, destination_2)
|
announceLoop(destination_1, destination_2)
|
||||||
@ -86,16 +86,14 @@ def announceLoop(destination_1, destination_2):
|
|||||||
# know how to create messages directed towards it.
|
# know how to create messages directed towards it.
|
||||||
while True:
|
while True:
|
||||||
entered = input()
|
entered = input()
|
||||||
|
|
||||||
# Randomly select a fruit
|
# Randomly select a fruit
|
||||||
fruit = fruits[random.randint(0,len(fruits)-1)]
|
fruit = fruits[random.randint(0,len(fruits)-1)]
|
||||||
|
|
||||||
# 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")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
|
@ -17,7 +17,7 @@ APP_NAME = "example_utilities"
|
|||||||
def program_setup(configpath, channel=None):
|
def program_setup(configpath, channel=None):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# If the user did not select a "channel" we use
|
# If the user did not select a "channel" we use
|
||||||
# a default one called "public_information".
|
# a default one called "public_information".
|
||||||
# This "channel" is added to the destination name-
|
# This "channel" is added to the destination name-
|
||||||
@ -40,7 +40,7 @@ def program_setup(configpath, channel=None):
|
|||||||
# We specify a callback that will get called every time
|
# We specify a callback that will get called every time
|
||||||
# the destination receives data.
|
# the destination receives data.
|
||||||
broadcast_destination.set_packet_callback(packet_callback)
|
broadcast_destination.set_packet_callback(packet_callback)
|
||||||
|
|
||||||
# Everything's ready!
|
# Everything's ready!
|
||||||
# Let's hand over control to the main loop
|
# Let's hand over control to the main loop
|
||||||
broadcastLoop(broadcast_destination)
|
broadcastLoop(broadcast_destination)
|
||||||
@ -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.
|
||||||
|
@ -35,7 +35,7 @@ latest_buffer = None
|
|||||||
def server(configpath):
|
def server(configpath):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our example
|
# Randomly create a new identity for our example
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
@ -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,9 +149,9 @@ 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)
|
||||||
except:
|
except:
|
||||||
RNS.log("Invalid destination entered. Check your input!\n")
|
RNS.log("Invalid destination entered. Check your input!\n")
|
||||||
@ -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()
|
||||||
|
|
||||||
@ -253,7 +251,7 @@ def link_closed(link):
|
|||||||
RNS.log("The link was closed by the server, exiting now")
|
RNS.log("The link was closed by the server, exiting now")
|
||||||
else:
|
else:
|
||||||
RNS.log("Link closed, exiting now")
|
RNS.log("Link closed, exiting now")
|
||||||
|
|
||||||
RNS.Reticulum.exit_handler()
|
RNS.Reticulum.exit_handler()
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
@ -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()
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ latest_client_link = None
|
|||||||
def server(configpath):
|
def server(configpath):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our link example
|
# Randomly create a new identity for our link example
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
@ -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,9 +204,9 @@ 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)
|
||||||
except:
|
except:
|
||||||
RNS.log("Invalid destination entered. Check your input!\n")
|
RNS.log("Invalid destination entered. Check your input!\n")
|
||||||
@ -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()
|
||||||
|
|
||||||
@ -320,7 +315,7 @@ def link_closed(link):
|
|||||||
RNS.log("The link was closed by the server, exiting now")
|
RNS.log("The link was closed by the server, exiting now")
|
||||||
else:
|
else:
|
||||||
RNS.log("Link closed, exiting now")
|
RNS.log("Link closed, exiting now")
|
||||||
|
|
||||||
RNS.Reticulum.exit_handler()
|
RNS.Reticulum.exit_handler()
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
@ -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()
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ def server(configpath):
|
|||||||
|
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our echo server
|
# Randomly create a new identity for our echo server
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ def server(configpath):
|
|||||||
# create a "single" destination that can receive encrypted
|
# create a "single" destination that can receive encrypted
|
||||||
# messages. This way the client can send a request and be
|
# messages. This way the client can send a request and be
|
||||||
# certain that no-one else than this destination was able
|
# certain that no-one else than this destination was able
|
||||||
# to read it.
|
# to read it.
|
||||||
echo_destination = RNS.Destination(
|
echo_destination = RNS.Destination(
|
||||||
server_identity,
|
server_identity,
|
||||||
RNS.Destination.IN,
|
RNS.Destination.IN,
|
||||||
@ -50,7 +50,7 @@ def server(configpath):
|
|||||||
# generate a proof for each incoming packet and transmit it
|
# generate a proof for each incoming packet and transmit it
|
||||||
# back to the sender of that packet.
|
# back to the sender of that packet.
|
||||||
echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
||||||
|
|
||||||
# Tell the destination which function in our program to
|
# Tell the destination which function in our program to
|
||||||
# run when a packet is received. We do this so we can
|
# run when a packet is received. We do this so we can
|
||||||
# print a log message when the server receives a request
|
# print a log message when the server receives a request
|
||||||
@ -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,12 +74,12 @@ 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):
|
||||||
global reticulum
|
global reticulum
|
||||||
|
|
||||||
# Tell the user that we received an echo request, and
|
# Tell the user that we received an echo request, and
|
||||||
# that we are going to send a reply to the requester.
|
# that we are going to send a reply to the requester.
|
||||||
# Sending the proof is handled automatically, since we
|
# Sending the proof is handled automatically, since we
|
||||||
@ -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:
|
|
||||||
reception_stats += " [SNR "+str(packet.snr)+" dB]"
|
|
||||||
|
|
||||||
RNS.log("Received packet from echo client, proof sent"+reception_stats)
|
if packet.snr != None:
|
||||||
|
reception_stats += f" [SNR {packet.snr} dB]"
|
||||||
|
|
||||||
|
RNS.log(f"Received packet from echo client, proof sent{reception_stats}")
|
||||||
|
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
@ -116,20 +114,20 @@ def server_callback(message, packet):
|
|||||||
# to run as a client
|
# to run as a client
|
||||||
def client(destination_hexhash, configpath, timeout=None):
|
def client(destination_hexhash, configpath, timeout=None):
|
||||||
global reticulum
|
global reticulum
|
||||||
|
|
||||||
# We need a binary representation of the destination
|
# We need a binary representation of the destination
|
||||||
# hash that was entered on the command line
|
# hash that was entered on the command line
|
||||||
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(
|
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.
|
||||||
@ -153,7 +149,7 @@ def client(destination_hexhash, configpath, timeout=None):
|
|||||||
# command line.
|
# command line.
|
||||||
while True:
|
while True:
|
||||||
input()
|
input()
|
||||||
|
|
||||||
# Let's first check if RNS knows a path to the destination.
|
# Let's first check if RNS knows a path to the destination.
|
||||||
# If it does, we'll load the server identity and create a packet
|
# If it does, we'll load the server identity and create a packet
|
||||||
if RNS.Transport.has_path(destination_hash):
|
if RNS.Transport.has_path(destination_hash):
|
||||||
@ -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")
|
||||||
|
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
|
@ -44,7 +44,7 @@ serve_path = None
|
|||||||
def server(configpath, path):
|
def server(configpath, path):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our file server
|
# Randomly create a new identity for our file server
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
@ -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
|
||||||
@ -120,7 +120,7 @@ def client_connected(link):
|
|||||||
RNS.log("Too many files in served directory!", RNS.LOG_ERROR)
|
RNS.log("Too many files in served directory!", RNS.LOG_ERROR)
|
||||||
RNS.log("You should implement a function to split the filelist over multiple packets.", RNS.LOG_ERROR)
|
RNS.log("You should implement a function to split the filelist over multiple packets.", RNS.LOG_ERROR)
|
||||||
RNS.log("Hint: The client already supports it :)", RNS.LOG_ERROR)
|
RNS.log("Hint: The client already supports it :)", RNS.LOG_ERROR)
|
||||||
|
|
||||||
# After this, we're just going to keep the link
|
# After this, we're just going to keep the link
|
||||||
# open until the client requests a file. We'll
|
# open until the client requests a file. We'll
|
||||||
# configure a function that get's called when
|
# configure a function that get's called when
|
||||||
@ -145,9 +145,9 @@ 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(
|
||||||
file,
|
file,
|
||||||
packet.link,
|
packet.link,
|
||||||
@ -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,9 +218,9 @@ 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)
|
||||||
except:
|
except:
|
||||||
RNS.log("Invalid destination entered. Check your input!\n")
|
RNS.log("Invalid destination entered. Check your input!\n")
|
||||||
@ -291,9 +291,9 @@ def download(filename):
|
|||||||
# packet receipt.
|
# packet receipt.
|
||||||
request_packet = RNS.Packet(server_link, filename.encode("utf-8"), create_receipt=False)
|
request_packet = RNS.Packet(server_link, filename.encode("utf-8"), create_receipt=False)
|
||||||
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
|
||||||
@ -474,7 +474,7 @@ def link_closed(link):
|
|||||||
RNS.log("The link was closed by the server, exiting now")
|
RNS.log("The link was closed by the server, exiting now")
|
||||||
else:
|
else:
|
||||||
RNS.log("Link closed, exiting now")
|
RNS.log("Link closed, exiting now")
|
||||||
|
|
||||||
RNS.Reticulum.exit_handler()
|
RNS.Reticulum.exit_handler()
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
@ -486,17 +486,17 @@ def link_closed(link):
|
|||||||
def download_began(resource):
|
def download_began(resource):
|
||||||
global menu_mode, current_download, download_started, transfer_size, file_size
|
global menu_mode, current_download, download_started, transfer_size, file_size
|
||||||
current_download = resource
|
current_download = resource
|
||||||
|
|
||||||
if download_started == 0:
|
if download_started == 0:
|
||||||
download_started = time.time()
|
download_started = time.time()
|
||||||
|
|
||||||
transfer_size += resource.size
|
transfer_size += resource.size
|
||||||
file_size = resource.total_size
|
file_size = resource.total_size
|
||||||
|
|
||||||
menu_mode = "downloading"
|
menu_mode = "downloading"
|
||||||
|
|
||||||
# When the download concludes, successfully
|
# When the download concludes, successfully
|
||||||
# or not, we'll update our menu state and
|
# or not, we'll update our menu state and
|
||||||
# inform the user about how it all went.
|
# inform the user about how it all went.
|
||||||
def download_concluded(resource):
|
def download_concluded(resource):
|
||||||
global menu_mode, current_filename, download_started, download_finished, download_time
|
global menu_mode, current_filename, download_started, download_finished, download_time
|
||||||
@ -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():
|
||||||
|
@ -27,7 +27,7 @@ latest_client_link = None
|
|||||||
def server(configpath):
|
def server(configpath):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our link example
|
# Randomly create a new identity for our link example
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
@ -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()
|
||||||
|
|
||||||
@ -244,7 +239,7 @@ def link_closed(link):
|
|||||||
RNS.log("The link was closed by the server, exiting now")
|
RNS.log("The link was closed by the server, exiting now")
|
||||||
else:
|
else:
|
||||||
RNS.log("Link closed, exiting now")
|
RNS.log("Link closed, exiting now")
|
||||||
|
|
||||||
RNS.Reticulum.exit_handler()
|
RNS.Reticulum.exit_handler()
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
@ -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()
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ latest_client_link = None
|
|||||||
def server(configpath):
|
def server(configpath):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our link example
|
# Randomly create a new identity for our link example
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
@ -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,9 +111,9 @@ 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)
|
||||||
except:
|
except:
|
||||||
RNS.log("Invalid destination entered. Check your input!\n")
|
RNS.log("Invalid destination entered. Check your input!\n")
|
||||||
@ -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()
|
||||||
|
|
||||||
@ -221,7 +217,7 @@ def link_closed(link):
|
|||||||
RNS.log("The link was closed by the server, exiting now")
|
RNS.log("The link was closed by the server, exiting now")
|
||||||
else:
|
else:
|
||||||
RNS.log("Link closed, exiting now")
|
RNS.log("Link closed, exiting now")
|
||||||
|
|
||||||
RNS.Reticulum.exit_handler()
|
RNS.Reticulum.exit_handler()
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
@ -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()
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ APP_NAME = "example_utilities"
|
|||||||
def program_setup(configpath):
|
def program_setup(configpath):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our example
|
# Randomly create a new identity for our example
|
||||||
identity = RNS.Identity()
|
identity = RNS.Identity()
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ def program_setup(configpath):
|
|||||||
# tries to communicate with the destination know whether their
|
# tries to communicate with the destination know whether their
|
||||||
# communication was received correctly.
|
# communication was received correctly.
|
||||||
destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
||||||
|
|
||||||
# Everything's ready!
|
# Everything's ready!
|
||||||
# Let's hand over control to the announce loop
|
# Let's hand over control to the announce loop
|
||||||
announceLoop(destination)
|
announceLoop(destination)
|
||||||
@ -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)}")
|
||||||
|
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
|
@ -28,7 +28,7 @@ def server(configpath):
|
|||||||
|
|
||||||
# TODO: Remove
|
# TODO: Remove
|
||||||
RNS.loglevel = RNS.LOG_DEBUG
|
RNS.loglevel = RNS.LOG_DEBUG
|
||||||
|
|
||||||
# Randomly create a new identity for our echo server
|
# Randomly create a new identity for our echo server
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ def server(configpath):
|
|||||||
# create a "single" destination that can receive encrypted
|
# create a "single" destination that can receive encrypted
|
||||||
# messages. This way the client can send a request and be
|
# messages. This way the client can send a request and be
|
||||||
# certain that no-one else than this destination was able
|
# certain that no-one else than this destination was able
|
||||||
# to read it.
|
# to read it.
|
||||||
echo_destination = RNS.Destination(
|
echo_destination = RNS.Destination(
|
||||||
server_identity,
|
server_identity,
|
||||||
RNS.Destination.IN,
|
RNS.Destination.IN,
|
||||||
@ -61,7 +61,7 @@ def server(configpath):
|
|||||||
# generate a proof for each incoming packet and transmit it
|
# generate a proof for each incoming packet and transmit it
|
||||||
# back to the sender of that packet.
|
# back to the sender of that packet.
|
||||||
echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
||||||
|
|
||||||
# Tell the destination which function in our program to
|
# Tell the destination which function in our program to
|
||||||
# run when a packet is received. We do this so we can
|
# run when a packet is received. We do this so we can
|
||||||
# print a log message when the server receives a request
|
# print a log message when the server receives a request
|
||||||
@ -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,12 +85,12 @@ 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):
|
||||||
global reticulum
|
global reticulum
|
||||||
|
|
||||||
# Tell the user that we received an echo request, and
|
# Tell the user that we received an echo request, and
|
||||||
# that we are going to send a reply to the requester.
|
# that we are going to send a reply to the requester.
|
||||||
# Sending the proof is handled automatically, since we
|
# Sending the proof is handled automatically, since we
|
||||||
@ -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:
|
|
||||||
reception_stats += " [SNR "+str(packet.snr)+" dB]"
|
|
||||||
|
|
||||||
RNS.log("Received packet from echo client, proof sent"+reception_stats)
|
if packet.snr != None:
|
||||||
|
reception_stats += f" [SNR {packet.snr} dB]"
|
||||||
|
|
||||||
|
RNS.log(f"Received packet from echo client, proof sent{reception_stats}")
|
||||||
|
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
@ -127,20 +125,20 @@ def server_callback(message, packet):
|
|||||||
# to run as a client
|
# to run as a client
|
||||||
def client(destination_hexhash, configpath, timeout=None):
|
def client(destination_hexhash, configpath, timeout=None):
|
||||||
global reticulum
|
global reticulum
|
||||||
|
|
||||||
# We need a binary representation of the destination
|
# We need a binary representation of the destination
|
||||||
# hash that was entered on the command line
|
# hash that was entered on the command line
|
||||||
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(
|
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.
|
||||||
@ -164,7 +160,7 @@ def client(destination_hexhash, configpath, timeout=None):
|
|||||||
# command line.
|
# command line.
|
||||||
while True:
|
while True:
|
||||||
input()
|
input()
|
||||||
|
|
||||||
# Let's first check if RNS knows a path to the destination.
|
# Let's first check if RNS knows a path to the destination.
|
||||||
# If it does, we'll load the server identity and create a packet
|
# If it does, we'll load the server identity and create a packet
|
||||||
if RNS.Transport.has_path(destination_hash):
|
if RNS.Transport.has_path(destination_hash):
|
||||||
@ -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")
|
||||||
|
|
||||||
|
|
||||||
##########################################################
|
##########################################################
|
||||||
|
@ -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", "I’ll stay away from it", "The pet shop stocks everything"]
|
texts = ["They looked up", "On each full moon", "Becky was upset", "I’ll stay away from it", "The pet shop stocks everything"]
|
||||||
return texts[random.randint(0, len(texts)-1)]
|
return texts[random.randint(0, len(texts)-1)]
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ def random_text_generator(path, data, request_id, link_id, remote_identity, requ
|
|||||||
def server(configpath):
|
def server(configpath):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our link example
|
# Randomly create a new identity for our link example
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
@ -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,9 +111,9 @@ 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)
|
||||||
except:
|
except:
|
||||||
RNS.log("Invalid destination entered. Check your input!\n")
|
RNS.log("Invalid destination entered. Check your input!\n")
|
||||||
@ -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
|
||||||
@ -225,7 +223,7 @@ def link_closed(link):
|
|||||||
RNS.log("The link was closed by the server, exiting now")
|
RNS.log("The link was closed by the server, exiting now")
|
||||||
else:
|
else:
|
||||||
RNS.log("Link closed, exiting now")
|
RNS.log("Link closed, exiting now")
|
||||||
|
|
||||||
RNS.Reticulum.exit_handler()
|
RNS.Reticulum.exit_handler()
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
@ -36,7 +36,7 @@ printed = False
|
|||||||
def server(configpath):
|
def server(configpath):
|
||||||
# We must first initialise Reticulum
|
# We must first initialise Reticulum
|
||||||
reticulum = RNS.Reticulum(configpath)
|
reticulum = RNS.Reticulum(configpath)
|
||||||
|
|
||||||
# Randomly create a new identity for our link example
|
# Randomly create a new identity for our link example
|
||||||
server_identity = RNS.Identity()
|
server_identity = RNS.Identity()
|
||||||
|
|
||||||
@ -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,16 +106,16 @@ 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):
|
||||||
global latest_client_link, first_packet_at, last_packet_at, received_data, rc, data_cap
|
global latest_client_link, first_packet_at, last_packet_at, received_data, rc, data_cap
|
||||||
|
|
||||||
received_data += len(packet.data)
|
received_data += len(packet.data)
|
||||||
|
|
||||||
rc += 1
|
rc += 1
|
||||||
if rc >= 50:
|
if rc >= 50:
|
||||||
RNS.log(size_str(received_data))
|
RNS.log(size_str(received_data))
|
||||||
@ -129,19 +127,19 @@ def server_packet_received(message, packet):
|
|||||||
rc = 0
|
rc = 0
|
||||||
|
|
||||||
last_packet_at = time.time()
|
last_packet_at = time.time()
|
||||||
|
|
||||||
# Print statistics
|
# Print statistics
|
||||||
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,9 +167,9 @@ 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)
|
||||||
except:
|
except:
|
||||||
RNS.log("Invalid destination entered. Check your input!\n")
|
RNS.log("Invalid destination entered. Check your input!\n")
|
||||||
@ -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()
|
||||||
@ -282,7 +280,7 @@ def link_closed(link):
|
|||||||
RNS.log("The link was closed by the server, exiting now")
|
RNS.log("The link was closed by the server, exiting now")
|
||||||
else:
|
else:
|
||||||
RNS.log("Link closed, exiting now")
|
RNS.log("Link closed, exiting now")
|
||||||
|
|
||||||
RNS.Reticulum.exit_handler()
|
RNS.Reticulum.exit_handler()
|
||||||
|
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
|
18
README.md
18
README.md
@ -109,8 +109,8 @@ network, and vice versa.
|
|||||||
|
|
||||||
## How do I get started?
|
## How do I get started?
|
||||||
The best way to get started with the Reticulum Network Stack depends on what
|
The best way to get started with the Reticulum Network Stack depends on what
|
||||||
you want to do. For full details and examples, have a look at the
|
you want to do. For full details and examples, have a look at the
|
||||||
[Getting Started Fast](https://markqvist.github.io/Reticulum/manual/gettingstartedfast.html)
|
[Getting Started Fast](https://markqvist.github.io/Reticulum/manual/gettingstartedfast.html)
|
||||||
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
||||||
|
|
||||||
To simply install Reticulum and related utilities on your system, the easiest way is via `pip`.
|
To simply install Reticulum and related utilities on your system, the easiest way is via `pip`.
|
||||||
@ -143,15 +143,15 @@ creating a more complex configuration.
|
|||||||
|
|
||||||
If you have an old version of `pip` on your system, you may need to upgrade it first with `pip install pip --upgrade`. If you no not already have `pip` installed, you can install it using the package manager of your system with `sudo apt install python3-pip` or similar.
|
If you have an old version of `pip` on your system, you may need to upgrade it first with `pip install pip --upgrade`. If you no not already have `pip` installed, you can install it using the package manager of your system with `sudo apt install python3-pip` or similar.
|
||||||
|
|
||||||
For more detailed examples on how to expand communication over many mediums such
|
For more detailed examples on how to expand communication over many mediums such
|
||||||
as packet radio or LoRa, serial ports, or over fast IP links and the Internet using
|
as packet radio or LoRa, serial ports, or over fast IP links and the Internet using
|
||||||
the UDP and TCP interfaces, take a look at the [Supported Interfaces](https://markqvist.github.io/Reticulum/manual/interfaces.html)
|
the UDP and TCP interfaces, take a look at the [Supported Interfaces](https://markqvist.github.io/Reticulum/manual/interfaces.html)
|
||||||
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
||||||
|
|
||||||
## Included Utilities
|
## Included Utilities
|
||||||
Reticulum includes a range of useful utilities for managing your networks,
|
Reticulum includes a range of useful utilities for managing your networks,
|
||||||
viewing status and information, and other tasks. You can read more about these
|
viewing status and information, and other tasks. You can read more about these
|
||||||
programs in the [Included Utility Programs](https://markqvist.github.io/Reticulum/manual/using.html#included-utility-programs)
|
programs in the [Included Utility Programs](https://markqvist.github.io/Reticulum/manual/using.html#included-utility-programs)
|
||||||
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
||||||
|
|
||||||
- The system daemon `rnsd` for running Reticulum as an always-available service
|
- The system daemon `rnsd` for running Reticulum as an always-available service
|
||||||
@ -242,7 +242,7 @@ The testnet is just that, an informal network for testing and experimenting.
|
|||||||
It will be up most of the time, and anyone can join, but it also means that
|
It will be up most of the time, and anyone can join, but it also means that
|
||||||
there's no guarantees for service availability.
|
there's no guarantees for service availability.
|
||||||
|
|
||||||
It probably goes without saying, but *don't use the testnet entry-points as
|
It probably goes without saying, but *don't use the testnet entry-points as
|
||||||
hardcoded or default interfaces in any applications you ship to users*. When
|
hardcoded or default interfaces in any applications you ship to users*. When
|
||||||
shipping applications, the best practice is to provide your own default
|
shipping applications, the best practice is to provide your own default
|
||||||
connectivity solutions, if needed and applicable, or in most cases, simply
|
connectivity solutions, if needed and applicable, or in most cases, simply
|
||||||
|
@ -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
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ class RawChannelWriter(RawIOBase, AbstractContextManager):
|
|||||||
processed_length = len(chunk)
|
processed_length = len(chunk)
|
||||||
|
|
||||||
message = StreamDataMessage(self._stream_id, chunk, self._eof, comp_success)
|
message = StreamDataMessage(self._stream_id, chunk, self._eof, comp_success)
|
||||||
|
|
||||||
self._channel.send(message)
|
self._channel.send(message)
|
||||||
return processed_length
|
return processed_length
|
||||||
|
|
||||||
@ -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
|
||||||
|
@ -136,7 +136,7 @@ class MessageBase(abc.ABC):
|
|||||||
MSGTYPE = None
|
MSGTYPE = None
|
||||||
"""
|
"""
|
||||||
Defines a unique identifier for a message class.
|
Defines a unique identifier for a message class.
|
||||||
|
|
||||||
* Must be unique within all classes registered with a ``Channel``
|
* Must be unique within all classes registered with a ``Channel``
|
||||||
* Must be less than ``0xf000``. Values greater than or equal to ``0xf000`` are reserved.
|
* Must be less than ``0xf000``. Values greater than or equal to ``0xf000`` are reserved.
|
||||||
"""
|
"""
|
||||||
@ -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)
|
||||||
@ -247,11 +247,11 @@ class Channel(contextlib.AbstractContextManager):
|
|||||||
|
|
||||||
# The maximum window size for transfers on fast links
|
# The maximum window size for transfers on fast links
|
||||||
WINDOW_MAX_FAST = 48
|
WINDOW_MAX_FAST = 48
|
||||||
|
|
||||||
# For calculating maps and guard segments, this
|
# For calculating maps and guard segments, this
|
||||||
# must be set to the global maximum window.
|
# must be set to the global maximum window.
|
||||||
WINDOW_MAX = WINDOW_MAX_FAST
|
WINDOW_MAX = WINDOW_MAX_FAST
|
||||||
|
|
||||||
# If the fast rate is sustained for this many request
|
# If the fast rate is sustained for this many request
|
||||||
# rounds, the fast link window size will be allowed.
|
# rounds, the fast link window size will be allowed.
|
||||||
FAST_RATE_THRESHOLD = 10
|
FAST_RATE_THRESHOLD = 10
|
||||||
@ -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,
|
||||||
@ -380,21 +380,21 @@ class Channel(contextlib.AbstractContextManager):
|
|||||||
def _emplace_envelope(self, envelope: Envelope, ring: collections.deque[Envelope]) -> bool:
|
def _emplace_envelope(self, envelope: Envelope, ring: collections.deque[Envelope]) -> bool:
|
||||||
with self._lock:
|
with self._lock:
|
||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
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):
|
||||||
ring.insert(i, envelope)
|
ring.insert(i, envelope)
|
||||||
|
|
||||||
envelope.tracked = True
|
envelope.tracked = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
envelope.tracked = True
|
envelope.tracked = True
|
||||||
ring.append(envelope)
|
ring.append(envelope)
|
||||||
|
|
||||||
@ -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:
|
||||||
@ -449,12 +449,12 @@ class Channel(contextlib.AbstractContextManager):
|
|||||||
m = e.unpack(self._message_factories)
|
m = e.unpack(self._message_factories)
|
||||||
else:
|
else:
|
||||||
m = e.message
|
m = e.message
|
||||||
|
|
||||||
self._rx_ring.remove(e)
|
self._rx_ring.remove(e)
|
||||||
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:
|
||||||
"""
|
"""
|
||||||
@ -468,7 +468,7 @@ class Channel(contextlib.AbstractContextManager):
|
|||||||
with self._lock:
|
with self._lock:
|
||||||
outstanding = 0
|
outstanding = 0
|
||||||
for envelope in self._tx_ring:
|
for envelope in self._tx_ring:
|
||||||
if envelope.outlet == self._outlet:
|
if envelope.outlet == self._outlet:
|
||||||
if not envelope.packet or not self._outlet.get_packet_state(envelope.packet) == MessageState.MSGSTATE_DELIVERED:
|
if not envelope.packet or not self._outlet.get_packet_state(envelope.packet) == MessageState.MSGSTATE_DELIVERED:
|
||||||
outstanding += 1
|
outstanding += 1
|
||||||
|
|
||||||
@ -508,7 +508,7 @@ class Channel(contextlib.AbstractContextManager):
|
|||||||
# TODO: Remove at some point
|
# TODO: Remove at some point
|
||||||
# RNS.log("Increased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_DEBUG)
|
# RNS.log("Increased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_DEBUG)
|
||||||
# RNS.log("Increased "+str(self)+" min window to "+str(self.window_min), RNS.LOG_DEBUG)
|
# RNS.log("Increased "+str(self)+" min window to "+str(self.window_min), RNS.LOG_DEBUG)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.fast_rate_rounds += 1
|
self.fast_rate_rounds += 1
|
||||||
if self.window_max < Channel.WINDOW_MAX_FAST and self.fast_rate_rounds == Channel.FAST_RATE_THRESHOLD:
|
if self.window_max < Channel.WINDOW_MAX_FAST and self.fast_rate_rounds == Channel.FAST_RATE_THRESHOLD:
|
||||||
@ -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
|
||||||
@ -581,7 +581,7 @@ class Channel(contextlib.AbstractContextManager):
|
|||||||
with self._lock:
|
with self._lock:
|
||||||
if not self.is_ready_to_send():
|
if not self.is_ready_to_send():
|
||||||
raise ChannelException(CEType.ME_LINK_NOT_READY, f"Link is not ready")
|
raise ChannelException(CEType.ME_LINK_NOT_READY, f"Link is not ready")
|
||||||
|
|
||||||
envelope = Envelope(self._outlet, message=message, sequence=self._next_sequence)
|
envelope = Envelope(self._outlet, message=message, sequence=self._next_sequence)
|
||||||
self._next_sequence = (self._next_sequence + 1) % Channel.SEQ_MODULUS
|
self._next_sequence = (self._next_sequence + 1) % Channel.SEQ_MODULUS
|
||||||
self._emplace_envelope(envelope, self._tx_ring)
|
self._emplace_envelope(envelope, self._tx_ring)
|
||||||
@ -592,7 +592,7 @@ class Channel(contextlib.AbstractContextManager):
|
|||||||
envelope.pack()
|
envelope.pack()
|
||||||
if len(envelope.raw) > self._outlet.mdu:
|
if len(envelope.raw) > self._outlet.mdu:
|
||||||
raise ChannelException(CEType.ME_TOO_BIG, f"Packed message too big for packet: {len(envelope.raw)} > {self._outlet.mdu}")
|
raise ChannelException(CEType.ME_TOO_BIG, f"Packed message too big for packet: {len(envelope.raw)} > {self._outlet.mdu}")
|
||||||
|
|
||||||
envelope.packet = self._outlet.send(envelope.raw)
|
envelope.packet = self._outlet.send(envelope.raw)
|
||||||
envelope.tries += 1
|
envelope.tries += 1
|
||||||
self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered)
|
self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered)
|
||||||
|
@ -25,7 +25,7 @@ import RNS.vendor.platformutils as pu
|
|||||||
|
|
||||||
if cp.PROVIDER == cp.PROVIDER_INTERNAL:
|
if cp.PROVIDER == cp.PROVIDER_INTERNAL:
|
||||||
from .aes import AES
|
from .aes import AES
|
||||||
|
|
||||||
elif cp.PROVIDER == cp.PROVIDER_PYCA:
|
elif cp.PROVIDER == cp.PROVIDER_PYCA:
|
||||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ class AES_128_CBC:
|
|||||||
cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
|
cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
|
||||||
else:
|
else:
|
||||||
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
|
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
|
||||||
|
|
||||||
encryptor = cipher.encryptor()
|
encryptor = cipher.encryptor()
|
||||||
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
|
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
|
||||||
return ciphertext
|
return ciphertext
|
||||||
|
@ -48,15 +48,15 @@ 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:]
|
||||||
|
|
||||||
|
|
||||||
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()
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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]
|
@ -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}"
|
@ -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,
|
||||||
@ -48,34 +48,34 @@ class sha256(object):
|
|||||||
_h = (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
_h = (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19)
|
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19)
|
||||||
_output_size = 8
|
_output_size = 8
|
||||||
|
|
||||||
blocksize = 1
|
blocksize = 1
|
||||||
block_size = 64
|
block_size = 64
|
||||||
digest_size = 32
|
digest_size = 32
|
||||||
|
|
||||||
def __init__(self, m=None):
|
def __init__(self, m=None):
|
||||||
self._buffer = b""
|
self._buffer = b""
|
||||||
self._counter = 0
|
self._counter = 0
|
||||||
|
|
||||||
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):
|
||||||
return ((x >> y) | (x << (32-y))) & 0xFFFFFFFF
|
return ((x >> y) | (x << (32-y))) & 0xFFFFFFFF
|
||||||
|
|
||||||
def _sha256_process(self, c):
|
def _sha256_process(self, c):
|
||||||
w = [0]*64
|
w = [0]*64
|
||||||
w[0:16] = struct.unpack('!16L', c)
|
w[0:16] = struct.unpack('!16L', c)
|
||||||
|
|
||||||
for i in range(16, 64):
|
for i in range(16, 64):
|
||||||
s0 = self._rotr(w[i-15], 7) ^ self._rotr(w[i-15], 18) ^ (w[i-15] >> 3)
|
s0 = self._rotr(w[i-15], 7) ^ self._rotr(w[i-15], 18) ^ (w[i-15] >> 3)
|
||||||
s1 = self._rotr(w[i-2], 17) ^ self._rotr(w[i-2], 19) ^ (w[i-2] >> 10)
|
s1 = self._rotr(w[i-2], 17) ^ self._rotr(w[i-2], 19) ^ (w[i-2] >> 10)
|
||||||
w[i] = (w[i-16] + s0 + w[i-7] + s1) & 0xFFFFFFFF
|
w[i] = (w[i-16] + s0 + w[i-7] + s1) & 0xFFFFFFFF
|
||||||
|
|
||||||
a,b,c,d,e,f,g,h = self._h
|
a,b,c,d,e,f,g,h = self._h
|
||||||
|
|
||||||
for i in range(64):
|
for i in range(64):
|
||||||
s0 = self._rotr(a, 2) ^ self._rotr(a, 13) ^ self._rotr(a, 22)
|
s0 = self._rotr(a, 2) ^ self._rotr(a, 13) ^ self._rotr(a, 22)
|
||||||
maj = (a & b) ^ (a & c) ^ (b & c)
|
maj = (a & b) ^ (a & c) ^ (b & c)
|
||||||
@ -83,7 +83,7 @@ class sha256(object):
|
|||||||
s1 = self._rotr(e, 6) ^ self._rotr(e, 11) ^ self._rotr(e, 25)
|
s1 = self._rotr(e, 6) ^ self._rotr(e, 11) ^ self._rotr(e, 25)
|
||||||
ch = (e & f) ^ ((~e) & g)
|
ch = (e & f) ^ ((~e) & g)
|
||||||
t1 = h + s1 + ch + self._k[i] + w[i]
|
t1 = h + s1 + ch + self._k[i] + w[i]
|
||||||
|
|
||||||
h = g
|
h = g
|
||||||
g = f
|
g = f
|
||||||
f = e
|
f = e
|
||||||
@ -92,38 +92,38 @@ class sha256(object):
|
|||||||
c = b
|
c = b
|
||||||
b = a
|
b = a
|
||||||
a = (t1 + t2) & 0xFFFFFFFF
|
a = (t1 + t2) & 0xFFFFFFFF
|
||||||
|
|
||||||
self._h = [(x+y) & 0xFFFFFFFF for x,y in zip(self._h, [a,b,c,d,e,f,g,h])]
|
self._h = [(x+y) & 0xFFFFFFFF for x,y in zip(self._h, [a,b,c,d,e,f,g,h])]
|
||||||
|
|
||||||
def update(self, m):
|
def update(self, m):
|
||||||
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)
|
||||||
|
|
||||||
while len(self._buffer) >= 64:
|
while len(self._buffer) >= 64:
|
||||||
self._sha256_process(self._buffer[:64])
|
self._sha256_process(self._buffer[:64])
|
||||||
self._buffer = self._buffer[64:]
|
self._buffer = self._buffer[64:]
|
||||||
|
|
||||||
def digest(self):
|
def digest(self):
|
||||||
mdi = self._counter & 0x3F
|
mdi = self._counter & 0x3F
|
||||||
length = struct.pack('!Q', self._counter<<3)
|
length = struct.pack('!Q', self._counter<<3)
|
||||||
|
|
||||||
if mdi < 56:
|
if mdi < 56:
|
||||||
padlen = 55-mdi
|
padlen = 55-mdi
|
||||||
else:
|
else:
|
||||||
padlen = 119-mdi
|
padlen = 119-mdi
|
||||||
|
|
||||||
r = self.copy()
|
r = self.copy()
|
||||||
r.update(b'\x80'+(b'\x00'*padlen)+length)
|
r.update(b'\x80'+(b'\x00'*padlen)+length)
|
||||||
return b''.join([struct.pack('!L', i) for i in r._h[:self._output_size]])
|
return b''.join([struct.pack('!L', i) for i in r._h[:self._output_size]])
|
||||||
|
|
||||||
def hexdigest(self):
|
def hexdigest(self):
|
||||||
return self.digest().encode('hex')
|
return self.digest().encode('hex')
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
return copy.deepcopy(self)
|
return copy.deepcopy(self)
|
||||||
|
@ -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)
|
||||||
|
@ -138,9 +138,9 @@ class X25519PrivateKey:
|
|||||||
peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key)
|
peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key)
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
shared = _pack_number(_raw_curve25519(peer_public_key.x, self.a))
|
shared = _pack_number(_raw_curve25519(peer_public_key.x, self.a))
|
||||||
|
|
||||||
end = time.time()
|
end = time.time()
|
||||||
duration = end-start
|
duration = end-start
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ class X25519PrivateKey:
|
|||||||
if end > X25519PrivateKey.T_CLEAR:
|
if end > X25519PrivateKey.T_CLEAR:
|
||||||
X25519PrivateKey.T_CLEAR = end + X25519PrivateKey.DELAY_WINDOW
|
X25519PrivateKey.T_CLEAR = end + X25519PrivateKey.DELAY_WINDOW
|
||||||
X25519PrivateKey.T_MAX = 0
|
X25519PrivateKey.T_MAX = 0
|
||||||
|
|
||||||
if duration < X25519PrivateKey.T_MAX or duration < X25519PrivateKey.MIN_EXEC_TIME:
|
if duration < X25519PrivateKey.T_MAX or duration < X25519PrivateKey.MIN_EXEC_TIME:
|
||||||
target = start+X25519PrivateKey.T_MAX
|
target = start+X25519PrivateKey.T_MAX
|
||||||
|
|
||||||
|
@ -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')]
|
||||||
|
@ -144,7 +144,7 @@ class AES:
|
|||||||
return matrix2bytes(state)
|
return matrix2bytes(state)
|
||||||
|
|
||||||
|
|
||||||
# will encrypt the entire data
|
# will encrypt the entire data
|
||||||
def encrypt(self, plaintext, iv):
|
def encrypt(self, plaintext, iv):
|
||||||
"""
|
"""
|
||||||
Encrypts `plaintext` using CBC mode and PKCS#7 padding, with the given
|
Encrypts `plaintext` using CBC mode and PKCS#7 padding, with the given
|
||||||
@ -173,7 +173,7 @@ class AES:
|
|||||||
return b''.join(ciphertext_blocks)
|
return b''.join(ciphertext_blocks)
|
||||||
|
|
||||||
|
|
||||||
# will decrypt the entire data
|
# will decrypt the entire data
|
||||||
def decrypt(self, ciphertext, iv):
|
def decrypt(self, ciphertext, iv):
|
||||||
"""
|
"""
|
||||||
Decrypts `ciphertext` using CBC mode and PKCS#7 padding, with the given
|
Decrypts `ciphertext` using CBC mode and PKCS#7 padding, with the given
|
||||||
@ -188,7 +188,7 @@ class AES:
|
|||||||
for ciphertext_block in split_blocks(ciphertext):
|
for ciphertext_block in split_blocks(ciphertext):
|
||||||
# in CBC mode every block is XOR'd with the previous block
|
# in CBC mode every block is XOR'd with the previous block
|
||||||
xorred = xor_bytes(previous, self._decrypt_block(ciphertext_block))
|
xorred = xor_bytes(previous, self._decrypt_block(ciphertext_block))
|
||||||
|
|
||||||
# append plaintext
|
# append plaintext
|
||||||
plaintext_blocks.append(xorred)
|
plaintext_blocks.append(xorred)
|
||||||
previous = ciphertext_block
|
previous = ciphertext_block
|
||||||
@ -223,14 +223,14 @@ def test():
|
|||||||
print("Single Block Tests")
|
print("Single Block Tests")
|
||||||
print("------------------")
|
print("------------------")
|
||||||
print(f"iv: {iv.hex()}")
|
print(f"iv: {iv.hex()}")
|
||||||
|
|
||||||
print(f"plain text: '{single_block_text.decode()}'")
|
print(f"plain text: '{single_block_text.decode()}'")
|
||||||
ciphertext_block = _aes._encrypt_block(single_block_text)
|
ciphertext_block = _aes._encrypt_block(single_block_text)
|
||||||
plaintext_block = _aes._decrypt_block(ciphertext_block)
|
plaintext_block = _aes._decrypt_block(ciphertext_block)
|
||||||
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,10 +262,10 @@ 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()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# test AES class
|
# test AES class
|
||||||
test()
|
test()
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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')
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ class Destination:
|
|||||||
|
|
||||||
def __init__(self, identity, direction, type, app_name, *aspects):
|
def __init__(self, identity, direction, type, app_name, *aspects):
|
||||||
# Check input values and build name string
|
# Check input values and build name string
|
||||||
if "." in app_name: raise ValueError("Dots can't be used in app names")
|
if "." in app_name: raise ValueError("Dots can't be used in app names")
|
||||||
if not type in Destination.types: raise ValueError("Unknown destination type")
|
if not type in Destination.types: raise ValueError("Unknown destination type")
|
||||||
if not direction in Destination.directions: raise ValueError("Unknown destination direction")
|
if not direction in Destination.directions: raise ValueError("Unknown destination direction")
|
||||||
|
|
||||||
@ -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
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ class Destination:
|
|||||||
|
|
||||||
if self.direction != Destination.IN:
|
if self.direction != Destination.IN:
|
||||||
raise TypeError("Only IN destination types can be announced")
|
raise TypeError("Only IN destination types can be announced")
|
||||||
|
|
||||||
ratchet = b""
|
ratchet = b""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
stale_responses = []
|
stale_responses = []
|
||||||
@ -262,9 +262,9 @@ 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:
|
||||||
destination_hash = self.hash
|
destination_hash = self.hash
|
||||||
random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big")
|
random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big")
|
||||||
@ -281,7 +281,7 @@ class Destination:
|
|||||||
returned_app_data = self.default_app_data()
|
returned_app_data = self.default_app_data()
|
||||||
if isinstance(returned_app_data, bytes):
|
if isinstance(returned_app_data, bytes):
|
||||||
app_data = returned_app_data
|
app_data = returned_app_data
|
||||||
|
|
||||||
signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash+ratchet
|
signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash+ratchet
|
||||||
if app_data != None:
|
if app_data != None:
|
||||||
signed_data += app_data
|
signed_data += app_data
|
||||||
@ -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?")
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ class Identity:
|
|||||||
# save, but the only changes. It might be possible to
|
# save, but the only changes. It might be possible to
|
||||||
# simply overwrite on exit now that every local client
|
# simply overwrite on exit now that every local client
|
||||||
# disconnect triggers a data persist.
|
# disconnect triggers a data persist.
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if hasattr(Identity, "saving_known_destinations"):
|
if hasattr(Identity, "saving_known_destinations"):
|
||||||
wait_interval = 0.2
|
wait_interval = 0.2
|
||||||
@ -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,8 +278,8 @@ 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)
|
||||||
|
|
||||||
@ -290,7 +290,7 @@ class Identity:
|
|||||||
ratchet_file.close()
|
ratchet_file.close()
|
||||||
os.replace(outpath, finalpath)
|
os.replace(outpath, finalpath)
|
||||||
|
|
||||||
|
|
||||||
threading.Thread(target=persist_job, daemon=True).start()
|
threading.Thread(target=persist_job, daemon=True).start()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -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):
|
||||||
@ -337,7 +337,7 @@ class Identity:
|
|||||||
Identity.known_ratchets[destination_hash] = ratchet_data["ratchet"]
|
Identity.known_ratchets[destination_hash] = ratchet_data["ratchet"]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log(f"An error occurred while loading ratchet data for {RNS.prettyhexrep(destination_hash)} from storage.", RNS.LOG_ERROR)
|
RNS.log(f"An error occurred while loading ratchet data for {RNS.prettyhexrep(destination_hash)} from storage.", RNS.LOG_ERROR)
|
||||||
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
|
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
|
||||||
@ -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):
|
||||||
"""
|
"""
|
||||||
@ -567,7 +567,7 @@ class Identity:
|
|||||||
self.prv = X25519PrivateKey.from_private_bytes(self.prv_bytes)
|
self.prv = X25519PrivateKey.from_private_bytes(self.prv_bytes)
|
||||||
self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:]
|
self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:]
|
||||||
self.sig_prv = Ed25519PrivateKey.from_private_bytes(self.sig_prv_bytes)
|
self.sig_prv = Ed25519PrivateKey.from_private_bytes(self.sig_prv_bytes)
|
||||||
|
|
||||||
self.pub = self.prv.public_key()
|
self.pub = self.prv.public_key()
|
||||||
self.pub_bytes = self.pub.public_bytes()
|
self.pub_bytes = self.pub.public_bytes()
|
||||||
|
|
||||||
@ -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
|
||||||
@ -640,7 +640,7 @@ class Identity:
|
|||||||
target_public_key = self.pub
|
target_public_key = self.pub
|
||||||
|
|
||||||
shared_key = ephemeral_key.exchange(target_public_key)
|
shared_key = ephemeral_key.exchange(target_public_key)
|
||||||
|
|
||||||
derived_key = RNS.Cryptography.hkdf(
|
derived_key = RNS.Cryptography.hkdf(
|
||||||
length=32,
|
length=32,
|
||||||
derive_from=shared_key,
|
derive_from=shared_key,
|
||||||
@ -690,14 +690,14 @@ class Identity:
|
|||||||
plaintext = fernet.decrypt(ciphertext)
|
plaintext = fernet.decrypt(ciphertext)
|
||||||
if ratchet_id_receiver:
|
if ratchet_id_receiver:
|
||||||
ratchet_id_receiver.latest_ratchet_id = ratchet_id
|
ratchet_id_receiver.latest_ratchet_id = ratchet_id
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
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,10 +717,10 @@ 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
|
||||||
|
|
||||||
return plaintext;
|
return plaintext;
|
||||||
else:
|
else:
|
||||||
RNS.log("Decryption failed because the token size was invalid.", RNS.LOG_DEBUG)
|
RNS.log("Decryption failed because the token size was invalid.", RNS.LOG_DEBUG)
|
||||||
@ -739,9 +739,9 @@ class Identity:
|
|||||||
"""
|
"""
|
||||||
if self.sig_prv != None:
|
if self.sig_prv != None:
|
||||||
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")
|
||||||
@ -770,7 +770,7 @@ class Identity:
|
|||||||
proof_data = signature
|
proof_data = signature
|
||||||
else:
|
else:
|
||||||
proof_data = packet.packet_hash + signature
|
proof_data = packet.packet_hash + signature
|
||||||
|
|
||||||
if destination == None:
|
if destination == None:
|
||||||
destination = packet.generate_proof_destination()
|
destination = packet.generate_proof_destination()
|
||||||
|
|
||||||
|
@ -80,14 +80,14 @@ class AX25KISSInterface(Interface):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 564
|
self.HW_MTU = 564
|
||||||
|
|
||||||
self.pyserial = serial
|
self.pyserial = serial
|
||||||
self.serial = None
|
self.serial = None
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
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,14 +336,14 @@ 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}]"
|
@ -74,7 +74,7 @@ class KISSInterface(Interface):
|
|||||||
|
|
||||||
from usbserial4a import serial4a as serial
|
from usbserial4a import serial4a as serial
|
||||||
self.parity = "N"
|
self.parity = "N"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
RNS.log("Could not load USB serial module for Android, KISS interface cannot be created.", RNS.LOG_CRITICAL)
|
RNS.log("Could not load USB serial module for Android, KISS interface cannot be created.", RNS.LOG_CRITICAL)
|
||||||
RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
|
RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
|
||||||
@ -83,9 +83,9 @@ class KISSInterface(Interface):
|
|||||||
raise SystemError("Android-specific interface was used on non-Android OS")
|
raise SystemError("Android-specific interface was used on non-Android OS")
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 564
|
self.HW_MTU = 564
|
||||||
|
|
||||||
if beacon_data == None:
|
if beacon_data == None:
|
||||||
beacon_data = ""
|
beacon_data = ""
|
||||||
|
|
||||||
@ -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
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ class KISSInterface(Interface):
|
|||||||
self.serial.timeout = 0.1
|
self.serial.timeout = 0.1
|
||||||
elif vid == 0x10C4:
|
elif vid == 0x10C4:
|
||||||
# Hardware parameters for SiLabs CP210x @ 115200 baud
|
# Hardware parameters for SiLabs CP210x @ 115200 baud
|
||||||
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
||||||
self.serial.USB_READ_TIMEOUT_MILLIS = 12
|
self.serial.USB_READ_TIMEOUT_MILLIS = 12
|
||||||
self.serial.timeout = 0.012
|
self.serial.timeout = 0.012
|
||||||
elif vid == 0x1A86 and pid == 0x55D4:
|
elif vid == 0x1A86 and pid == 0x55D4:
|
||||||
@ -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)
|
||||||
@ -352,7 +352,7 @@ class KISSInterface(Interface):
|
|||||||
data_buffer = data_buffer+bytes([byte])
|
data_buffer = data_buffer+bytes([byte])
|
||||||
elif (command == KISS.CMD_READY):
|
elif (command == KISS.CMD_READY):
|
||||||
self.process_queue()
|
self.process_queue()
|
||||||
|
|
||||||
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:
|
||||||
@ -365,21 +365,21 @@ 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}]"
|
@ -42,7 +42,7 @@ class KISS():
|
|||||||
FESC = 0xDB
|
FESC = 0xDB
|
||||||
TFEND = 0xDC
|
TFEND = 0xDC
|
||||||
TFESC = 0xDD
|
TFESC = 0xDD
|
||||||
|
|
||||||
CMD_UNKNOWN = 0xFE
|
CMD_UNKNOWN = 0xFE
|
||||||
CMD_DATA = 0x00
|
CMD_DATA = 0x00
|
||||||
CMD_FREQUENCY = 0x01
|
CMD_FREQUENCY = 0x01
|
||||||
@ -78,11 +78,11 @@ class KISS():
|
|||||||
|
|
||||||
DETECT_REQ = 0x73
|
DETECT_REQ = 0x73
|
||||||
DETECT_RESP = 0x46
|
DETECT_RESP = 0x46
|
||||||
|
|
||||||
RADIO_STATE_OFF = 0x00
|
RADIO_STATE_OFF = 0x00
|
||||||
RADIO_STATE_ON = 0x01
|
RADIO_STATE_ON = 0x01
|
||||||
RADIO_STATE_ASK = 0xFF
|
RADIO_STATE_ASK = 0xFF
|
||||||
|
|
||||||
CMD_ERROR = 0x90
|
CMD_ERROR = 0x90
|
||||||
ERROR_INITRADIO = 0x01
|
ERROR_INITRADIO = 0x01
|
||||||
ERROR_TXFAILED = 0x02
|
ERROR_TXFAILED = 0x02
|
||||||
@ -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,20 +181,20 @@ 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:
|
||||||
if self.rfcomm_reader != None:
|
if self.rfcomm_reader != None:
|
||||||
self.rfcomm_reader.close()
|
self.rfcomm_reader.close()
|
||||||
self.rfcomm_reader = None
|
self.rfcomm_reader = None
|
||||||
|
|
||||||
if self.rfcomm_writer != None:
|
if self.rfcomm_writer != None:
|
||||||
self.rfcomm_writer.close()
|
self.rfcomm_writer.close()
|
||||||
self.rfcomm_writer = None
|
self.rfcomm_writer = None
|
||||||
@ -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
|
||||||
|
|
||||||
@ -371,7 +371,7 @@ class RNodeInterface(Interface):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
self.bt_manager = None
|
self.bt_manager = None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
RNS.log("Could not load USB serial module for Android, RNode interface cannot be created.", RNS.LOG_CRITICAL)
|
RNS.log("Could not load USB serial module for Android, RNode interface cannot be created.", RNS.LOG_CRITICAL)
|
||||||
RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
|
RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
|
||||||
@ -382,7 +382,7 @@ class RNodeInterface(Interface):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 508
|
self.HW_MTU = 508
|
||||||
|
|
||||||
self.pyserial = serial
|
self.pyserial = serial
|
||||||
self.serial = None
|
self.serial = None
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
@ -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))
|
||||||
@ -561,11 +561,11 @@ class RNodeInterface(Interface):
|
|||||||
# self.ble = BLEConnection(owner=self, target_name=self.ble_name, target_bt_addr=self.ble_addr)
|
# self.ble = BLEConnection(owner=self, target_name=self.ble_name, target_bt_addr=self.ble_addr)
|
||||||
# self.serial = self.ble
|
# self.serial = self.ble
|
||||||
# RNS.log(f"New connection instance: "+str(self.ble))
|
# RNS.log(f"New connection instance: "+str(self.ble))
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@ -602,7 +602,7 @@ class RNodeInterface(Interface):
|
|||||||
self.serial.timeout = 0.1
|
self.serial.timeout = 0.1
|
||||||
elif vid == 0x10C4:
|
elif vid == 0x10C4:
|
||||||
# Hardware parameters for SiLabs CP210x @ 115200 baud
|
# Hardware parameters for SiLabs CP210x @ 115200 baud
|
||||||
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
||||||
self.serial.USB_READ_TIMEOUT_MILLIS = 12
|
self.serial.USB_READ_TIMEOUT_MILLIS = 12
|
||||||
self.serial.timeout = 0.012
|
self.serial.timeout = 0.012
|
||||||
elif vid == 0x1A86 and pid == 0x55D4:
|
elif vid == 0x1A86 and pid == 0x55D4:
|
||||||
@ -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,21 +680,21 @@ 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)
|
||||||
|
|
||||||
if self.serial != None:
|
if self.serial != None:
|
||||||
self.serial.close()
|
self.serial.close()
|
||||||
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):
|
||||||
self.setFrequency()
|
self.setFrequency()
|
||||||
@ -702,22 +702,22 @@ class RNodeInterface(Interface):
|
|||||||
|
|
||||||
self.setBandwidth()
|
self.setBandwidth()
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
|
|
||||||
self.setTXPower()
|
self.setTXPower()
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
|
|
||||||
self.setSpreadingFactor()
|
self.setSpreadingFactor()
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
|
|
||||||
self.setCodingRate()
|
self.setCodingRate()
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
|
|
||||||
self.setSTALock()
|
self.setSTALock()
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
|
|
||||||
self.setLTALock()
|
self.setLTALock()
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
|
|
||||||
self.setRadioState(KISS.RADIO_STATE_ON)
|
self.setRadioState(KISS.RADIO_STATE_ON)
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
|
|
||||||
@ -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
|
||||||
@ -788,16 +788,16 @@ class RNodeInterface(Interface):
|
|||||||
data = line_byte+line_data
|
data = line_byte+line_data
|
||||||
escaped_data = KISS.escape(data)
|
escaped_data = KISS.escape(data)
|
||||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND])
|
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_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 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):
|
||||||
@ -883,21 +883,21 @@ class RNodeInterface(Interface):
|
|||||||
if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ):
|
if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ):
|
||||||
if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN):
|
if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN):
|
||||||
self.firmware_ok = True
|
self.firmware_ok = True
|
||||||
|
|
||||||
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
|
||||||
@ -1188,7 +1188,7 @@ class RNodeInterface(Interface):
|
|||||||
atl = command_buffer[2] << 8 | command_buffer[3]
|
atl = command_buffer[2] << 8 | command_buffer[3]
|
||||||
cus = command_buffer[4] << 8 | command_buffer[5]
|
cus = command_buffer[4] << 8 | command_buffer[5]
|
||||||
cul = command_buffer[6] << 8 | command_buffer[7]
|
cul = command_buffer[6] << 8 | command_buffer[7]
|
||||||
|
|
||||||
self.r_airtime_short = ats/100.0
|
self.r_airtime_short = ats/100.0
|
||||||
self.r_airtime_long = atl/100.0
|
self.r_airtime_long = atl/100.0
|
||||||
self.r_channel_load_short = cus/100.0
|
self.r_channel_load_short = cus/100.0
|
||||||
@ -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()
|
||||||
|
|
||||||
@ -1343,7 +1343,7 @@ class RNodeInterface(Interface):
|
|||||||
if self.last_imagedata != None:
|
if self.last_imagedata != None:
|
||||||
self.display_image(self.last_imagedata)
|
self.display_image(self.last_imagedata)
|
||||||
self.enable_external_framebuffer()
|
self.enable_external_framebuffer()
|
||||||
|
|
||||||
elif hasattr(self, "bt_manager") and self.bt_manager != None and self.bt_manager.connected:
|
elif hasattr(self, "bt_manager") and self.bt_manager != None and self.bt_manager.connected:
|
||||||
self.configure_device()
|
self.configure_device()
|
||||||
if self.online:
|
if self.online:
|
||||||
@ -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
|
||||||
@ -1504,7 +1504,7 @@ class BLEConnection(BluetoothDispatcher):
|
|||||||
self.write_characteristic(self.rx_char, data)
|
self.write_characteristic(self.rx_char, data)
|
||||||
else:
|
else:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("An error occurred in {self} write loop: {e}", RNS.LOG_ERROR)
|
RNS.log("An error occurred in {self} write loop: {e}", RNS.LOG_ERROR)
|
||||||
RNS.trace_exception(e)
|
RNS.trace_exception(e)
|
||||||
@ -1552,7 +1552,7 @@ class BLEConnection(BluetoothDispatcher):
|
|||||||
self.owner.hw_errors.append({"error": KISS.ERROR_INVALID_BLE_MTU, "description": "The Bluetooth Low Energy transfer MTU could not be configured for the connected device, and communication has failed. Restart Reticulum and any connected applications to retry connecting."})
|
self.owner.hw_errors.append({"error": KISS.ERROR_INVALID_BLE_MTU, "description": "The Bluetooth Low Energy transfer MTU could not be configured for the connected device, and communication has failed. Restart Reticulum and any connected applications to retry connecting."})
|
||||||
self.close()
|
self.close()
|
||||||
self.should_run = False
|
self.should_run = False
|
||||||
|
|
||||||
self.close_gatt()
|
self.close_gatt()
|
||||||
|
|
||||||
self.connect_job_running = False
|
self.connect_job_running = False
|
||||||
@ -1599,14 +1599,14 @@ class BLEConnection(BluetoothDispatcher):
|
|||||||
def on_services(self, status, services):
|
def on_services(self, status, services):
|
||||||
if status == GATT_SUCCESS:
|
if status == GATT_SUCCESS:
|
||||||
self.rx_char = services.search(BLEConnection.UART_RX_CHAR_UUID)
|
self.rx_char = services.search(BLEConnection.UART_RX_CHAR_UUID)
|
||||||
|
|
||||||
if self.rx_char is not None:
|
if self.rx_char is not None:
|
||||||
self.tx_char = services.search(BLEConnection.UART_TX_CHAR_UUID)
|
self.tx_char = services.search(BLEConnection.UART_TX_CHAR_UUID)
|
||||||
|
|
||||||
if self.tx_char is not None:
|
if self.tx_char is not None:
|
||||||
if self.enable_notifications(self.tx_char):
|
if self.enable_notifications(self.tx_char):
|
||||||
RNS.log("Enabled notifications for BLE TX characteristic", RNS.LOG_DEBUG)
|
RNS.log("Enabled notifications for BLE TX characteristic", RNS.LOG_DEBUG)
|
||||||
|
|
||||||
RNS.log(f"Requesting BLE connection MTU update to {self.target_mtu}", RNS.LOG_DEBUG)
|
RNS.log(f"Requesting BLE connection MTU update to {self.target_mtu}", RNS.LOG_DEBUG)
|
||||||
self.mtu_requested_time = time.time()
|
self.mtu_requested_time = time.time()
|
||||||
self.request_mtu(self.target_mtu)
|
self.request_mtu(self.target_mtu)
|
||||||
|
@ -64,7 +64,7 @@ class SerialInterface(Interface):
|
|||||||
|
|
||||||
from usbserial4a import serial4a as serial
|
from usbserial4a import serial4a as serial
|
||||||
self.parity = "N"
|
self.parity = "N"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
RNS.log("Could not load USB serial module for Android, Serial interface cannot be created.", RNS.LOG_CRITICAL)
|
RNS.log("Could not load USB serial module for Android, Serial interface cannot be created.", RNS.LOG_CRITICAL)
|
||||||
RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
|
RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
|
||||||
@ -75,7 +75,7 @@ class SerialInterface(Interface):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 564
|
self.HW_MTU = 564
|
||||||
|
|
||||||
self.pyserial = serial
|
self.pyserial = serial
|
||||||
self.serial = None
|
self.serial = None
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
@ -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
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ class SerialInterface(Interface):
|
|||||||
self.serial.timeout = 0.1
|
self.serial.timeout = 0.1
|
||||||
elif vid == 0x10C4:
|
elif vid == 0x10C4:
|
||||||
# Hardware parameters for SiLabs CP210x @ 115200 baud
|
# Hardware parameters for SiLabs CP210x @ 115200 baud
|
||||||
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
||||||
self.serial.USB_READ_TIMEOUT_MILLIS = 12
|
self.serial.USB_READ_TIMEOUT_MILLIS = 12
|
||||||
self.serial.timeout = 0.012
|
self.serial.timeout = 0.012
|
||||||
elif vid == 0x1A86 and pid == 0x55D4:
|
elif vid == 0x1A86 and pid == 0x55D4:
|
||||||
@ -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):
|
||||||
@ -182,9 +182,9 @@ class SerialInterface(Interface):
|
|||||||
if self.online:
|
if self.online:
|
||||||
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
||||||
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:
|
||||||
@ -217,7 +217,7 @@ class SerialInterface(Interface):
|
|||||||
byte = HDLC.ESC
|
byte = HDLC.ESC
|
||||||
escape = False
|
escape = False
|
||||||
data_buffer = data_buffer+bytes([byte])
|
data_buffer = data_buffer+bytes([byte])
|
||||||
|
|
||||||
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:
|
||||||
@ -225,12 +225,12 @@ class SerialInterface(Interface):
|
|||||||
in_frame = False
|
in_frame = False
|
||||||
escape = False
|
escape = False
|
||||||
# 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()
|
||||||
|
|
||||||
@ -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}]"
|
||||||
|
@ -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')]
|
@ -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,19 +277,19 @@ 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]
|
||||||
|
|
||||||
udp_server = socketserver.UDPServer(address, self.handler_factory(self.processIncoming))
|
udp_server = socketserver.UDPServer(address, self.handler_factory(self.processIncoming))
|
||||||
self.interface_servers[ifname] = udp_server
|
self.interface_servers[ifname] = udp_server
|
||||||
|
|
||||||
thread = threading.Thread(target=udp_server.serve_forever)
|
thread = threading.Thread(target=udp_server.serve_forever)
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
@ -306,18 +306,18 @@ class AutoInterface(Interface):
|
|||||||
def discovery_handler(self, socket, ifname):
|
def discovery_handler(self, socket, ifname):
|
||||||
def announce_loop():
|
def announce_loop():
|
||||||
self.announce_handler(ifname)
|
self.announce_handler(ifname)
|
||||||
|
|
||||||
thread = threading.Thread(target=announce_loop)
|
thread = threading.Thread(target=announce_loop)
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
data, ipv6_src = socket.recvfrom(1024)
|
data, ipv6_src = socket.recvfrom(1024)
|
||||||
expected_hash = RNS.Identity.full_hash(self.group_id+ipv6_src[0].encode("utf-8"))
|
expected_hash = RNS.Identity.full_hash(self.group_id+ipv6_src[0].encode("utf-8"))
|
||||||
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,20 +389,20 @@ 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
|
||||||
|
|
||||||
|
|
||||||
def announce_handler(self, ifname):
|
def announce_handler(self, ifname):
|
||||||
while True:
|
while True:
|
||||||
self.peer_announce(ifname)
|
self.peer_announce(ifname)
|
||||||
time.sleep(self.announce_interval)
|
time.sleep(self.announce_interval)
|
||||||
|
|
||||||
def peer_announce(self, ifname):
|
def peer_announce(self, ifname):
|
||||||
try:
|
try:
|
||||||
link_local_address = self.adopted_interfaces[ifname]
|
link_local_address = self.adopted_interfaces[ifname]
|
||||||
@ -414,10 +414,10 @@ class AutoInterface(Interface):
|
|||||||
announce_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
|
announce_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
|
||||||
announce_socket.sendto(discovery_token, addr_info[0][4])
|
announce_socket.sendto(discovery_token, addr_info[0][4])
|
||||||
announce_socket.close()
|
announce_socket.close()
|
||||||
|
|
||||||
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,16 +464,16 @@ 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)
|
||||||
|
|
||||||
|
|
||||||
# Until per-device sub-interfacing is implemented,
|
# Until per-device sub-interfacing is implemented,
|
||||||
# ingress limiting should be disabled on AutoInterface
|
# ingress limiting should be disabled on AutoInterface
|
||||||
@ -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):
|
||||||
|
@ -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,18 +136,18 @@ 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()
|
||||||
|
|
||||||
self.loop.ext_owner = self
|
self.loop.ext_owner = self
|
||||||
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:
|
|
||||||
raise IOError("No tunnel control instance was created")
|
|
||||||
|
|
||||||
else:
|
if not i2p_destination in self.i2plib_tunnels:
|
||||||
|
raise OSError("No tunnel control instance was created")
|
||||||
|
|
||||||
|
else:
|
||||||
tn = self.i2plib_tunnels[i2p_destination]
|
tn = self.i2plib_tunnels[i2p_destination]
|
||||||
if tn != None and hasattr(tn, "status"):
|
if tn != None and hasattr(tn, "status"):
|
||||||
|
|
||||||
@ -167,28 +167,28 @@ 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
|
||||||
|
|
||||||
except ConnectionAbortedError as e:
|
except ConnectionAbortedError as e:
|
||||||
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,16 +313,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", 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
|
||||||
@ -393,7 +393,7 @@ class I2PInterfacePeer(Interface):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 1064
|
self.HW_MTU = 1064
|
||||||
|
|
||||||
self.IN = True
|
self.IN = True
|
||||||
self.OUT = False
|
self.OUT = False
|
||||||
self.socket = None
|
self.socket = None
|
||||||
@ -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)
|
||||||
@ -492,7 +492,7 @@ class I2PInterfacePeer(Interface):
|
|||||||
while self.awaiting_i2p_tunnel:
|
while self.awaiting_i2p_tunnel:
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
if not self.kiss_framing:
|
if not self.kiss_framing:
|
||||||
self.wants_tunnel = True
|
self.wants_tunnel = True
|
||||||
|
|
||||||
@ -525,37 +525,37 @@ class I2PInterfacePeer(Interface):
|
|||||||
|
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||||
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(I2PInterfacePeer.I2P_PROBE_AFTER))
|
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(I2PInterfacePeer.I2P_PROBE_AFTER))
|
||||||
|
|
||||||
def shutdown_socket(self, target_socket):
|
def shutdown_socket(self, target_socket):
|
||||||
if callable(target_socket.close):
|
if callable(target_socket.close):
|
||||||
try:
|
try:
|
||||||
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):
|
||||||
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
|
||||||
|
|
||||||
@ -564,15 +564,15 @@ class I2PInterfacePeer(Interface):
|
|||||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.socket.connect((self.target_ip, self.target_port))
|
self.socket.connect((self.target_ip, self.target_port))
|
||||||
self.online = True
|
self.online = True
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
@ -580,7 +580,7 @@ class I2PInterfacePeer(Interface):
|
|||||||
self.set_timeouts_linux()
|
self.set_timeouts_linux()
|
||||||
elif platform.system() == "Darwin":
|
elif platform.system() == "Darwin":
|
||||||
self.set_timeouts_osx()
|
self.set_timeouts_osx()
|
||||||
|
|
||||||
self.online = True
|
self.online = True
|
||||||
self.writing = False
|
self.writing = False
|
||||||
self.never_connected = False
|
self.never_connected = 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,13 +625,13 @@ 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)
|
||||||
if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count:
|
if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count:
|
||||||
self.parent_interface.rxb += len(data)
|
self.parent_interface.rxb += len(data)
|
||||||
|
|
||||||
self.owner.inbound(data, self)
|
self.owner.inbound(data, self)
|
||||||
|
|
||||||
def processOutgoing(self, data):
|
def processOutgoing(self, data):
|
||||||
@ -651,13 +651,13 @@ class I2PInterfacePeer(Interface):
|
|||||||
self.writing = False
|
self.writing = False
|
||||||
self.txb += len(data)
|
self.txb += len(data)
|
||||||
self.last_write = time.time()
|
self.last_write = time.time()
|
||||||
|
|
||||||
if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count:
|
if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count:
|
||||||
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,22 +683,22 @@ 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
|
||||||
|
|
||||||
if (time.time()-self.last_read > I2PInterfacePeer.I2P_READ_TIMEOUT):
|
if (time.time()-self.last_read > I2PInterfacePeer.I2P_READ_TIMEOUT):
|
||||||
RNS.log("I2P socket is unresponsive, restarting...", RNS.LOG_WARNING)
|
RNS.log("I2P socket is unresponsive, restarting...", RNS.LOG_WARNING)
|
||||||
if self.socket != None:
|
if self.socket != None:
|
||||||
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,18 +782,18 @@ 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
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
@ -832,7 +832,7 @@ class I2PInterface(Interface):
|
|||||||
|
|
||||||
def __init__(self, owner, name, rns_storagepath, peers, connectable = False, ifac_size = 16, ifac_netname = None, ifac_netkey = None):
|
def __init__(self, owner, name, rns_storagepath, peers, connectable = False, ifac_size = 16, ifac_netname = None, ifac_netkey = None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 1064
|
self.HW_MTU = 1064
|
||||||
|
|
||||||
self.online = False
|
self.online = False
|
||||||
@ -882,7 +882,7 @@ class I2PInterface(Interface):
|
|||||||
def createHandler(*args, **keys):
|
def createHandler(*args, **keys):
|
||||||
return I2PInterfaceHandler(callback, *args, **keys)
|
return I2PInterfaceHandler(callback, *args, **keys)
|
||||||
return createHandler
|
return createHandler
|
||||||
|
|
||||||
ThreadingI2PServer.allow_reuse_address = True
|
ThreadingI2PServer.allow_reuse_address = True
|
||||||
self.server = ThreadingI2PServer(self.address, handlerFactory(self.incoming_connection))
|
self.server = ThreadingI2PServer(self.address, handlerFactory(self.incoming_connection))
|
||||||
|
|
||||||
@ -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):
|
||||||
|
@ -140,16 +140,16 @@ 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():
|
||||||
RNS.Transport.inbound(selected_announce_packet.raw, selected_announce_packet.receiving_interface)
|
RNS.Transport.inbound(selected_announce_packet.raw, selected_announce_packet.receiving_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())
|
||||||
@ -170,7 +170,7 @@ class Interface:
|
|||||||
for i in range(1,dq_len):
|
for i in range(1,dq_len):
|
||||||
delta_sum += self.ia_freq_deque[i]-self.ia_freq_deque[i-1]
|
delta_sum += self.ia_freq_deque[i]-self.ia_freq_deque[i-1]
|
||||||
delta_sum += time.time() - self.ia_freq_deque[dq_len-1]
|
delta_sum += time.time() - self.ia_freq_deque[dq_len-1]
|
||||||
|
|
||||||
if delta_sum == 0:
|
if delta_sum == 0:
|
||||||
avg = 0
|
avg = 0
|
||||||
else:
|
else:
|
||||||
@ -187,7 +187,7 @@ class Interface:
|
|||||||
for i in range(1,dq_len):
|
for i in range(1,dq_len):
|
||||||
delta_sum += self.oa_freq_deque[i]-self.oa_freq_deque[i-1]
|
delta_sum += self.oa_freq_deque[i]-self.oa_freq_deque[i-1]
|
||||||
delta_sum += time.time() - self.oa_freq_deque[dq_len-1]
|
delta_sum += time.time() - self.oa_freq_deque[dq_len-1]
|
||||||
|
|
||||||
if delta_sum == 0:
|
if delta_sum == 0:
|
||||||
avg = 0
|
avg = 0
|
||||||
else:
|
else:
|
||||||
@ -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):
|
||||||
|
@ -71,9 +71,9 @@ class KISSInterface(Interface):
|
|||||||
RNS.panic()
|
RNS.panic()
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 564
|
self.HW_MTU = 564
|
||||||
|
|
||||||
if beacon_data == None:
|
if beacon_data == None:
|
||||||
beacon_data = ""
|
beacon_data = ""
|
||||||
|
|
||||||
@ -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,20 +205,20 @@ 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):
|
||||||
self.rxb += len(data)
|
self.rxb += len(data)
|
||||||
self.owner.inbound(data, self)
|
self.owner.inbound(data, self)
|
||||||
|
|
||||||
|
|
||||||
@ -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,21 +311,21 @@ 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}]"
|
@ -58,11 +58,11 @@ class LocalClientInterface(Interface):
|
|||||||
|
|
||||||
# TODO: Remove at some point
|
# TODO: Remove at some point
|
||||||
# self.rxptime = 0
|
# self.rxptime = 0
|
||||||
|
|
||||||
self.HW_MTU = 1064
|
self.HW_MTU = 1064
|
||||||
|
|
||||||
self.online = False
|
self.online = False
|
||||||
|
|
||||||
self.IN = True
|
self.IN = True
|
||||||
self.OUT = False
|
self.OUT = False
|
||||||
self.socket = None
|
self.socket = None
|
||||||
@ -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)
|
||||||
@ -146,20 +146,20 @@ class LocalClientInterface(Interface):
|
|||||||
time.sleep(LocalClientInterface.RECONNECT_WAIT+2)
|
time.sleep(LocalClientInterface.RECONNECT_WAIT+2)
|
||||||
RNS.Transport.shared_connection_reappeared()
|
RNS.Transport.shared_connection_reappeared()
|
||||||
threading.Thread(target=job, daemon=True).start()
|
threading.Thread(target=job, daemon=True).start()
|
||||||
|
|
||||||
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):
|
||||||
self.rxb += len(data)
|
self.rxb += len(data)
|
||||||
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
||||||
self.parent_interface.rxb += len(data)
|
self.parent_interface.rxb += len(data)
|
||||||
|
|
||||||
# TODO: Remove at some point
|
# TODO: Remove at some point
|
||||||
# processing_start = time.time()
|
# processing_start = time.time()
|
||||||
|
|
||||||
self.owner.inbound(data, self)
|
self.owner.inbound(data, self)
|
||||||
|
|
||||||
# TODO: Remove at some point
|
# TODO: Remove at some point
|
||||||
@ -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:
|
||||||
@ -234,29 +234,29 @@ class LocalClientInterface(Interface):
|
|||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
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,19 +276,19 @@ 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()
|
||||||
|
|
||||||
if self.is_connected_to_shared_instance:
|
if self.is_connected_to_shared_instance:
|
||||||
if nowarning == False:
|
if nowarning == False:
|
||||||
RNS.log("Permanently lost connection to local shared RNS instance. Exiting now.", RNS.LOG_CRITICAL)
|
RNS.log("Permanently lost connection to local shared RNS instance. Exiting now.", RNS.LOG_CRITICAL)
|
||||||
|
|
||||||
RNS.exit()
|
RNS.exit()
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "LocalInterface["+str(self.target_port)+"]"
|
return f"LocalInterface[{self.target_port}]"
|
||||||
|
|
||||||
|
|
||||||
class LocalServerInterface(Interface):
|
class LocalServerInterface(Interface):
|
||||||
@ -297,7 +297,7 @@ class LocalServerInterface(Interface):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.online = False
|
self.online = False
|
||||||
self.clients = 0
|
self.clients = 0
|
||||||
|
|
||||||
self.IN = True
|
self.IN = True
|
||||||
self.OUT = False
|
self.OUT = False
|
||||||
self.name = "Reticulum"
|
self.name = "Reticulum"
|
||||||
@ -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):
|
||||||
|
@ -49,7 +49,7 @@ class PipeInterface(Interface):
|
|||||||
|
|
||||||
owner = None
|
owner = None
|
||||||
command = None
|
command = None
|
||||||
|
|
||||||
def __init__(self, owner, name, command, respawn_delay):
|
def __init__(self, owner, name, command, respawn_delay):
|
||||||
if respawn_delay == None:
|
if respawn_delay == None:
|
||||||
respawn_delay = 5
|
respawn_delay = 5
|
||||||
@ -57,7 +57,7 @@ class PipeInterface(Interface):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 1064
|
self.HW_MTU = 1064
|
||||||
|
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
self.name = name
|
self.name = name
|
||||||
self.command = command
|
self.command = command
|
||||||
@ -72,18 +72,18 @@ 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)
|
||||||
self.pipe_is_open = True
|
self.pipe_is_open = True
|
||||||
@ -98,11 +98,11 @@ 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):
|
||||||
self.rxb += len(data)
|
self.rxb += len(data)
|
||||||
self.owner.inbound(data, self)
|
self.owner.inbound(data, self)
|
||||||
|
|
||||||
|
|
||||||
@ -111,9 +111,9 @@ class PipeInterface(Interface):
|
|||||||
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
||||||
written = self.process.stdin.write(data)
|
written = self.process.stdin.write(data)
|
||||||
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,9 +150,9 @@ 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:
|
||||||
self.online = False
|
self.online = False
|
||||||
try:
|
try:
|
||||||
@ -160,9 +160,9 @@ 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}]"
|
||||||
|
@ -33,7 +33,7 @@ class KISS():
|
|||||||
FESC = 0xDB
|
FESC = 0xDB
|
||||||
TFEND = 0xDC
|
TFEND = 0xDC
|
||||||
TFESC = 0xDD
|
TFESC = 0xDD
|
||||||
|
|
||||||
CMD_UNKNOWN = 0xFE
|
CMD_UNKNOWN = 0xFE
|
||||||
CMD_DATA = 0x00
|
CMD_DATA = 0x00
|
||||||
CMD_FREQUENCY = 0x01
|
CMD_FREQUENCY = 0x01
|
||||||
@ -69,11 +69,11 @@ class KISS():
|
|||||||
|
|
||||||
DETECT_REQ = 0x73
|
DETECT_REQ = 0x73
|
||||||
DETECT_RESP = 0x46
|
DETECT_RESP = 0x46
|
||||||
|
|
||||||
RADIO_STATE_OFF = 0x00
|
RADIO_STATE_OFF = 0x00
|
||||||
RADIO_STATE_ON = 0x01
|
RADIO_STATE_ON = 0x01
|
||||||
RADIO_STATE_ASK = 0xFF
|
RADIO_STATE_ASK = 0xFF
|
||||||
|
|
||||||
CMD_ERROR = 0x90
|
CMD_ERROR = 0x90
|
||||||
ERROR_INITRADIO = 0x01
|
ERROR_INITRADIO = 0x01
|
||||||
ERROR_TXFAILED = 0x02
|
ERROR_TXFAILED = 0x02
|
||||||
@ -91,7 +91,7 @@ class KISS():
|
|||||||
data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd]))
|
data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd]))
|
||||||
data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc]))
|
data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc]))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
class RNodeInterface(Interface):
|
class RNodeInterface(Interface):
|
||||||
MAX_CHUNK = 32768
|
MAX_CHUNK = 32768
|
||||||
@ -132,7 +132,7 @@ class RNodeInterface(Interface):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 508
|
self.HW_MTU = 508
|
||||||
|
|
||||||
self.pyserial = serial
|
self.pyserial = serial
|
||||||
self.serial = None
|
self.serial = None
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
@ -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,
|
||||||
@ -287,7 +287,7 @@ class RNodeInterface(Interface):
|
|||||||
write_timeout = None,
|
write_timeout = None,
|
||||||
dsrdtr = False,
|
dsrdtr = False,
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
RNS.log(f"Opening BLE connection for {self}...")
|
RNS.log(f"Opening BLE connection for {self}...")
|
||||||
if self.ble == None:
|
if self.ble == None:
|
||||||
@ -325,28 +325,28 @@ class RNodeInterface(Interface):
|
|||||||
detect_time = RNS.prettytime(time.time()-detect_time)
|
detect_time = RNS.prettytime(time.time()-detect_time)
|
||||||
else:
|
else:
|
||||||
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()
|
||||||
|
|
||||||
|
|
||||||
def initRadio(self):
|
def initRadio(self):
|
||||||
self.setFrequency()
|
self.setFrequency()
|
||||||
@ -365,27 +365,27 @@ class RNodeInterface(Interface):
|
|||||||
kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND])
|
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
|
||||||
@ -406,16 +406,16 @@ class RNodeInterface(Interface):
|
|||||||
data = line_byte+line_data
|
data = line_byte+line_data
|
||||||
escaped_data = KISS.escape(data)
|
escaped_data = KISS.escape(data)
|
||||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND])
|
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_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 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):
|
||||||
@ -428,7 +428,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
|
||||||
@ -440,28 +440,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:
|
||||||
@ -473,7 +473,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:
|
||||||
@ -485,14 +485,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):
|
||||||
@ -501,18 +501,18 @@ class RNodeInterface(Interface):
|
|||||||
if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ):
|
if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ):
|
||||||
if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN):
|
if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN):
|
||||||
self.firmware_ok = True
|
self.firmware_ok = True
|
||||||
|
|
||||||
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)
|
||||||
sleep(0.25);
|
sleep(0.25);
|
||||||
|
|
||||||
self.validcfg = True
|
self.validcfg = True
|
||||||
@ -542,7 +542,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
|
||||||
|
|
||||||
@ -573,7 +573,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)
|
||||||
|
|
||||||
@ -639,7 +639,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):
|
||||||
@ -655,26 +655,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
|
||||||
@ -752,7 +752,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
|
||||||
@ -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_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
|
||||||
@ -784,7 +784,7 @@ class RNodeInterface(Interface):
|
|||||||
atl = command_buffer[2] << 8 | command_buffer[3]
|
atl = command_buffer[2] << 8 | command_buffer[3]
|
||||||
cus = command_buffer[4] << 8 | command_buffer[5]
|
cus = command_buffer[4] << 8 | command_buffer[5]
|
||||||
cul = command_buffer[6] << 8 | command_buffer[7]
|
cul = command_buffer[6] << 8 | command_buffer[7]
|
||||||
|
|
||||||
self.r_airtime_short = ats/100.0
|
self.r_airtime_short = ats/100.0
|
||||||
self.r_airtime_long = atl/100.0
|
self.r_airtime_long = atl/100.0
|
||||||
self.r_channel_load_short = cus/100.0
|
self.r_channel_load_short = cus/100.0
|
||||||
@ -813,9 +813,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
|
||||||
@ -843,26 +843,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):
|
||||||
@ -870,11 +870,11 @@ class RNodeInterface(Interface):
|
|||||||
self.detected = True
|
self.detected = True
|
||||||
else:
|
else:
|
||||||
self.detected = False
|
self.detected = False
|
||||||
|
|
||||||
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
|
||||||
@ -883,15 +883,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()
|
||||||
@ -912,23 +912,23 @@ 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
|
||||||
self.disable_external_framebuffer()
|
self.disable_external_framebuffer()
|
||||||
self.setRadioState(KISS.RADIO_STATE_OFF)
|
self.setRadioState(KISS.RADIO_STATE_OFF)
|
||||||
self.leave()
|
self.leave()
|
||||||
|
|
||||||
if self.use_ble:
|
if self.use_ble:
|
||||||
self.ble.close()
|
self.ble.close()
|
||||||
|
|
||||||
@ -965,7 +965,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"
|
||||||
@ -1021,7 +1021,7 @@ class BLEConnection():
|
|||||||
if importlib.util.find_spec("bleak") != None:
|
if importlib.util.find_spec("bleak") != None:
|
||||||
import bleak
|
import bleak
|
||||||
BLEConnection.bleak = bleak
|
BLEConnection.bleak = bleak
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
BLEConnection.asyncio = asyncio
|
BLEConnection.asyncio = asyncio
|
||||||
else:
|
else:
|
||||||
@ -1100,7 +1100,7 @@ class BLEConnection():
|
|||||||
else:
|
else:
|
||||||
if self.target_bt_addr != None and device.address == self.target_bt_addr:
|
if self.target_bt_addr != None and device.address == self.target_bt_addr:
|
||||||
RNS.log(f"Can't connect to target device {self.target_bt_addr} over BLE, device is not bonded", RNS.LOG_ERROR)
|
RNS.log(f"Can't connect to target device {self.target_bt_addr} over BLE, device is not bonded", RNS.LOG_ERROR)
|
||||||
|
|
||||||
elif self.target_name != None and device.name == self.target_name:
|
elif self.target_name != None and device.name == self.target_name:
|
||||||
RNS.log(f"Can't connect to target device {self.target_name} over BLE, device is not bonded", RNS.LOG_ERROR)
|
RNS.log(f"Can't connect to target device {self.target_name} over BLE, device is not bonded", RNS.LOG_ERROR)
|
||||||
|
|
||||||
@ -1115,7 +1115,7 @@ class BLEConnection():
|
|||||||
if "props" in device.details and "Bonded" in device.details["props"]:
|
if "props" in device.details and "Bonded" in device.details["props"]:
|
||||||
if device.details["props"]["Bonded"] == True:
|
if device.details["props"]["Bonded"] == True:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log(f"Error while determining device bond status for {device}, the contained exception was: {e}", RNS.LOG_ERROR)
|
RNS.log(f"Error while determining device bond status for {device}, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class KISS():
|
|||||||
FESC = 0xDB
|
FESC = 0xDB
|
||||||
TFEND = 0xDC
|
TFEND = 0xDC
|
||||||
TFESC = 0xDD
|
TFESC = 0xDD
|
||||||
|
|
||||||
CMD_UNKNOWN = 0xFE
|
CMD_UNKNOWN = 0xFE
|
||||||
CMD_FREQUENCY = 0x01
|
CMD_FREQUENCY = 0x01
|
||||||
CMD_BANDWIDTH = 0x02
|
CMD_BANDWIDTH = 0x02
|
||||||
@ -94,11 +94,11 @@ class KISS():
|
|||||||
|
|
||||||
DETECT_REQ = 0x73
|
DETECT_REQ = 0x73
|
||||||
DETECT_RESP = 0x46
|
DETECT_RESP = 0x46
|
||||||
|
|
||||||
RADIO_STATE_OFF = 0x00
|
RADIO_STATE_OFF = 0x00
|
||||||
RADIO_STATE_ON = 0x01
|
RADIO_STATE_ON = 0x01
|
||||||
RADIO_STATE_ASK = 0xFF
|
RADIO_STATE_ASK = 0xFF
|
||||||
|
|
||||||
CMD_ERROR = 0x90
|
CMD_ERROR = 0x90
|
||||||
ERROR_INITRADIO = 0x01
|
ERROR_INITRADIO = 0x01
|
||||||
ERROR_TXFAILED = 0x02
|
ERROR_TXFAILED = 0x02
|
||||||
@ -159,7 +159,7 @@ class KISS():
|
|||||||
data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd]))
|
data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd]))
|
||||||
data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc]))
|
data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc]))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
class RNodeMultiInterface(Interface):
|
class RNodeMultiInterface(Interface):
|
||||||
MAX_CHUNK = 32768
|
MAX_CHUNK = 32768
|
||||||
@ -188,7 +188,7 @@ class RNodeMultiInterface(Interface):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 508
|
self.HW_MTU = 508
|
||||||
|
|
||||||
self.clients = 0
|
self.clients = 0
|
||||||
self.pyserial = serial
|
self.pyserial = serial
|
||||||
self.serial = None
|
self.serial = None
|
||||||
@ -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,
|
||||||
@ -294,15 +294,15 @@ class RNodeMultiInterface(Interface):
|
|||||||
|
|
||||||
self.detect()
|
self.detect()
|
||||||
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])
|
||||||
@ -327,44 +327,44 @@ class RNodeMultiInterface(Interface):
|
|||||||
|
|
||||||
interface.OUT = subint[10]
|
interface.OUT = subint[10]
|
||||||
interface.IN = True
|
interface.IN = True
|
||||||
|
|
||||||
interface.announce_rate_target = self.announce_rate_target
|
interface.announce_rate_target = self.announce_rate_target
|
||||||
interface.mode = self.mode
|
interface.mode = self.mode
|
||||||
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
|
||||||
@ -385,16 +385,16 @@ class RNodeMultiInterface(Interface):
|
|||||||
data = line_byte+line_data
|
data = line_byte+line_data
|
||||||
escaped_data = KISS.escape(data)
|
escaped_data = KISS.escape(data)
|
||||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND])
|
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_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 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,19 +478,19 @@ 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):
|
||||||
if (self.maj_version >= RNodeMultiInterface.REQUIRED_FW_VER_MAJ):
|
if (self.maj_version >= RNodeMultiInterface.REQUIRED_FW_VER_MAJ):
|
||||||
if (self.min_version >= RNodeMultiInterface.REQUIRED_FW_VER_MIN):
|
if (self.min_version >= RNodeMultiInterface.REQUIRED_FW_VER_MIN):
|
||||||
self.firmware_ok = True
|
self.firmware_ok = True
|
||||||
|
|
||||||
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
|
||||||
@ -737,7 +737,7 @@ class RNodeMultiInterface(Interface):
|
|||||||
atl = command_buffer[2] << 8 | command_buffer[3]
|
atl = command_buffer[2] << 8 | command_buffer[3]
|
||||||
cus = command_buffer[4] << 8 | command_buffer[5]
|
cus = command_buffer[4] << 8 | command_buffer[5]
|
||||||
cul = command_buffer[6] << 8 | command_buffer[7]
|
cul = command_buffer[6] << 8 | command_buffer[7]
|
||||||
|
|
||||||
self.r_airtime_short = ats/100.0
|
self.r_airtime_short = ats/100.0
|
||||||
self.r_airtime_long = atl/100.0
|
self.r_airtime_long = atl/100.0
|
||||||
self.r_channel_load_short = cus/100.0
|
self.r_channel_load_short = cus/100.0
|
||||||
@ -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):
|
||||||
@ -804,11 +804,11 @@ class RNodeMultiInterface(Interface):
|
|||||||
# add the interface to the back of the list, they're all given from vport 0 and up in order
|
# add the interface to the back of the list, they're all given from vport 0 and up in order
|
||||||
self.subinterface_types.append(KISS.interface_type_to_str(command_buffer[1]))
|
self.subinterface_types.append(KISS.interface_type_to_str(command_buffer[1]))
|
||||||
command_buffer = b""
|
command_buffer = b""
|
||||||
|
|
||||||
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
|
||||||
@ -918,7 +918,7 @@ class RNodeSubInterface(Interface):
|
|||||||
RNS.panic()
|
RNS.panic()
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if index == 0:
|
if index == 0:
|
||||||
sel_cmd = KISS.CMD_SEL_INT0
|
sel_cmd = KISS.CMD_SEL_INT0
|
||||||
data_cmd= KISS.CMD_INT0_DATA
|
data_cmd= KISS.CMD_INT0_DATA
|
||||||
@ -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,18 +1068,18 @@ 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)
|
||||||
|
|
||||||
|
|
||||||
def initRadio(self):
|
def initRadio(self):
|
||||||
self.parent_interface.setFrequency(self.frequency, self)
|
self.parent_interface.setFrequency(self.frequency, self)
|
||||||
@ -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}]"
|
||||||
|
@ -63,7 +63,7 @@ class SerialInterface(Interface):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 564
|
self.HW_MTU = 564
|
||||||
|
|
||||||
self.pyserial = serial
|
self.pyserial = serial
|
||||||
self.serial = None
|
self.serial = None
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
@ -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,11 +118,11 @@ 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):
|
||||||
self.rxb += len(data)
|
self.rxb += len(data)
|
||||||
self.owner.inbound(data, self)
|
self.owner.inbound(data, self)
|
||||||
|
|
||||||
|
|
||||||
@ -130,9 +130,9 @@ class SerialInterface(Interface):
|
|||||||
if self.online:
|
if self.online:
|
||||||
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
||||||
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):
|
||||||
@ -164,7 +164,7 @@ class SerialInterface(Interface):
|
|||||||
byte = HDLC.ESC
|
byte = HDLC.ESC
|
||||||
escape = False
|
escape = False
|
||||||
data_buffer = data_buffer+bytes([byte])
|
data_buffer = data_buffer+bytes([byte])
|
||||||
|
|
||||||
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:
|
||||||
@ -172,12 +172,12 @@ class SerialInterface(Interface):
|
|||||||
in_frame = False
|
in_frame = False
|
||||||
escape = False
|
escape = False
|
||||||
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()
|
||||||
|
|
||||||
@ -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}]"
|
||||||
|
@ -80,9 +80,9 @@ class TCPClientInterface(Interface):
|
|||||||
|
|
||||||
def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None, max_reconnect_tries=None, kiss_framing=False, i2p_tunneled = False, connect_timeout = None):
|
def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None, max_reconnect_tries=None, kiss_framing=False, i2p_tunneled = False, connect_timeout = None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.HW_MTU = 1064
|
self.HW_MTU = 1064
|
||||||
|
|
||||||
self.IN = True
|
self.IN = True
|
||||||
self.OUT = False
|
self.OUT = False
|
||||||
self.socket = None
|
self.socket = None
|
||||||
@ -99,7 +99,7 @@ class TCPClientInterface(Interface):
|
|||||||
self.i2p_tunneled = i2p_tunneled
|
self.i2p_tunneled = i2p_tunneled
|
||||||
self.mode = RNS.Interfaces.Interface.Interface.MODE_FULL
|
self.mode = RNS.Interfaces.Interface.Interface.MODE_FULL
|
||||||
self.bitrate = TCPClientInterface.BITRATE_GUESS
|
self.bitrate = TCPClientInterface.BITRATE_GUESS
|
||||||
|
|
||||||
if max_reconnect_tries == None:
|
if max_reconnect_tries == None:
|
||||||
self.max_reconnect_tries = TCPClientInterface.RECONNECT_MAX_TRIES
|
self.max_reconnect_tries = TCPClientInterface.RECONNECT_MAX_TRIES
|
||||||
else:
|
else:
|
||||||
@ -128,14 +128,14 @@ class TCPClientInterface(Interface):
|
|||||||
self.connect_timeout = connect_timeout
|
self.connect_timeout = connect_timeout
|
||||||
else:
|
else:
|
||||||
self.connect_timeout = TCPClientInterface.INITIAL_CONNECT_TIMEOUT
|
self.connect_timeout = TCPClientInterface.INITIAL_CONNECT_TIMEOUT
|
||||||
|
|
||||||
if TCPClientInterface.SYNCHRONOUS_START:
|
if TCPClientInterface.SYNCHRONOUS_START:
|
||||||
self.initial_connect()
|
self.initial_connect()
|
||||||
else:
|
else:
|
||||||
thread = threading.Thread(target=self.initial_connect)
|
thread = threading.Thread(target=self.initial_connect)
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
def initial_connect(self):
|
def initial_connect(self):
|
||||||
if not self.connect(initial=True):
|
if not self.connect(initial=True):
|
||||||
thread = threading.Thread(target=self.reconnect)
|
thread = threading.Thread(target=self.reconnect)
|
||||||
@ -170,35 +170,35 @@ class TCPClientInterface(Interface):
|
|||||||
TCP_KEEPIDLE = 0x10
|
TCP_KEEPIDLE = 0x10
|
||||||
|
|
||||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||||
|
|
||||||
if not self.i2p_tunneled:
|
if not self.i2p_tunneled:
|
||||||
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.TCP_PROBE_AFTER))
|
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.TCP_PROBE_AFTER))
|
||||||
else:
|
else:
|
||||||
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.I2P_PROBE_AFTER))
|
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.I2P_PROBE_AFTER))
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
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,14 +208,14 @@ 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:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ class TCPClientInterface(Interface):
|
|||||||
self.set_timeouts_linux()
|
self.set_timeouts_linux()
|
||||||
elif platform.system() == "Darwin":
|
elif platform.system() == "Darwin":
|
||||||
self.set_timeouts_osx()
|
self.set_timeouts_osx()
|
||||||
|
|
||||||
self.online = True
|
self.online = True
|
||||||
self.writing = False
|
self.writing = False
|
||||||
self.never_connected = False
|
self.never_connected = False
|
||||||
@ -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,13 +263,13 @@ 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)
|
||||||
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
||||||
self.parent_interface.rxb += len(data)
|
self.parent_interface.rxb += len(data)
|
||||||
|
|
||||||
self.owner.inbound(data, self)
|
self.owner.inbound(data, self)
|
||||||
|
|
||||||
def processOutgoing(self, data):
|
def processOutgoing(self, 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,18 +361,18 @@ 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
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
@ -427,7 +427,7 @@ class TCPServerInterface(Interface):
|
|||||||
|
|
||||||
self.online = False
|
self.online = False
|
||||||
self.clients = 0
|
self.clients = 0
|
||||||
|
|
||||||
self.IN = True
|
self.IN = True
|
||||||
self.OUT = False
|
self.OUT = False
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -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
|
||||||
@ -474,7 +474,7 @@ class TCPServerInterface(Interface):
|
|||||||
spawned_interface.target_port = str(handler.client_address[1])
|
spawned_interface.target_port = str(handler.client_address[1])
|
||||||
spawned_interface.parent_interface = self
|
spawned_interface.parent_interface = self
|
||||||
spawned_interface.bitrate = self.bitrate
|
spawned_interface.bitrate = self.bitrate
|
||||||
|
|
||||||
spawned_interface.ifac_size = self.ifac_size
|
spawned_interface.ifac_size = self.ifac_size
|
||||||
spawned_interface.ifac_netname = self.ifac_netname
|
spawned_interface.ifac_netname = self.ifac_netname
|
||||||
spawned_interface.ifac_netkey = self.ifac_netkey
|
spawned_interface.ifac_netkey = self.ifac_netkey
|
||||||
@ -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):
|
||||||
|
@ -99,13 +99,13 @@ class UDPInterface(Interface):
|
|||||||
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||||
udp_socket.sendto(data, (self.forward_ip, self.forward_port))
|
udp_socket.sendto(data, (self.forward_ip, self.forward_port))
|
||||||
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):
|
||||||
|
@ -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')]
|
||||||
|
106
RNS/Link.py
106
RNS/Link.py
@ -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()
|
||||||
@ -124,13 +124,13 @@ class Link:
|
|||||||
RNS.Transport.register_link(link)
|
RNS.Transport.register_link(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:
|
||||||
@ -189,7 +189,7 @@ class Link:
|
|||||||
self.sig_prv = Ed25519PrivateKey.generate()
|
self.sig_prv = Ed25519PrivateKey.generate()
|
||||||
|
|
||||||
self.fernet = None
|
self.fernet = None
|
||||||
|
|
||||||
self.pub = self.prv.public_key()
|
self.pub = self.prv.public_key()
|
||||||
self.pub_bytes = self.pub.public_bytes()
|
self.pub_bytes = self.pub.public_bytes()
|
||||||
|
|
||||||
@ -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):
|
||||||
@ -288,10 +288,10 @@ class Link:
|
|||||||
self.establishment_cost += len(packet.raw)
|
self.establishment_cost += len(packet.raw)
|
||||||
signed_data = self.link_id+self.peer_pub_bytes+self.peer_sig_pub_bytes
|
signed_data = self.link_id+self.peer_pub_bytes+self.peer_sig_pub_bytes
|
||||||
signature = packet.data[:RNS.Identity.SIGLENGTH//8]
|
signature = packet.data[:RNS.Identity.SIGLENGTH//8]
|
||||||
|
|
||||||
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,8 +300,8 @@ 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):
|
||||||
@ -377,10 +377,10 @@ class Link:
|
|||||||
timeout = timeout,
|
timeout = timeout,
|
||||||
request_size = len(packed_request),
|
request_size = len(packed_request),
|
||||||
)
|
)
|
||||||
|
|
||||||
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):
|
||||||
@ -547,7 +547,7 @@ class Link:
|
|||||||
resource.cancel()
|
resource.cancel()
|
||||||
if self._channel:
|
if self._channel:
|
||||||
self._channel._shutdown()
|
self._channel._shutdown()
|
||||||
|
|
||||||
self.prv = None
|
self.prv = None
|
||||||
self.pub = None
|
self.pub = None
|
||||||
self.pub_bytes = None
|
self.pub_bytes = None
|
||||||
@ -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):
|
||||||
@ -620,7 +620,7 @@ class Link:
|
|||||||
self.status = Link.STALE
|
self.status = Link.STALE
|
||||||
else:
|
else:
|
||||||
sleep_time = self.keepalive
|
sleep_time = self.keepalive
|
||||||
|
|
||||||
else:
|
else:
|
||||||
sleep_time = (last_inbound + self.keepalive) - time.time()
|
sleep_time = (last_inbound + self.keepalive) - time.time()
|
||||||
|
|
||||||
@ -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
|
||||||
|
|
||||||
@ -655,7 +655,7 @@ class Link:
|
|||||||
self.snr = packet.snr
|
self.snr = packet.snr
|
||||||
if packet.q != None:
|
if packet.q != None:
|
||||||
self.q = packet.q
|
self.q = packet.q
|
||||||
|
|
||||||
def send_keepalive(self):
|
def send_keepalive(self):
|
||||||
keepalive_packet = RNS.Packet(self, bytes([0xFF]), context=RNS.Packet.KEEPALIVE)
|
keepalive_packet = RNS.Packet(self, bytes([0xFF]), context=RNS.Packet.KEEPALIVE)
|
||||||
keepalive_packet.send()
|
keepalive_packet.send()
|
||||||
@ -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)
|
||||||
@ -782,7 +782,7 @@ class Link:
|
|||||||
thread = threading.Thread(target=self.callbacks.packet, args=(plaintext, packet))
|
thread = threading.Thread(target=self.callbacks.packet, args=(plaintext, packet))
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
if self.destination.proof_strategy == RNS.Destination.PROVE_ALL:
|
if self.destination.proof_strategy == RNS.Destination.PROVE_ALL:
|
||||||
packet.prove()
|
packet.prove()
|
||||||
should_query = True
|
should_query = True
|
||||||
@ -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,8 +814,8 @@ 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)
|
||||||
|
|
||||||
elif packet.context == RNS.Packet.REQUEST:
|
elif packet.context == RNS.Packet.REQUEST:
|
||||||
@ -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)
|
||||||
|
|
||||||
@ -903,7 +903,7 @@ class Link:
|
|||||||
if not packet.packet_hash in resource.req_hashlist:
|
if not packet.packet_hash in resource.req_hashlist:
|
||||||
resource.req_hashlist.append(packet.packet_hash)
|
resource.req_hashlist.append(packet.packet_hash)
|
||||||
resource.request(plaintext)
|
resource.request(plaintext)
|
||||||
|
|
||||||
# TODO: Test and possibly enable this at some point
|
# TODO: Test and possibly enable this at some point
|
||||||
# def request_job():
|
# def request_job():
|
||||||
# resource.request(plaintext)
|
# resource.request(plaintext)
|
||||||
@ -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
|
||||||
|
|
||||||
|
|
||||||
@ -984,11 +984,11 @@ class Link:
|
|||||||
try:
|
try:
|
||||||
if not self.fernet:
|
if not self.fernet:
|
||||||
self.fernet = Fernet(self.derived_key)
|
self.fernet = Fernet(self.derived_key)
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
@ -1140,7 +1140,7 @@ class RequestReceipt():
|
|||||||
elif self.resource != None:
|
elif self.resource != None:
|
||||||
self.hash = resource.request_id
|
self.hash = resource.request_id
|
||||||
resource.set_callback(self.request_resource_concluded)
|
resource.set_callback(self.request_resource_concluded)
|
||||||
|
|
||||||
self.link = link
|
self.link = link
|
||||||
self.request_id = self.hash
|
self.request_id = self.hash
|
||||||
self.request_size = request_size
|
self.request_size = request_size
|
||||||
@ -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):
|
||||||
@ -1224,16 +1224,16 @@ class RequestReceipt():
|
|||||||
self.packet_receipt.callbacks.delivery(self.packet_receipt)
|
self.packet_receipt.callbacks.delivery(self.packet_receipt)
|
||||||
|
|
||||||
self.progress = resource.get_progress()
|
self.progress = resource.get_progress()
|
||||||
|
|
||||||
if self.callbacks.progress != None:
|
if self.callbacks.progress != None:
|
||||||
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()
|
||||||
|
|
||||||
|
|
||||||
def response_received(self, response):
|
def response_received(self, response):
|
||||||
if not self.status == RequestReceipt.FAILED:
|
if not self.status == RequestReceipt.FAILED:
|
||||||
self.progress = 1.0
|
self.progress = 1.0
|
||||||
@ -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):
|
||||||
"""
|
"""
|
||||||
|
@ -97,7 +97,7 @@ class Packet:
|
|||||||
# the below calculation; 383 bytes.
|
# the below calculation; 383 bytes.
|
||||||
ENCRYPTED_MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.FERNET_OVERHEAD-RNS.Identity.KEYSIZE//16)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1
|
ENCRYPTED_MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.FERNET_OVERHEAD-RNS.Identity.KEYSIZE//16)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1
|
||||||
"""
|
"""
|
||||||
The maximum size of the payload data in a single encrypted packet
|
The maximum size of the payload data in a single encrypted packet
|
||||||
"""
|
"""
|
||||||
PLAIN_MDU = MDU
|
PLAIN_MDU = MDU
|
||||||
"""
|
"""
|
||||||
@ -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,19 +250,19 @@ 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):
|
||||||
"""
|
"""
|
||||||
Sends the packet.
|
Sends the packet.
|
||||||
|
|
||||||
:returns: A :ref:`RNS.PacketReceipt<api-packetreceipt>` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned.
|
:returns: A :ref:`RNS.PacketReceipt<api-packetreceipt>` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned.
|
||||||
"""
|
"""
|
||||||
if not self.sent:
|
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
|
||||||
@ -278,21 +278,21 @@ class Packet:
|
|||||||
self.sent = False
|
self.sent = False
|
||||||
self.receipt = None
|
self.receipt = None
|
||||||
return False
|
return False
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise IOError("Packet was already sent")
|
raise OSError("Packet was already sent")
|
||||||
|
|
||||||
def resend(self):
|
def resend(self):
|
||||||
"""
|
"""
|
||||||
Re-sends the packet.
|
Re-sends the packet.
|
||||||
|
|
||||||
:returns: A :ref:`RNS.PacketReceipt<api-packetreceipt>` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned.
|
:returns: A :ref:`RNS.PacketReceipt<api-packetreceipt>` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned.
|
||||||
"""
|
"""
|
||||||
if self.sent:
|
if self.sent:
|
||||||
# Re-pack the packet to obtain new ciphertext for
|
# Re-pack the packet to obtain new ciphertext for
|
||||||
# encrypted destinations
|
# encrypted destinations
|
||||||
self.pack()
|
self.pack()
|
||||||
|
|
||||||
if RNS.Transport.outbound(self):
|
if RNS.Transport.outbound(self):
|
||||||
return self.receipt
|
return self.receipt
|
||||||
else:
|
else:
|
||||||
@ -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:
|
||||||
@ -388,7 +388,7 @@ class PacketReceipt:
|
|||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
"""
|
"""
|
||||||
:returns: The status of the associated :ref:`RNS.Packet<api-packet>` instance. Can be one of ``RNS.PacketReceipt.SENT``, ``RNS.PacketReceipt.DELIVERED``, ``RNS.PacketReceipt.FAILED`` or ``RNS.PacketReceipt.CULLED``.
|
:returns: The status of the associated :ref:`RNS.Packet<api-packet>` instance. Can be one of ``RNS.PacketReceipt.SENT``, ``RNS.PacketReceipt.DELIVERED``, ``RNS.PacketReceipt.FAILED`` or ``RNS.PacketReceipt.CULLED``.
|
||||||
"""
|
"""
|
||||||
return self.status
|
return self.status
|
||||||
|
|
||||||
@ -419,10 +419,10 @@ 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
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@ -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,8 +489,8 @@ 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:
|
||||||
return False
|
return False
|
||||||
@ -524,7 +524,7 @@ class PacketReceipt:
|
|||||||
def set_timeout(self, timeout):
|
def set_timeout(self, timeout):
|
||||||
"""
|
"""
|
||||||
Sets a timeout in seconds
|
Sets a timeout in seconds
|
||||||
|
|
||||||
:param timeout: The timeout in seconds.
|
:param timeout: The timeout in seconds.
|
||||||
"""
|
"""
|
||||||
self.timeout = float(timeout)
|
self.timeout = float(timeout)
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
|
|
||||||
class Resolver:
|
class Resolver:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_identity(full_name):
|
def resolve_identity(full_name):
|
||||||
pass
|
pass
|
@ -59,11 +59,11 @@ class Resource:
|
|||||||
|
|
||||||
# The maximum window size for transfers on fast links
|
# The maximum window size for transfers on fast links
|
||||||
WINDOW_MAX_FAST = 75
|
WINDOW_MAX_FAST = 75
|
||||||
|
|
||||||
# For calculating maps and guard segments, this
|
# For calculating maps and guard segments, this
|
||||||
# must be set to the global maximum window.
|
# must be set to the global maximum window.
|
||||||
WINDOW_MAX = WINDOW_MAX_FAST
|
WINDOW_MAX = WINDOW_MAX_FAST
|
||||||
|
|
||||||
# If the fast rate is sustained for this many request
|
# If the fast rate is sustained for this many request
|
||||||
# rounds, the fast link window size will be allowed.
|
# rounds, the fast link window size will be allowed.
|
||||||
FAST_RATE_THRESHOLD = WINDOW_MAX_SLOW - WINDOW - 2
|
FAST_RATE_THRESHOLD = WINDOW_MAX_SLOW - WINDOW - 2
|
||||||
@ -111,7 +111,7 @@ class Resource:
|
|||||||
# fit in 3 bytes in resource advertisements.
|
# fit in 3 bytes in resource advertisements.
|
||||||
MAX_EFFICIENT_SIZE = 16 * 1024 * 1024 - 1
|
MAX_EFFICIENT_SIZE = 16 * 1024 * 1024 - 1
|
||||||
RESPONSE_MAX_GRACE_TIME = 10
|
RESPONSE_MAX_GRACE_TIME = 10
|
||||||
|
|
||||||
# The maximum size to auto-compress with
|
# The maximum size to auto-compress with
|
||||||
# bz2 before sending.
|
# bz2 before sending.
|
||||||
AUTO_COMPRESS_MAX_SIZE = MAX_EFFICIENT_SIZE
|
AUTO_COMPRESS_MAX_SIZE = MAX_EFFICIENT_SIZE
|
||||||
@ -172,7 +172,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:
|
||||||
@ -185,7 +185,7 @@ class Resource:
|
|||||||
resource.waiting_for_hmu = False
|
resource.waiting_for_hmu = False
|
||||||
resource.receiving_part = False
|
resource.receiving_part = False
|
||||||
resource.consecutive_completed_height = -1
|
resource.consecutive_completed_height = -1
|
||||||
|
|
||||||
if not resource.link.has_incoming_resource(resource):
|
if not resource.link.has_incoming_resource(resource):
|
||||||
resource.link.register_incoming_resource(resource)
|
resource.link.register_incoming_resource(resource)
|
||||||
|
|
||||||
@ -194,7 +194,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)
|
||||||
|
|
||||||
@ -203,7 +203,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:
|
||||||
@ -256,7 +256,7 @@ class Resource:
|
|||||||
data_size = len(data)
|
data_size = len(data)
|
||||||
self.grand_total_parts = math.ceil(data_size/Resource.SDU)
|
self.grand_total_parts = math.ceil(data_size/Resource.SDU)
|
||||||
self.total_size = data_size
|
self.total_size = data_size
|
||||||
|
|
||||||
resource_data = data
|
resource_data = data
|
||||||
self.total_segments = 1
|
self.total_segments = 1
|
||||||
self.segment_index = 1
|
self.segment_index = 1
|
||||||
@ -309,7 +309,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
|
||||||
|
|
||||||
@ -318,12 +318,12 @@ 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]
|
||||||
self.data += self.compressed_data
|
self.data += self.compressed_data
|
||||||
|
|
||||||
self.compressed = True
|
self.compressed = True
|
||||||
self.uncompressed_data = None
|
self.uncompressed_data = None
|
||||||
|
|
||||||
@ -348,11 +348,11 @@ class Resource:
|
|||||||
self.size = len(self.data)
|
self.size = len(self.data)
|
||||||
self.sent_parts = 0
|
self.sent_parts = 0
|
||||||
hashmap_entries = int(math.ceil(self.size/float(Resource.SDU)))
|
hashmap_entries = int(math.ceil(self.size/float(Resource.SDU)))
|
||||||
|
|
||||||
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,13 +388,13 @@ 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()
|
||||||
else:
|
else:
|
||||||
self.receive_lock = Lock()
|
self.receive_lock = Lock()
|
||||||
|
|
||||||
|
|
||||||
def hashmap_update_packet(self, plaintext):
|
def hashmap_update_packet(self, plaintext):
|
||||||
if not self.status == Resource.FAILED:
|
if not self.status == Resource.FAILED:
|
||||||
@ -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,9 +487,9 @@ 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()
|
||||||
|
|
||||||
|
|
||||||
elif self.status == Resource.TRANSFERRING:
|
elif self.status == Resource.TRANSFERRING:
|
||||||
if not self.initiator:
|
if not self.initiator:
|
||||||
@ -504,11 +504,11 @@ class Resource:
|
|||||||
retries_used = self.max_retries - self.retries_left
|
retries_used = self.max_retries - self.retries_left
|
||||||
extra_wait = retries_used * Resource.PER_RETRY_DELAY
|
extra_wait = retries_used * Resource.PER_RETRY_DELAY
|
||||||
sleep_time = self.last_activity + (rtt*(self.part_timeout_factor+window_remaining)) + Resource.RETRY_GRACE_TIME + extra_wait - time.time()
|
sleep_time = self.last_activity + (rtt*(self.part_timeout_factor+window_remaining)) + Resource.RETRY_GRACE_TIME + extra_wait - time.time()
|
||||||
|
|
||||||
if sleep_time < 0:
|
if 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:
|
||||||
@ -554,7 +554,7 @@ class Resource:
|
|||||||
if sleep_time == None or sleep_time < 0:
|
if sleep_time == None or sleep_time < 0:
|
||||||
RNS.log("Timing error, cancelling resource transfer.", RNS.LOG_ERROR)
|
RNS.log("Timing error, cancelling resource transfer.", RNS.LOG_ERROR)
|
||||||
self.cancel()
|
self.cancel()
|
||||||
|
|
||||||
if sleep_time != None:
|
if sleep_time != None:
|
||||||
sleep(min(sleep_time, Resource.WATCHDOG_MAX_SLEEP))
|
sleep(min(sleep_time, Resource.WATCHDOG_MAX_SLEEP))
|
||||||
|
|
||||||
@ -591,7 +591,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)
|
||||||
@ -602,7 +602,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):
|
||||||
@ -614,7 +614,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):
|
||||||
@ -626,7 +626,7 @@ class Resource:
|
|||||||
proof_packet.send()
|
proof_packet.send()
|
||||||
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):
|
||||||
@ -657,7 +657,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"):
|
||||||
@ -665,7 +665,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
|
||||||
@ -692,7 +692,7 @@ class Resource:
|
|||||||
if self.req_resp == None:
|
if self.req_resp == None:
|
||||||
self.req_resp = self.last_activity
|
self.req_resp = self.last_activity
|
||||||
rtt = self.req_resp-self.req_sent
|
rtt = self.req_resp-self.req_sent
|
||||||
|
|
||||||
self.part_timeout_factor = Resource.PART_TIMEOUT_FACTOR_AFTER_RTT
|
self.part_timeout_factor = Resource.PART_TIMEOUT_FACTOR_AFTER_RTT
|
||||||
if self.rtt == None:
|
if self.rtt == None:
|
||||||
self.rtt = self.link.rtt
|
self.rtt = self.link.rtt
|
||||||
@ -732,7 +732,7 @@ class Resource:
|
|||||||
# Update consecutive completed pointer
|
# Update consecutive completed pointer
|
||||||
if i == self.consecutive_completed_height + 1:
|
if i == self.consecutive_completed_height + 1:
|
||||||
self.consecutive_completed_height = i
|
self.consecutive_completed_height = i
|
||||||
|
|
||||||
cp = self.consecutive_completed_height + 1
|
cp = self.consecutive_completed_height + 1
|
||||||
while cp < len(self.parts) and self.parts[cp] != None:
|
while cp < len(self.parts) and self.parts[cp] != None:
|
||||||
self.consecutive_completed_height = cp
|
self.consecutive_completed_height = cp
|
||||||
@ -742,7 +742,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
|
||||||
|
|
||||||
@ -797,7 +797,7 @@ class Resource:
|
|||||||
i = 0; pn = self.consecutive_completed_height+1
|
i = 0; pn = self.consecutive_completed_height+1
|
||||||
search_start = pn
|
search_start = pn
|
||||||
search_size = self.window
|
search_size = self.window
|
||||||
|
|
||||||
for part in self.parts[search_start:search_start+search_size]:
|
for part in self.parts[search_start:search_start+search_size]:
|
||||||
if part == None:
|
if part == None:
|
||||||
part_hash = self.hashmap[pn]
|
part_hash = self.hashmap[pn]
|
||||||
@ -830,7 +830,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
|
||||||
@ -876,12 +876,12 @@ 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:
|
||||||
last_map_hash = request_data[1:Resource.MAPHASH_LEN+1]
|
last_map_hash = request_data[1:Resource.MAPHASH_LEN+1]
|
||||||
|
|
||||||
part_index = self.receiver_min_consecutive_height
|
part_index = self.receiver_min_consecutive_height
|
||||||
search_start = part_index
|
search_start = part_index
|
||||||
search_end = self.receiver_min_consecutive_height+ResourceAdvertisement.COLLISION_GUARD_SIZE
|
search_end = self.receiver_min_consecutive_height+ResourceAdvertisement.COLLISION_GUARD_SIZE
|
||||||
@ -899,7 +899,7 @@ class Resource:
|
|||||||
else:
|
else:
|
||||||
segment = part_index // ResourceAdvertisement.HASHMAP_MAX_LEN
|
segment = part_index // ResourceAdvertisement.HASHMAP_MAX_LEN
|
||||||
|
|
||||||
|
|
||||||
hashmap_start = segment*ResourceAdvertisement.HASHMAP_MAX_LEN
|
hashmap_start = segment*ResourceAdvertisement.HASHMAP_MAX_LEN
|
||||||
hashmap_end = min((segment+1)*ResourceAdvertisement.HASHMAP_MAX_LEN, len(self.parts))
|
hashmap_end = min((segment+1)*ResourceAdvertisement.HASHMAP_MAX_LEN, len(self.parts))
|
||||||
|
|
||||||
@ -915,7 +915,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):
|
||||||
@ -925,7 +925,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):
|
||||||
"""
|
"""
|
||||||
@ -939,17 +939,17 @@ 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)
|
||||||
|
|
||||||
if self.callback != None:
|
if self.callback != None:
|
||||||
try:
|
try:
|
||||||
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
|
||||||
@ -968,7 +968,7 @@ class Resource:
|
|||||||
self.processed_parts += self.sent_parts
|
self.processed_parts += self.sent_parts
|
||||||
self.progress_total_parts = float(self.grand_total_parts)
|
self.progress_total_parts = float(self.grand_total_parts)
|
||||||
else:
|
else:
|
||||||
self.processed_parts = (self.segment_index-1)*math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU)
|
self.processed_parts = (self.segment_index-1)*math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU)
|
||||||
self.processed_parts += self.received_count
|
self.processed_parts += self.received_count
|
||||||
if self.split:
|
if self.split:
|
||||||
self.progress_total_parts = float(math.ceil(self.total_size/Resource.SDU))
|
self.progress_total_parts = float(math.ceil(self.total_size/Resource.SDU))
|
||||||
@ -1015,7 +1015,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:
|
||||||
@ -1141,7 +1141,7 @@ class ResourceAdvertisement:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def unpack(data):
|
def unpack(data):
|
||||||
dictionary = umsgpack.unpackb(data)
|
dictionary = umsgpack.unpackb(data)
|
||||||
|
|
||||||
adv = ResourceAdvertisement()
|
adv = ResourceAdvertisement()
|
||||||
adv.t = dictionary["t"]
|
adv.t = dictionary["t"]
|
||||||
adv.d = dictionary["d"]
|
adv.d = dictionary["d"]
|
||||||
|
120
RNS/Reticulum.py
120
RNS/Reticulum.py
@ -128,7 +128,7 @@ class Reticulum:
|
|||||||
HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*2
|
HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*2
|
||||||
IFAC_MIN_SIZE = 1
|
IFAC_MIN_SIZE = 1
|
||||||
IFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8")
|
IFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8")
|
||||||
|
|
||||||
MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE
|
MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE
|
||||||
|
|
||||||
RESOURCE_CACHE = 24*60*60
|
RESOURCE_CACHE = 24*60*60
|
||||||
@ -139,7 +139,7 @@ class Reticulum:
|
|||||||
|
|
||||||
router = None
|
router = None
|
||||||
config = None
|
config = None
|
||||||
|
|
||||||
# The default configuration path will be expanded to a directory
|
# The default configuration path will be expanded to a directory
|
||||||
# named ".reticulum" inside the current users home directory
|
# named ".reticulum" inside the current users home directory
|
||||||
userdir = os.path.expanduser("~")
|
userdir = os.path.expanduser("~")
|
||||||
@ -149,7 +149,7 @@ class Reticulum:
|
|||||||
cachepath = ""
|
cachepath = ""
|
||||||
|
|
||||||
__instance = None
|
__instance = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def exit_handler():
|
def exit_handler():
|
||||||
# This exit handler is called whenever Reticulum is asked to
|
# This exit handler is called whenever Reticulum is asked to
|
||||||
@ -203,20 +203,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
|
||||||
@ -266,18 +266,18 @@ 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()
|
||||||
|
|
||||||
RNS.Transport.start(self)
|
RNS.Transport.start(self)
|
||||||
@ -285,7 +285,7 @@ class Reticulum:
|
|||||||
self.rpc_addr = ("127.0.0.1", self.local_control_port)
|
self.rpc_addr = ("127.0.0.1", self.local_control_port)
|
||||||
if self.rpc_key == None:
|
if self.rpc_key == None:
|
||||||
self.rpc_key = RNS.Identity.full_hash(RNS.Transport.identity.get_private_key())
|
self.rpc_key = RNS.Identity.full_hash(RNS.Transport.identity.get_private_key())
|
||||||
|
|
||||||
if self.is_shared_instance:
|
if self.is_shared_instance:
|
||||||
self.rpc_listener = multiprocessing.connection.Listener(self.rpc_addr, authkey=self.rpc_key)
|
self.rpc_listener = multiprocessing.connection.Listener(self.rpc_addr, authkey=self.rpc_key)
|
||||||
thread = threading.Thread(target=self.rpc_loop)
|
thread = threading.Thread(target=self.rpc_loop)
|
||||||
@ -313,7 +313,7 @@ class Reticulum:
|
|||||||
|
|
||||||
if now > self.last_data_persist+Reticulum.PERSIST_INTERVAL:
|
if now > self.last_data_persist+Reticulum.PERSIST_INTERVAL:
|
||||||
self.__persist_data()
|
self.__persist_data()
|
||||||
|
|
||||||
time.sleep(Reticulum.JOB_INTERVAL)
|
time.sleep(Reticulum.JOB_INTERVAL)
|
||||||
|
|
||||||
def __start_local_interface(self):
|
def __start_local_interface(self):
|
||||||
@ -329,9 +329,9 @@ class Reticulum:
|
|||||||
interface._force_bitrate = Reticulum._force_shared_instance_bitrate
|
interface._force_bitrate = Reticulum._force_shared_instance_bitrate
|
||||||
RNS.log(f"Forcing shared instance bitrate of {RNS.prettyspeed(interface.bitrate)}", RNS.LOG_WARNING)
|
RNS.log(f"Forcing shared instance bitrate of {RNS.prettyspeed(interface.bitrate)}", RNS.LOG_WARNING)
|
||||||
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:
|
||||||
@ -353,10 +353,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
|
||||||
@ -411,11 +411,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)
|
||||||
@ -454,7 +454,7 @@ class Reticulum:
|
|||||||
c = self.config["interfaces"][name]
|
c = self.config["interfaces"][name]
|
||||||
|
|
||||||
interface_mode = Interface.Interface.MODE_FULL
|
interface_mode = Interface.Interface.MODE_FULL
|
||||||
|
|
||||||
if "interface_mode" in c:
|
if "interface_mode" in c:
|
||||||
c["interface_mode"] = str(c["interface_mode"]).lower()
|
c["interface_mode"] = str(c["interface_mode"]).lower()
|
||||||
if c["interface_mode"] == "full":
|
if c["interface_mode"] == "full":
|
||||||
@ -489,7 +489,7 @@ class Reticulum:
|
|||||||
if "ifac_size" in c:
|
if "ifac_size" in c:
|
||||||
if c.as_int("ifac_size") >= Reticulum.IFAC_MIN_SIZE*8:
|
if c.as_int("ifac_size") >= Reticulum.IFAC_MIN_SIZE*8:
|
||||||
ifac_size = c.as_int("ifac_size")//8
|
ifac_size = c.as_int("ifac_size")//8
|
||||||
|
|
||||||
ifac_netname = None
|
ifac_netname = None
|
||||||
if "networkname" in c:
|
if "networkname" in c:
|
||||||
if c["networkname"] != "":
|
if c["networkname"] != "":
|
||||||
@ -505,7 +505,7 @@ class Reticulum:
|
|||||||
if "pass_phrase" in c:
|
if "pass_phrase" in c:
|
||||||
if c["pass_phrase"] != "":
|
if c["pass_phrase"] != "":
|
||||||
ifac_netkey = c["pass_phrase"]
|
ifac_netkey = c["pass_phrase"]
|
||||||
|
|
||||||
ingress_control = True
|
ingress_control = True
|
||||||
if "ingress_control" in c: ingress_control = c.as_bool("ingress_control")
|
if "ingress_control" in c: ingress_control = c.as_bool("ingress_control")
|
||||||
ic_max_held_announces = None
|
ic_max_held_announces = None
|
||||||
@ -532,12 +532,12 @@ class Reticulum:
|
|||||||
if "announce_rate_target" in c:
|
if "announce_rate_target" in c:
|
||||||
if c.as_int("announce_rate_target") > 0:
|
if c.as_int("announce_rate_target") > 0:
|
||||||
announce_rate_target = c.as_int("announce_rate_target")
|
announce_rate_target = c.as_int("announce_rate_target")
|
||||||
|
|
||||||
announce_rate_grace = None
|
announce_rate_grace = None
|
||||||
if "announce_rate_grace" in c:
|
if "announce_rate_grace" in c:
|
||||||
if c.as_int("announce_rate_grace") >= 0:
|
if c.as_int("announce_rate_grace") >= 0:
|
||||||
announce_rate_grace = c.as_int("announce_rate_grace")
|
announce_rate_grace = c.as_int("announce_rate_grace")
|
||||||
|
|
||||||
announce_rate_penalty = None
|
announce_rate_penalty = None
|
||||||
if "announce_rate_penalty" in c:
|
if "announce_rate_penalty" in c:
|
||||||
if c.as_int("announce_rate_penalty") >= 0:
|
if c.as_int("announce_rate_penalty") >= 0:
|
||||||
@ -553,7 +553,7 @@ class Reticulum:
|
|||||||
if "announce_cap" in c:
|
if "announce_cap" in c:
|
||||||
if c.as_float("announce_cap") > 0 and c.as_float("announce_cap") <= 100:
|
if c.as_float("announce_cap") > 0 and c.as_float("announce_cap") <= 100:
|
||||||
announce_cap = c.as_float("announce_cap")/100.0
|
announce_cap = c.as_float("announce_cap")/100.0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
interface = None
|
interface = None
|
||||||
|
|
||||||
@ -658,9 +658,9 @@ 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
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
@ -695,9 +695,9 @@ 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
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
@ -732,9 +732,9 @@ 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
|
||||||
|
|
||||||
interface.announce_cap = announce_cap
|
interface.announce_cap = announce_cap
|
||||||
@ -937,7 +937,7 @@ class Reticulum:
|
|||||||
ble_addr = ble_string
|
ble_addr = ble_string
|
||||||
else:
|
else:
|
||||||
ble_name = ble_string
|
ble_name = ble_string
|
||||||
|
|
||||||
interface = RNodeInterface.RNodeInterface(
|
interface = RNodeInterface.RNodeInterface(
|
||||||
RNS.Transport,
|
RNS.Transport,
|
||||||
name,
|
name,
|
||||||
@ -1011,11 +1011,11 @@ class Reticulum:
|
|||||||
txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None
|
txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None
|
||||||
subint_config[subint_index][4] = txpower
|
subint_config[subint_index][4] = txpower
|
||||||
spreadingfactor = int(subinterface_config["spreadingfactor"]) if "spreadingfactor" in subinterface_config else None
|
spreadingfactor = int(subinterface_config["spreadingfactor"]) if "spreadingfactor" in subinterface_config else None
|
||||||
subint_config[subint_index][5] = spreadingfactor
|
subint_config[subint_index][5] = spreadingfactor
|
||||||
codingrate = int(subinterface_config["codingrate"]) if "codingrate" in subinterface_config else None
|
codingrate = int(subinterface_config["codingrate"]) if "codingrate" in subinterface_config else None
|
||||||
subint_config[subint_index][6] = codingrate
|
subint_config[subint_index][6] = codingrate
|
||||||
flow_control = subinterface_config.as_bool("flow_control") if "flow_control" in subinterface_config else False
|
flow_control = subinterface_config.as_bool("flow_control") if "flow_control" in subinterface_config else False
|
||||||
subint_config[subint_index][7] = flow_control
|
subint_config[subint_index][7] = flow_control
|
||||||
st_alock = float(subinterface_config["airtime_limit_short"]) if "airtime_limit_short" in subinterface_config else None
|
st_alock = float(subinterface_config["airtime_limit_short"]) if "airtime_limit_short" in subinterface_config else None
|
||||||
subint_config[subint_index][8] = st_alock
|
subint_config[subint_index][8] = st_alock
|
||||||
lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None
|
lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None
|
||||||
@ -1029,17 +1029,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,
|
||||||
@ -1106,14 +1106,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)
|
||||||
@ -1121,7 +1121,7 @@ class Reticulum:
|
|||||||
def _add_interface(self,interface, mode = None, configured_bitrate=None, ifac_size=None, ifac_netname=None, ifac_netkey=None, announce_cap=None, announce_rate_target=None, announce_rate_grace=None, announce_rate_penalty=None):
|
def _add_interface(self,interface, mode = None, configured_bitrate=None, ifac_size=None, ifac_netname=None, ifac_netkey=None, announce_cap=None, announce_rate_target=None, announce_rate_grace=None, announce_rate_penalty=None):
|
||||||
if not self.is_connected_to_shared_instance:
|
if not self.is_connected_to_shared_instance:
|
||||||
if interface != None and issubclass(type(interface), RNS.Interfaces.Interface.Interface):
|
if interface != None and issubclass(type(interface), RNS.Interfaces.Interface.Interface):
|
||||||
|
|
||||||
if mode == None:
|
if mode == None:
|
||||||
mode = Interface.Interface.MODE_FULL
|
mode = Interface.Interface.MODE_FULL
|
||||||
interface.mode = mode
|
interface.mode = mode
|
||||||
@ -1181,32 +1181,32 @@ 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__)
|
||||||
self.config.filename = Reticulum.configpath
|
self.config.filename = Reticulum.configpath
|
||||||
|
|
||||||
if not os.path.isdir(Reticulum.configdir):
|
if not os.path.isdir(Reticulum.configdir):
|
||||||
os.makedirs(Reticulum.configdir)
|
os.makedirs(Reticulum.configdir)
|
||||||
self.config.write()
|
self.config.write()
|
||||||
@ -1266,7 +1266,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:
|
||||||
@ -1278,7 +1278,7 @@ class Reticulum:
|
|||||||
interfaces = []
|
interfaces = []
|
||||||
for interface in RNS.Transport.interfaces:
|
for interface in RNS.Transport.interfaces:
|
||||||
ifstats = {}
|
ifstats = {}
|
||||||
|
|
||||||
if hasattr(interface, "clients"):
|
if hasattr(interface, "clients"):
|
||||||
ifstats["clients"] = interface.clients
|
ifstats["clients"] = interface.clients
|
||||||
else:
|
else:
|
||||||
@ -1296,7 +1296,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
|
||||||
|
|
||||||
@ -1485,12 +1485,12 @@ class Reticulum:
|
|||||||
|
|
||||||
if self.is_connected_to_shared_instance and hasattr(self, "_force_shared_instance_bitrate") and self._force_shared_instance_bitrate:
|
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:
|
||||||
|
342
RNS/Transport.py
342
RNS/Transport.py
File diff suppressed because it is too large
Load Diff
@ -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')]
|
||||||
|
@ -54,11 +54,11 @@ 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)
|
||||||
|
|
||||||
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("No valid saved identity found, creating new...", RNS.LOG_INFO)
|
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO)
|
||||||
@ -68,8 +68,8 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
|
|||||||
destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "receive")
|
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:
|
||||||
@ -79,14 +79,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:
|
||||||
@ -102,17 +102,17 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
|
|||||||
ms = "y"
|
ms = "y"
|
||||||
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)
|
||||||
@ -141,11 +141,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")
|
||||||
@ -169,7 +169,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
|
|||||||
|
|
||||||
destination.set_link_established_callback(client_link_established)
|
destination.set_link_established_callback(client_link_established)
|
||||||
destination.register_request_handler("fetch_file", response_generator=fetch_request, allow=RNS.Destination.ALLOW_LIST, allowed_list=allowed_identity_hashes)
|
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():
|
||||||
@ -180,7 +180,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
|
|||||||
destination.announce()
|
destination.announce()
|
||||||
|
|
||||||
threading.Thread(target=job, daemon=True).start()
|
threading.Thread(target=job, daemon=True).start()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ def receive_sender_identified(link, identity):
|
|||||||
|
|
||||||
def receive_resource_callback(resource):
|
def receive_resource_callback(resource):
|
||||||
global allow_all
|
global allow_all
|
||||||
|
|
||||||
sender_identity = resource.link.get_remote_identity()
|
sender_identity = resource.link.get_remote_identity()
|
||||||
|
|
||||||
if sender_identity != None:
|
if sender_identity != None:
|
||||||
@ -220,15 +220,15 @@ 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):
|
||||||
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")
|
||||||
@ -238,8 +238,8 @@ def receive_resource_concluded(resource):
|
|||||||
saved_filename = filename
|
saved_filename = filename
|
||||||
while os.path.isfile(saved_filename):
|
while os.path.isfile(saved_filename):
|
||||||
counter += 1
|
counter += 1
|
||||||
saved_filename = filename+"."+str(counter)
|
saved_filename = f"{filename}.{counter}"
|
||||||
|
|
||||||
file = open(saved_filename, "wb")
|
file = open(saved_filename, "wb")
|
||||||
file.write(resource.data.read())
|
file.write(resource.data.read())
|
||||||
file.close()
|
file.close()
|
||||||
@ -285,7 +285,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:
|
||||||
@ -296,11 +296,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
|
||||||
@ -313,9 +313,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=" ")
|
print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=" ")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
@ -324,7 +324,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
|
|||||||
while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout:
|
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'\x08\x08{syms[i]} ', end="")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
i = (i+1)%len(syms)
|
i = (i+1)%len(syms)
|
||||||
|
|
||||||
@ -336,9 +336,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("\r \rEstablishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=" ")
|
print(f'\r \rEstablishing link with {RNS.prettyhexrep(destination_hash)} ', end=" ")
|
||||||
|
|
||||||
listener_identity = RNS.Identity.recall(destination_hash)
|
listener_identity = RNS.Identity.recall(destination_hash)
|
||||||
listener_destination = RNS.Destination(
|
listener_destination = RNS.Destination(
|
||||||
@ -353,15 +353,15 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
|
|||||||
while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout:
|
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'\x08\x08{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("\r \rCould not establish link with "+RNS.prettyhexrep(destination_hash))
|
print(f'\r \rCould not establish link with {RNS.prettyhexrep(destination_hash)}')
|
||||||
exit(1)
|
exit(1)
|
||||||
else:
|
else:
|
||||||
if silent:
|
if silent:
|
||||||
@ -411,8 +411,8 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
|
|||||||
saved_filename = filename
|
saved_filename = filename
|
||||||
while os.path.isfile(saved_filename):
|
while os.path.isfile(saved_filename):
|
||||||
counter += 1
|
counter += 1
|
||||||
saved_filename = filename+"."+str(counter)
|
saved_filename = f"{filename}.{counter}"
|
||||||
|
|
||||||
file = open(saved_filename, "wb")
|
file = open(saved_filename, "wb")
|
||||||
file.write(resource.data.read())
|
file.write(resource.data.read())
|
||||||
file.close()
|
file.close()
|
||||||
@ -437,19 +437,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'\x08\x08{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("\r \r", end="")
|
if not silent: print("\r \r", end="")
|
||||||
print("Fetch request failed, fetching the file "+str(file)+" was not allowed by the remote")
|
print(f"Fetch request failed, fetching the file {file} was not allowed by the remote")
|
||||||
link.teardown()
|
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("\r \r", end="")
|
if not silent: print("\r \r", end="")
|
||||||
print("Fetch request failed, the file "+str(file)+" was not found on the remote")
|
print(f"Fetch request failed, the file {file} was not found on the remote")
|
||||||
link.teardown()
|
link.teardown()
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
exit(0)
|
exit(0)
|
||||||
@ -474,13 +474,13 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
|
|||||||
if current_resource:
|
if current_resource:
|
||||||
prg = current_resource.get_progress()
|
prg = current_resource.get_progress()
|
||||||
percent = round(prg * 100.0, 1)
|
percent = round(prg * 100.0, 1)
|
||||||
stat_str = str(percent)+"% - " + size_str(int(prg*current_resource.total_size)) + " of " + size_str(current_resource.total_size) + " - " +size_str(speed, "b")+"ps"
|
stat_str = f"{percent}% - {size_str(int(prg * current_resource.total_size))} of {size_str(current_resource.total_size)} - {size_str(speed, 'b')}ps"
|
||||||
if prg != 1.0:
|
if prg != 1.0:
|
||||||
print("\r \rTransferring file "+syms[i]+" "+stat_str, end=" ")
|
print(f'\r \rTransferring file {syms[i]} {stat_str}', end=" ")
|
||||||
else:
|
else:
|
||||||
print("\r \rTransfer complete "+stat_str, end=" ")
|
print(f'\r \rTransfer complete {stat_str}', end=" ")
|
||||||
else:
|
else:
|
||||||
print("\r \rWaiting for transfer to start "+syms[i]+" ", end=" ")
|
print(f'\r \rWaiting for transfer to start {syms[i]} ', end=" ")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
i = (i+1)%len(syms)
|
i = (i+1)%len(syms)
|
||||||
|
|
||||||
@ -492,10 +492,10 @@ 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("\r \r"+str(file)+" fetched from "+RNS.prettyhexrep(destination_hash))
|
#print("\r \r"+str(file)+" fetched from "+RNS.prettyhexrep(destination_hash))
|
||||||
print("\n"+str(file)+" fetched from "+RNS.prettyhexrep(destination_hash))
|
print(f"\n{file} fetched from {RNS.prettyhexrep(destination_hash)}")
|
||||||
link.teardown()
|
link.teardown()
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
exit(0)
|
exit(0)
|
||||||
@ -512,7 +512,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:
|
||||||
@ -521,7 +521,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
|||||||
print(str(e))
|
print(str(e))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
file_path = os.path.expanduser(file)
|
file_path = os.path.expanduser(file)
|
||||||
if not os.path.isfile(file_path):
|
if not os.path.isfile(file_path):
|
||||||
print("File not found")
|
print("File not found")
|
||||||
@ -547,11 +547,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
|
||||||
@ -564,9 +564,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=" ")
|
print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=" ")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
@ -575,7 +575,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
|||||||
while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout:
|
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'\x08\x08{syms[i]} ', end="")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
i = (i+1)%len(syms)
|
i = (i+1)%len(syms)
|
||||||
|
|
||||||
@ -587,9 +587,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("\r \rEstablishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=" ")
|
print(f'\r \rEstablishing link with {RNS.prettyhexrep(destination_hash)} ', end=" ")
|
||||||
|
|
||||||
receiver_identity = RNS.Identity.recall(destination_hash)
|
receiver_identity = RNS.Identity.recall(destination_hash)
|
||||||
receiver_destination = RNS.Destination(
|
receiver_destination = RNS.Destination(
|
||||||
@ -604,21 +604,21 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
|||||||
while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout:
|
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'\x08\x08{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("\r \rLink establishment with "+RNS.prettyhexrep(destination_hash)+" timed out")
|
print(f'\r \rLink 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("\r \rNo path found to "+RNS.prettyhexrep(destination_hash))
|
print(f'\r \rNo path found to {RNS.prettyhexrep(destination_hash)}')
|
||||||
exit(1)
|
exit(1)
|
||||||
else:
|
else:
|
||||||
if silent:
|
if silent:
|
||||||
@ -633,16 +633,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'\x08\x08{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("\r \rFile was not accepted by "+RNS.prettyhexrep(destination_hash))
|
print(f'\r \rFile was not accepted by {RNS.prettyhexrep(destination_hash)}')
|
||||||
exit(1)
|
exit(1)
|
||||||
else:
|
else:
|
||||||
if silent:
|
if silent:
|
||||||
@ -654,11 +654,11 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
|||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
prg = current_resource.get_progress()
|
prg = current_resource.get_progress()
|
||||||
percent = round(prg * 100.0, 1)
|
percent = round(prg * 100.0, 1)
|
||||||
stat_str = str(percent)+"% - " + size_str(int(prg*current_resource.total_size)) + " of " + size_str(current_resource.total_size) + " - " +size_str(speed, "b")+"ps"
|
stat_str = f"{percent}% - {size_str(int(prg * current_resource.total_size))} of {size_str(current_resource.total_size)} - {size_str(speed, 'b')}ps"
|
||||||
if not done:
|
if not done:
|
||||||
print("\r \rTransferring file "+syms[i]+" "+stat_str, end=" ")
|
print(f'\r \rTransferring file {syms[i]} {stat_str}', end=" ")
|
||||||
else:
|
else:
|
||||||
print("\r \rTransfer complete "+stat_str, end=" ")
|
print(f'\r \rTransfer complete {stat_str}', end=" ")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
i = (i+1)%len(syms)
|
i = (i+1)%len(syms)
|
||||||
return i
|
return i
|
||||||
@ -678,10 +678,10 @@ 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("\r \r"+str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash))
|
# print("\r \r"+str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash))
|
||||||
print("\n"+str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash))
|
print(f"\n{file_path} copied to {RNS.prettyhexrep(destination_hash)}")
|
||||||
link.teardown()
|
link.teardown()
|
||||||
time.sleep(0.25)
|
time.sleep(0.25)
|
||||||
real_file.close()
|
real_file.close()
|
||||||
@ -707,8 +707,8 @@ def main():
|
|||||||
parser.add_argument('-p', '--print-identity', action='store_true', default=False, help="print identity and destination info and exit")
|
parser.add_argument('-p', '--print-identity', action='store_true', default=False, help="print identity and destination info and exit")
|
||||||
parser.add_argument("-w", action="store", metavar="seconds", type=float, help="sender timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT)
|
parser.add_argument("-w", action="store", metavar="seconds", type=float, help="sender timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT)
|
||||||
# parser.add_argument("--limit", action="store", metavar="files", type=float, help="maximum number of files to accept", default=None)
|
# parser.add_argument("--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()
|
||||||
|
|
||||||
if args.listen or args.print_identity:
|
if args.listen or args.print_identity:
|
||||||
@ -777,12 +777,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()
|
||||||
|
@ -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'\x08\x08{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
|
||||||
@ -82,7 +82,7 @@ def main():
|
|||||||
parser.add_argument("-w", "--write", metavar="file", action="store", default=None, help="output file path", type=str)
|
parser.add_argument("-w", "--write", metavar="file", action="store", default=None, help="output file path", type=str)
|
||||||
parser.add_argument("-f", "--force", action="store_true", default=None, help="write output even if it overwrites existing files")
|
parser.add_argument("-f", "--force", action="store_true", default=None, help="write output even if it overwrites existing files")
|
||||||
parser.add_argument("-I", "--stdin", action="store_true", default=False, help=argparse.SUPPRESS) # "read input from STDIN instead of file"
|
parser.add_argument("-I", "--stdin", action="store_true", default=False, help=argparse.SUPPRESS) # "read input from STDIN instead of file"
|
||||||
parser.add_argument("-O", "--stdout", action="store_true", default=False, help=argparse.SUPPRESS) # help="write output to STDOUT instead of file",
|
parser.add_argument("-O", "--stdout", action="store_true", default=False, help=argparse.SUPPRESS) # help="write output to STDOUT instead of file",
|
||||||
|
|
||||||
parser.add_argument("-R", "--request", action="store_true", default=False, help="request unknown Identities from the network")
|
parser.add_argument("-R", "--request", action="store_true", default=False, help="request unknown Identities from the network")
|
||||||
parser.add_argument("-t", action="store", metavar="seconds", type=float, help="identity request timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT)
|
parser.add_argument("-t", action="store", metavar="seconds", type=float, help="identity request timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT)
|
||||||
@ -92,15 +92,15 @@ 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()
|
||||||
|
|
||||||
ops = 0;
|
ops = 0;
|
||||||
for t in [args.encrypt, args.decrypt, args.validate, args.sign]:
|
for t in [args.encrypt, args.decrypt, args.validate, args.sign]:
|
||||||
if t:
|
if t:
|
||||||
ops += 1
|
ops += 1
|
||||||
|
|
||||||
if ops > 1:
|
if ops > 1:
|
||||||
RNS.log("This utility currently only supports one of the encrypt, decrypt, sign or verify operations per invocation", RNS.LOG_ERROR)
|
RNS.log("This utility currently only supports one of the encrypt, decrypt, sign or verify operations per invocation", RNS.LOG_ERROR)
|
||||||
exit(1)
|
exit(1)
|
||||||
@ -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)
|
||||||
@ -179,7 +179,7 @@ def main():
|
|||||||
quietness = args.quiet
|
quietness = args.quiet
|
||||||
if verbosity != 0 or quietness != 0:
|
if verbosity != 0 or quietness != 0:
|
||||||
targetloglevel = targetloglevel+verbosity-quietness
|
targetloglevel = targetloglevel+verbosity-quietness
|
||||||
|
|
||||||
# Start Reticulum
|
# Start Reticulum
|
||||||
reticulum = RNS.Reticulum(configdir=args.config, loglevel=targetloglevel)
|
reticulum = RNS.Reticulum(configdir=args.config, loglevel=targetloglevel)
|
||||||
RNS.compact_log_fmt = True
|
RNS.compact_log_fmt = True
|
||||||
@ -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,31 +210,31 @@ 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:
|
||||||
RNS.log("Invalid hexadecimal hash provided", RNS.LOG_ERROR)
|
RNS.log("Invalid hexadecimal hash provided", RNS.LOG_ERROR)
|
||||||
exit(7)
|
exit(7)
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Try loading Identity from file
|
# Try loading Identity from file
|
||||||
if not os.path.isfile(identity_str):
|
if not os.path.isfile(identity_str):
|
||||||
@ -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,30 +368,30 @@ 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
|
||||||
# probably need to create a wrapper that takes
|
# probably need to create a wrapper that takes
|
||||||
# into account not closing stdout when done
|
# into account not closing stdout when done
|
||||||
@ -414,22 +414,22 @@ 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()))
|
||||||
data_output.close()
|
data_output.close()
|
||||||
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)+" 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:
|
||||||
@ -448,13 +448,13 @@ def main():
|
|||||||
else:
|
else:
|
||||||
# if not args.stdout:
|
# if not args.stdout:
|
||||||
# RNS.log("Verifying "+str(args.validate)+" for "+str(args.read))
|
# RNS.log("Verifying "+str(args.validate)+" for "+str(args.read))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
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,8 +497,8 @@ 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
|
||||||
while more_data:
|
while more_data:
|
||||||
@ -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,8 +544,8 @@ 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
|
||||||
while more_data:
|
while more_data:
|
||||||
@ -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:
|
||||||
|
@ -48,8 +48,8 @@ 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()
|
||||||
|
|
||||||
if args.exampleconfig:
|
if args.exampleconfig:
|
||||||
|
File diff suppressed because one or more lines are too long
@ -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:
|
||||||
@ -235,28 +235,28 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
|||||||
hour_rate = round(len(entry["timestamps"])/span_hours, 3)
|
hour_rate = round(len(entry["timestamps"])/span_hours, 3)
|
||||||
if hour_rate-int(hour_rate) == 0:
|
if hour_rate-int(hour_rate) == 0:
|
||||||
hour_rate = int(hour_rate)
|
hour_rate = int(hour_rate)
|
||||||
|
|
||||||
if entry["rate_violations"] > 0:
|
if entry["rate_violations"] > 0:
|
||||||
if entry["rate_violations"] == 1:
|
if entry["rate_violations"] == 1:
|
||||||
s_str = ""
|
s_str = ""
|
||||||
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:
|
||||||
@ -272,7 +272,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
|||||||
|
|
||||||
print("Dropping announce queues on all interfaces...")
|
print("Dropping announce queues on all interfaces...")
|
||||||
reticulum.drop_announce_queues()
|
reticulum.drop_announce_queues()
|
||||||
|
|
||||||
elif drop:
|
elif drop:
|
||||||
if remote_link:
|
if remote_link:
|
||||||
if not no_output:
|
if not no_output:
|
||||||
@ -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:
|
||||||
@ -341,10 +341,10 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(str(e))
|
print(str(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
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'\x08\x08{syms[i]} ', end="")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
i = (i+1)%len(syms)
|
i = (i+1)%len(syms)
|
||||||
|
|
||||||
@ -371,12 +371,12 @@ 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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
@ -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(
|
||||||
@ -479,7 +479,7 @@ def main():
|
|||||||
help="timeout before giving up on remote queries",
|
help="timeout before giving up on remote queries",
|
||||||
default=RNS.Transport.PATH_REQUEST_TIMEOUT
|
default=RNS.Transport.PATH_REQUEST_TIMEOUT
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-j",
|
"-j",
|
||||||
"--json",
|
"--json",
|
||||||
@ -497,7 +497,7 @@ def main():
|
|||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.config:
|
if args.config:
|
||||||
@ -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()
|
@ -38,7 +38,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
|
|||||||
if full_name == None:
|
if full_name == None:
|
||||||
print("The full destination name including application name aspects must be specified for the destination")
|
print("The full destination name including application name aspects must be specified for the destination")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
app_name, aspects = RNS.Destination.app_and_aspects_from_name(full_name)
|
app_name, aspects = RNS.Destination.app_and_aspects_from_name(full_name)
|
||||||
|
|
||||||
@ -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'\x08\x08{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,25 +115,25 @@ 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'\x08\x08{syms[i]} ', end="")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
i = (i+1)%len(syms)
|
i = (i+1)%len(syms)
|
||||||
|
|
||||||
if time.time() > _timeout:
|
if time.time() > _timeout:
|
||||||
print("\r \rProbe timed out")
|
print("\r \rProbe timed out")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("\b\b ")
|
print("\b\b ")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
@ -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:
|
||||||
@ -196,7 +192,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
|
|||||||
exit(2)
|
exit(2)
|
||||||
else:
|
else:
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
@ -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)
|
||||||
|
|
||||||
|
@ -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,8 +55,8 @@ 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()
|
||||||
|
|
||||||
if args.exampleconfig:
|
if args.exampleconfig:
|
||||||
@ -192,7 +192,7 @@ loglevel = 4
|
|||||||
|
|
||||||
# The following example enables communication with other
|
# The following example enables communication with other
|
||||||
# local Reticulum peers using UDP broadcasts.
|
# local Reticulum peers using UDP broadcasts.
|
||||||
|
|
||||||
[[UDP Interface]]
|
[[UDP Interface]]
|
||||||
type = UDPInterface
|
type = UDPInterface
|
||||||
enabled = no
|
enabled = no
|
||||||
@ -235,24 +235,24 @@ loglevel = 4
|
|||||||
# This example demonstrates a TCP server interface.
|
# This example demonstrates a TCP server interface.
|
||||||
# It will listen for incoming connections on the
|
# It will listen for incoming connections on the
|
||||||
# specified IP address and port number.
|
# specified IP address and port number.
|
||||||
|
|
||||||
[[TCP Server Interface]]
|
[[TCP Server Interface]]
|
||||||
type = TCPServerInterface
|
type = TCPServerInterface
|
||||||
enabled = no
|
enabled = no
|
||||||
|
|
||||||
# This configuration will listen on all IP
|
# This configuration will listen on all IP
|
||||||
# interfaces on port 4242
|
# interfaces on port 4242
|
||||||
|
|
||||||
listen_ip = 0.0.0.0
|
listen_ip = 0.0.0.0
|
||||||
listen_port = 4242
|
listen_port = 4242
|
||||||
|
|
||||||
# Alternatively you can bind to a specific IP
|
# Alternatively you can bind to a specific IP
|
||||||
|
|
||||||
# listen_ip = 10.0.0.88
|
# listen_ip = 10.0.0.88
|
||||||
# listen_port = 4242
|
# listen_port = 4242
|
||||||
|
|
||||||
# Or a specific network device
|
# Or a specific network device
|
||||||
|
|
||||||
# device = eth0
|
# device = eth0
|
||||||
# port = 4242
|
# port = 4242
|
||||||
|
|
||||||
@ -300,7 +300,7 @@ loglevel = 4
|
|||||||
# host device before connecting. BLE
|
# host device before connecting. BLE
|
||||||
# devices can be connected by name,
|
# devices can be connected by name,
|
||||||
# BLE MAC address or by any available.
|
# BLE MAC address or by any available.
|
||||||
|
|
||||||
# Connect to specific device by name
|
# Connect to specific device by name
|
||||||
# port = ble://RNode 3B87
|
# port = ble://RNode 3B87
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ loglevel = 4
|
|||||||
# Set TX power to 7 dBm (5 mW)
|
# Set TX power to 7 dBm (5 mW)
|
||||||
txpower = 7
|
txpower = 7
|
||||||
|
|
||||||
# Select spreading factor 8. Valid
|
# Select spreading factor 8. Valid
|
||||||
# range is 7 through 12, with 7
|
# range is 7 through 12, with 7
|
||||||
# being the fastest and 12 having
|
# being the fastest and 12 having
|
||||||
# the longest range.
|
# the longest range.
|
||||||
@ -349,8 +349,8 @@ loglevel = 4
|
|||||||
# flow control can be useful. By default
|
# flow control can be useful. By default
|
||||||
# it is disabled.
|
# it is disabled.
|
||||||
flow_control = False
|
flow_control = False
|
||||||
|
|
||||||
|
|
||||||
# An example KISS modem interface. Useful for running
|
# An example KISS modem interface. Useful for running
|
||||||
# Reticulum over packet radio hardware.
|
# Reticulum over packet radio hardware.
|
||||||
|
|
||||||
@ -365,7 +365,7 @@ loglevel = 4
|
|||||||
|
|
||||||
# Set the serial baud-rate and other
|
# Set the serial baud-rate and other
|
||||||
# configuration parameters.
|
# configuration parameters.
|
||||||
speed = 115200
|
speed = 115200
|
||||||
databits = 8
|
databits = 8
|
||||||
parity = none
|
parity = none
|
||||||
stopbits = 1
|
stopbits = 1
|
||||||
@ -413,7 +413,7 @@ loglevel = 4
|
|||||||
# way, Reticulum will automatically encapsulate it's
|
# way, Reticulum will automatically encapsulate it's
|
||||||
# traffic in AX.25 and also identify your stations
|
# traffic in AX.25 and also identify your stations
|
||||||
# transmissions with your callsign and SSID.
|
# transmissions with your callsign and SSID.
|
||||||
#
|
#
|
||||||
# Only do this if you really need to! Reticulum doesn't
|
# Only do this if you really need to! Reticulum doesn't
|
||||||
# need the AX.25 layer for anything, and it incurs extra
|
# need the AX.25 layer for anything, and it incurs extra
|
||||||
# overhead on every packet to encapsulate in AX.25.
|
# overhead on every packet to encapsulate in AX.25.
|
||||||
@ -436,7 +436,7 @@ loglevel = 4
|
|||||||
|
|
||||||
# Set the serial baud-rate and other
|
# Set the serial baud-rate and other
|
||||||
# configuration parameters.
|
# configuration parameters.
|
||||||
speed = 115200
|
speed = 115200
|
||||||
databits = 8
|
databits = 8
|
||||||
parity = none
|
parity = none
|
||||||
stopbits = 1
|
stopbits = 1
|
||||||
|
@ -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)
|
||||||
@ -161,7 +161,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
|||||||
stats, link_count = remote_status
|
stats, link_count = remote_status
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(str(e))
|
print(str(e))
|
||||||
exit(20)
|
exit(20)
|
||||||
@ -215,7 +215,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
|||||||
if sorting == "held":
|
if sorting == "held":
|
||||||
interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse)
|
interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse)
|
||||||
|
|
||||||
|
|
||||||
for ifstat in interfaces:
|
for ifstat in interfaces:
|
||||||
name = ifstat["name"]
|
name = ifstat["name"]
|
||||||
|
|
||||||
@ -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"])))
|
||||||
@ -295,16 +295,16 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
|||||||
if "battery_percent" in ifstat and ifstat["battery_percent"] != None:
|
if "battery_percent" in ifstat and ifstat["battery_percent"] != None:
|
||||||
try:
|
try:
|
||||||
bpi = int(ifstat["battery_percent"])
|
bpi = int(ifstat["battery_percent"])
|
||||||
print(" Battery : {bp}%".format(bp=bpi))
|
print(f" Battery : {bpi}%")
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if "airtime_short" in ifstat and "airtime_long" in ifstat:
|
if "airtime_short" in ifstat and "airtime_long" in ifstat:
|
||||||
print(" Airtime : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["airtime_short"]),atl=str(ifstat["airtime_long"])))
|
print(" Airtime : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["airtime_short"]),atl=str(ifstat["airtime_long"])))
|
||||||
|
|
||||||
if "channel_load_short" in ifstat and "channel_load_long" in ifstat:
|
if "channel_load_short" in ifstat and "channel_load_long" in ifstat:
|
||||||
print(" Ch.Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"])))
|
print(" Ch.Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"])))
|
||||||
|
|
||||||
if "peers" in ifstat and ifstat["peers"] != None:
|
if "peers" in ifstat and ifstat["peers"] != None:
|
||||||
print(" Peers : {np} reachable".format(np=ifstat["peers"]))
|
print(" Peers : {np} reachable".format(np=ifstat["peers"]))
|
||||||
|
|
||||||
@ -314,7 +314,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
|||||||
if "ifac_signature" in ifstat and ifstat["ifac_signature"] != None:
|
if "ifac_signature" in ifstat and ifstat["ifac_signature"] != None:
|
||||||
sigstr = "<…"+RNS.hexrep(ifstat["ifac_signature"][-5:], delimit=False)+">"
|
sigstr = "<…"+RNS.hexrep(ifstat["ifac_signature"][-5:], delimit=False)+">"
|
||||||
print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr))
|
print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr))
|
||||||
|
|
||||||
if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None:
|
if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None:
|
||||||
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
||||||
|
|
||||||
@ -324,14 +324,14 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
|||||||
print(" Queued : {np} announce".format(np=aqn))
|
print(" Queued : {np} announce".format(np=aqn))
|
||||||
else:
|
else:
|
||||||
print(" Queued : {np} announces".format(np=aqn))
|
print(" Queued : {np} announces".format(np=aqn))
|
||||||
|
|
||||||
if astats and "held_announces" in ifstat and ifstat["held_announces"] != None and ifstat["held_announces"] > 0:
|
if astats and "held_announces" in ifstat and ifstat["held_announces"] != None and ifstat["held_announces"] > 0:
|
||||||
aqn = ifstat["held_announces"]
|
aqn = ifstat["held_announces"]
|
||||||
if aqn == 1:
|
if aqn == 1:
|
||||||
print(" Held : {np} announce".format(np=aqn))
|
print(" Held : {np} announce".format(np=aqn))
|
||||||
else:
|
else:
|
||||||
print(" Held : {np} announces".format(np=aqn))
|
print(" Held : {np} announces".format(np=aqn))
|
||||||
|
|
||||||
if astats and "incoming_announce_frequency" in ifstat and ifstat["incoming_announce_frequency"] != None:
|
if astats and "incoming_announce_frequency" in ifstat and ifstat["incoming_announce_frequency"] != None:
|
||||||
print(" Announces : {iaf}↑".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"])))
|
print(" Announces : {iaf}↑".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"])))
|
||||||
print(" {iaf}↓".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"])))
|
print(" {iaf}↓".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"])))
|
||||||
@ -357,7 +357,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
|||||||
print(f"\n{lstr}")
|
print(f"\n{lstr}")
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if not remote:
|
if not remote:
|
||||||
print("Could not get RNS status")
|
print("Could not get RNS status")
|
||||||
@ -378,7 +378,7 @@ def main():
|
|||||||
help="show all interfaces",
|
help="show all interfaces",
|
||||||
default=False
|
default=False
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-A",
|
"-A",
|
||||||
"--announce-stats",
|
"--announce-stats",
|
||||||
@ -386,7 +386,7 @@ def main():
|
|||||||
help="show announce stats",
|
help="show announce stats",
|
||||||
default=False
|
default=False
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-l",
|
"-l",
|
||||||
"--link-stats",
|
"--link-stats",
|
||||||
@ -394,7 +394,7 @@ def main():
|
|||||||
help="show link stats",
|
help="show link stats",
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-s",
|
"-s",
|
||||||
"--sort",
|
"--sort",
|
||||||
@ -403,7 +403,7 @@ def main():
|
|||||||
default=None,
|
default=None,
|
||||||
type=str
|
type=str
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-r",
|
"-r",
|
||||||
"--reverse",
|
"--reverse",
|
||||||
@ -411,7 +411,7 @@ def main():
|
|||||||
help="reverse sorting",
|
help="reverse sorting",
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-j",
|
"-j",
|
||||||
"--json",
|
"--json",
|
||||||
@ -450,7 +450,7 @@ def main():
|
|||||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||||
|
|
||||||
parser.add_argument("filter", nargs="?", default=None, help="only display interfaces with names including filter", type=str)
|
parser.add_argument("filter", nargs="?", default=None, help="only display interfaces with names including filter", type=str)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.config:
|
if args.config:
|
||||||
@ -488,10 +488,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()
|
||||||
|
@ -42,10 +42,10 @@ 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)
|
||||||
|
|
||||||
if identity == None:
|
if identity == None:
|
||||||
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO)
|
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO)
|
||||||
@ -57,13 +57,13 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed
|
|||||||
|
|
||||||
targetloglevel = 3+verbosity-quietness
|
targetloglevel = 3+verbosity-quietness
|
||||||
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel)
|
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel)
|
||||||
|
|
||||||
prepare_identity(identitypath)
|
prepare_identity(identitypath)
|
||||||
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,27 +103,27 @@ 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()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
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'\x08\x08{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)
|
||||||
|
|
||||||
@ -338,9 +338,9 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
|
|||||||
if link == None or link.status == RNS.Link.CLOSED or link.status == RNS.Link.PENDING:
|
if link == None or link.status == RNS.Link.CLOSED or link.status == RNS.Link.PENDING:
|
||||||
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,8 +547,8 @@ 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()
|
||||||
|
|
||||||
if args.listen or args.print_identity:
|
if args.listen or args.print_identity:
|
||||||
@ -593,15 +593,15 @@ 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""
|
||||||
# while True:
|
# while True:
|
||||||
# ch = sys.stdin.read(1)
|
# ch = sys.stdin.read(1)
|
||||||
# cmdbuf += ch.encode("utf-8")
|
# cmdbuf += ch.encode("utf-8")
|
||||||
# print("\r"+prompt+cmdbuf.decode("utf-8"), end="")
|
# print("\r"+prompt+cmdbuf.decode("utf-8"), end="")
|
||||||
|
|
||||||
command = input()
|
command = input()
|
||||||
if command.lower() == "exit" or command.lower() == "quit":
|
if command.lower() == "exit" or command.lower() == "quit":
|
||||||
exit(0)
|
exit(0)
|
||||||
@ -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))
|
||||||
@ -676,7 +676,7 @@ def pretty_time(time, verbose=False):
|
|||||||
minutes = int(time // 60)
|
minutes = int(time // 60)
|
||||||
time %= 60
|
time %= 60
|
||||||
seconds = round(time, 2)
|
seconds = round(time, 2)
|
||||||
|
|
||||||
ss = "" if seconds == 1 else "s"
|
ss = "" if seconds == 1 else "s"
|
||||||
sm = "" if minutes == 1 else "s"
|
sm = "" if minutes == 1 else "s"
|
||||||
sh = "" if hours == 1 else "s"
|
sh = "" if hours == 1 else "s"
|
||||||
@ -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 = ""
|
||||||
|
@ -90,7 +90,7 @@ def loglevelname(level):
|
|||||||
return "Debug"
|
return "Debug"
|
||||||
if (level == LOG_EXTREME):
|
if (level == LOG_EXTREME):
|
||||||
return "Extra"
|
return "Extra"
|
||||||
|
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
|
|
||||||
def version():
|
def version():
|
||||||
@ -124,7 +124,7 @@ def log(msg, level=3, _override_destination = False):
|
|||||||
file = open(logfile, "a")
|
file = open(logfile, "a")
|
||||||
file.write(logstring+"\n")
|
file.write(logstring+"\n")
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
if os.path.getsize(logfile) > LOG_MAXSIZE:
|
if os.path.getsize(logfile) > LOG_MAXSIZE:
|
||||||
prevfile = logfile+".1"
|
prevfile = logfile+".1"
|
||||||
if os.path.isfile(prevfile):
|
if os.path.isfile(prevfile):
|
||||||
@ -138,7 +138,7 @@ def log(msg, level=3, _override_destination = False):
|
|||||||
log("Exception occurred while writing log message to log file: "+str(e), LOG_CRITICAL)
|
log("Exception occurred while writing log message to log file: "+str(e), LOG_CRITICAL)
|
||||||
log("Dumping future log events to console!", LOG_CRITICAL)
|
log("Dumping future log events to console!", LOG_CRITICAL)
|
||||||
log(msg, level)
|
log(msg, level)
|
||||||
|
|
||||||
|
|
||||||
def rand():
|
def rand():
|
||||||
result = instance_random.random()
|
result = instance_random.random()
|
||||||
@ -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):
|
||||||
@ -155,16 +155,16 @@ def hexrep(data, delimit=True):
|
|||||||
iter(data)
|
iter(data)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
data = [data]
|
data = [data]
|
||||||
|
|
||||||
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))
|
||||||
@ -228,7 +228,7 @@ def prettytime(time, verbose=False, compact=False):
|
|||||||
seconds = int(time)
|
seconds = int(time)
|
||||||
else:
|
else:
|
||||||
seconds = round(time, 2)
|
seconds = round(time, 2)
|
||||||
|
|
||||||
ss = "" if seconds == 1 else "s"
|
ss = "" if seconds == 1 else "s"
|
||||||
sm = "" if minutes == 1 else "s"
|
sm = "" if minutes == 1 else "s"
|
||||||
sh = "" if hours == 1 else "s"
|
sh = "" if hours == 1 else "s"
|
||||||
@ -272,7 +272,7 @@ def prettytime(time, verbose=False, compact=False):
|
|||||||
|
|
||||||
def prettyshorttime(time, verbose=False, compact=False):
|
def prettyshorttime(time, verbose=False, compact=False):
|
||||||
time = time*1e6
|
time = time*1e6
|
||||||
|
|
||||||
seconds = int(time // 1e6); time %= 1e6
|
seconds = int(time // 1e6); time %= 1e6
|
||||||
milliseconds = int(time // 1e3); time %= 1e3
|
milliseconds = int(time // 1e3); time %= 1e3
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ def prettyshorttime(time, verbose=False, compact=False):
|
|||||||
microseconds = int(time)
|
microseconds = int(time)
|
||||||
else:
|
else:
|
||||||
microseconds = round(time, 2)
|
microseconds = round(time, 2)
|
||||||
|
|
||||||
ss = "" if seconds == 1 else "s"
|
ss = "" if seconds == 1 else "s"
|
||||||
sms = "" if milliseconds == 1 else "s"
|
sms = "" if milliseconds == 1 else "s"
|
||||||
sus = "" if microseconds == 1 else "s"
|
sus = "" if microseconds == 1 else "s"
|
||||||
@ -365,16 +365,16 @@ def profiler(tag=None, capture=False, super_tag=None):
|
|||||||
def profiler_results():
|
def profiler_results():
|
||||||
from statistics import mean, median, stdev
|
from statistics import mean, median, stdev
|
||||||
results = {}
|
results = {}
|
||||||
|
|
||||||
for tag in profiler_tags:
|
for tag in profiler_tags:
|
||||||
tag_captures = []
|
tag_captures = []
|
||||||
tag_entry = profiler_tags[tag]
|
tag_entry = profiler_tags[tag]
|
||||||
|
|
||||||
for thread_ident in tag_entry["threads"]:
|
for thread_ident in tag_entry["threads"]:
|
||||||
thread_entry = tag_entry["threads"][thread_ident]
|
thread_entry = tag_entry["threads"][thread_ident]
|
||||||
thread_captures = thread_entry["captures"]
|
thread_captures = thread_entry["captures"]
|
||||||
sample_count = len(thread_captures)
|
sample_count = len(thread_captures)
|
||||||
|
|
||||||
if sample_count > 2:
|
if sample_count > 2:
|
||||||
thread_results = {
|
thread_results = {
|
||||||
"count": sample_count,
|
"count": sample_count,
|
||||||
|
2
RNS/vendor/__init__.py
vendored
2
RNS/vendor/__init__.py
vendored
@ -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')]
|
||||||
|
502
RNS/vendor/configobj.py
vendored
502
RNS/vendor/configobj.py
vendored
File diff suppressed because it is too large
Load Diff
4
RNS/vendor/i2plib/__init__.py
vendored
4
RNS/vendor/i2plib/__init__.py
vendored
@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
A modern asynchronous library for building I2P applications.
|
A modern asynchronous library for building I2P applications.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .__version__ import (
|
from .__version__ import (
|
||||||
@ -10,7 +10,7 @@ from .__version__ import (
|
|||||||
from .sam import Destination, PrivateKey
|
from .sam import Destination, PrivateKey
|
||||||
|
|
||||||
from .aiosam import (
|
from .aiosam import (
|
||||||
get_sam_socket, dest_lookup, new_destination,
|
get_sam_socket, dest_lookup, new_destination,
|
||||||
create_session, stream_connect, stream_accept,
|
create_session, stream_connect, stream_accept,
|
||||||
Session, StreamConnection, StreamAcceptor
|
Session, StreamConnection, StreamAcceptor
|
||||||
)
|
)
|
||||||
|
54
RNS/vendor/i2plib/aiosam.py
vendored
54
RNS/vendor/i2plib/aiosam.py
vendored
@ -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")
|
||||||
|
|
||||||
@ -34,12 +34,12 @@ async def get_sam_socket(sam_address=sam.DEFAULT_ADDRESS, loop=None):
|
|||||||
writer.close()
|
writer.close()
|
||||||
raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]()
|
raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]()
|
||||||
|
|
||||||
async def dest_lookup(domain, sam_address=sam.DEFAULT_ADDRESS,
|
async def dest_lookup(domain, sam_address=sam.DEFAULT_ADDRESS,
|
||||||
loop=None):
|
loop=None):
|
||||||
"""A coroutine used to lookup a full I2P destination by .i2p domain or
|
"""A coroutine used to lookup a full I2P destination by .i2p domain or
|
||||||
.b32.i2p address.
|
.b32.i2p address.
|
||||||
|
|
||||||
:param domain: Address to be resolved, can be a .i2p domain or a .b32.i2p
|
:param domain: Address to be resolved, can be a .i2p domain or a .b32.i2p
|
||||||
address.
|
address.
|
||||||
:param sam_address: (optional) SAM API address
|
:param sam_address: (optional) SAM API address
|
||||||
:param loop: (optional) Event loop instance
|
:param loop: (optional) Event loop instance
|
||||||
@ -56,7 +56,7 @@ async def dest_lookup(domain, sam_address=sam.DEFAULT_ADDRESS,
|
|||||||
|
|
||||||
async def new_destination(sam_address=sam.DEFAULT_ADDRESS, loop=None,
|
async def new_destination(sam_address=sam.DEFAULT_ADDRESS, loop=None,
|
||||||
sig_type=sam.Destination.default_sig_type):
|
sig_type=sam.Destination.default_sig_type):
|
||||||
"""A coroutine used to generate a new destination with a private key of a
|
"""A coroutine used to generate a new destination with a private key of a
|
||||||
chosen signature type.
|
chosen signature type.
|
||||||
|
|
||||||
:param sam_address: (optional) SAM API address
|
:param sam_address: (optional) SAM API address
|
||||||
@ -70,7 +70,7 @@ async def new_destination(sam_address=sam.DEFAULT_ADDRESS, loop=None,
|
|||||||
writer.close()
|
writer.close()
|
||||||
return sam.Destination(reply["PRIV"], has_private_key=True)
|
return sam.Destination(reply["PRIV"], has_private_key=True)
|
||||||
|
|
||||||
async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
|
async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||||
loop=None, style="STREAM",
|
loop=None, style="STREAM",
|
||||||
signature_type=sam.Destination.default_sig_type,
|
signature_type=sam.Destination.default_sig_type,
|
||||||
destination=None, options={}):
|
destination=None, options={}):
|
||||||
@ -80,16 +80,16 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
|
|||||||
:param sam_address: (optional) SAM API address
|
:param sam_address: (optional) SAM API address
|
||||||
:param loop: (optional) Event loop instance
|
:param loop: (optional) Event loop instance
|
||||||
:param style: (optional) Session style, can be STREAM, DATAGRAM, RAW
|
:param style: (optional) Session style, can be STREAM, DATAGRAM, RAW
|
||||||
:param signature_type: (optional) If the destination is TRANSIENT, this
|
:param signature_type: (optional) If the destination is TRANSIENT, this
|
||||||
signature type is used
|
signature type is used
|
||||||
:param destination: (optional) Destination to use in this session. Can be
|
:param destination: (optional) Destination to use in this session. Can be
|
||||||
a base64 encoded string, :class:`Destination`
|
a base64 encoded string, :class:`Destination`
|
||||||
instance or None. TRANSIENT destination is used when it
|
instance or None. TRANSIENT destination is used when it
|
||||||
is None.
|
is None.
|
||||||
: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(
|
||||||
@ -111,15 +111,15 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
|
|||||||
if reply.ok:
|
if reply.ok:
|
||||||
if not destination:
|
if not destination:
|
||||||
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()
|
||||||
raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]()
|
raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]()
|
||||||
|
|
||||||
async def stream_connect(session_name, destination,
|
async def stream_connect(session_name, destination,
|
||||||
sam_address=sam.DEFAULT_ADDRESS, loop=None):
|
sam_address=sam.DEFAULT_ADDRESS, loop=None):
|
||||||
"""A coroutine used to connect to a remote I2P destination.
|
"""A coroutine used to connect to a remote I2P destination.
|
||||||
|
|
||||||
@ -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()
|
||||||
@ -173,16 +173,16 @@ class Session:
|
|||||||
:param sam_address: (optional) SAM API address
|
:param sam_address: (optional) SAM API address
|
||||||
:param loop: (optional) Event loop instance
|
:param loop: (optional) Event loop instance
|
||||||
:param style: (optional) Session style, can be STREAM, DATAGRAM, RAW
|
:param style: (optional) Session style, can be STREAM, DATAGRAM, RAW
|
||||||
:param signature_type: (optional) If the destination is TRANSIENT, this
|
:param signature_type: (optional) If the destination is TRANSIENT, this
|
||||||
signature type is used
|
signature type is used
|
||||||
:param destination: (optional) Destination to use in this session. Can be
|
:param destination: (optional) Destination to use in this session. Can be
|
||||||
a base64 encoded string, :class:`Destination`
|
a base64 encoded string, :class:`Destination`
|
||||||
instance or None. TRANSIENT destination is used when it
|
instance or None. TRANSIENT destination is used when it
|
||||||
is None.
|
is None.
|
||||||
:param options: (optional) A dict object with i2cp options
|
:param options: (optional) A dict object with i2cp options
|
||||||
:return: :class:`Session` object
|
:return: :class:`Session` object
|
||||||
"""
|
"""
|
||||||
def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS,
|
def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||||
loop=None, style="STREAM",
|
loop=None, style="STREAM",
|
||||||
signature_type=sam.Destination.default_sig_type,
|
signature_type=sam.Destination.default_sig_type,
|
||||||
destination=None, options={}):
|
destination=None, options={}):
|
||||||
@ -195,9 +195,9 @@ class Session:
|
|||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
self.reader, self.writer = await create_session(self.session_name,
|
self.reader, self.writer = await create_session(self.session_name,
|
||||||
sam_address=self.sam_address, loop=self.loop, style=self.style,
|
sam_address=self.sam_address, loop=self.loop, style=self.style,
|
||||||
signature_type=self.signature_type,
|
signature_type=self.signature_type,
|
||||||
destination=self.destination, options=self.options)
|
destination=self.destination, options=self.options)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ class StreamConnection:
|
|||||||
:param loop: (optional) Event loop instance
|
:param loop: (optional) Event loop instance
|
||||||
:return: :class:`StreamConnection` object
|
:return: :class:`StreamConnection` object
|
||||||
"""
|
"""
|
||||||
def __init__(self, session_name, destination,
|
def __init__(self, session_name, destination,
|
||||||
sam_address=sam.DEFAULT_ADDRESS, loop=None):
|
sam_address=sam.DEFAULT_ADDRESS, loop=None):
|
||||||
self.session_name = session_name
|
self.session_name = session_name
|
||||||
self.sam_address = sam_address
|
self.sam_address = sam_address
|
||||||
@ -222,7 +222,7 @@ class StreamConnection:
|
|||||||
self.destination = destination
|
self.destination = destination
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
self.reader, self.writer = await stream_connect(self.session_name,
|
self.reader, self.writer = await stream_connect(self.session_name,
|
||||||
self.destination, sam_address=self.sam_address, loop=self.loop)
|
self.destination, sam_address=self.sam_address, loop=self.loop)
|
||||||
self.read = self.reader.read
|
self.read = self.reader.read
|
||||||
self.write = self.writer.write
|
self.write = self.writer.write
|
||||||
@ -240,14 +240,14 @@ class StreamAcceptor:
|
|||||||
:param loop: (optional) Event loop instance
|
:param loop: (optional) Event loop instance
|
||||||
:return: :class:`StreamAcceptor` object
|
:return: :class:`StreamAcceptor` object
|
||||||
"""
|
"""
|
||||||
def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS,
|
def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||||
loop=None):
|
loop=None):
|
||||||
self.session_name = session_name
|
self.session_name = session_name
|
||||||
self.sam_address = sam_address
|
self.sam_address = sam_address
|
||||||
self.loop = loop
|
self.loop = loop
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
self.reader, self.writer = await stream_accept(self.session_name,
|
self.reader, self.writer = await stream_accept(self.session_name,
|
||||||
sam_address=self.sam_address, loop=self.loop)
|
sam_address=self.sam_address, loop=self.loop)
|
||||||
self.read = self.reader.read
|
self.read = self.reader.read
|
||||||
self.write = self.writer.write
|
self.write = self.writer.write
|
||||||
|
46
RNS/vendor/i2plib/sam.py
vendored
46
RNS/vendor/i2plib/sam.py
vendored
@ -8,7 +8,7 @@ I2P_B64_CHARS = "-~"
|
|||||||
|
|
||||||
def i2p_b64encode(x):
|
def i2p_b64encode(x):
|
||||||
"""Encode I2P destination"""
|
"""Encode I2P destination"""
|
||||||
return b64encode(x, altchars=I2P_B64_CHARS.encode()).decode()
|
return b64encode(x, altchars=I2P_B64_CHARS.encode()).decode()
|
||||||
|
|
||||||
def i2p_b64decode(x):
|
def i2p_b64decode(x):
|
||||||
"""Decode I2P destination"""
|
"""Decode I2P destination"""
|
||||||
@ -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,41 +51,37 @@ 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
|
||||||
|
|
||||||
:param data: (optional) Base64 encoded data or binary data
|
:param data: (optional) Base64 encoded data or binary data
|
||||||
:param path: (optional) A path to a file with binary data
|
:param path: (optional) A path to a file with binary data
|
||||||
:param has_private_key: (optional) Does data have a private key?
|
:param has_private_key: (optional) Does data have a private key?
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ECDSA_SHA256_P256 = 1
|
ECDSA_SHA256_P256 = 1
|
||||||
@ -101,12 +97,12 @@ 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
|
||||||
self.private_key = None
|
self.private_key = None
|
||||||
|
|
||||||
if path:
|
if path:
|
||||||
with open(path, "rb") as f: data = f.read()
|
with open(path, "rb") as f: data = f.read()
|
||||||
|
|
||||||
@ -123,20 +119,20 @@ 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):
|
||||||
"""Base32 destination hash of this destination"""
|
"""Base32 destination hash of this destination"""
|
||||||
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
|
||||||
|
|
||||||
:param data: Base64 encoded data or binary data
|
:param data: Base64 encoded data or binary data
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
|
49
RNS/vendor/i2plib/tunnel.py
vendored
49
RNS/vendor/i2plib/tunnel.py
vendored
@ -2,7 +2,7 @@ import logging
|
|||||||
import asyncio
|
import asyncio
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from . import sam
|
from . import sam
|
||||||
from . import aiosam
|
from . import aiosam
|
||||||
from . import utils
|
from . import utils
|
||||||
from .log import logger
|
from .log import logger
|
||||||
@ -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,12 +26,12 @@ 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.
|
||||||
E.g. ("127.0.0.1", 6668)
|
E.g. ("127.0.0.1", 6668)
|
||||||
:param destination: (optional) Destination to use for this tunnel. Can be
|
:param destination: (optional) Destination to use for this tunnel. Can be
|
||||||
a base64 encoded string, :class:`Destination`
|
a base64 encoded string, :class:`Destination`
|
||||||
instance or None. A new destination is created when it
|
instance or None. A new destination is created when it
|
||||||
is None.
|
is None.
|
||||||
@ -42,7 +42,7 @@ class I2PTunnel(object):
|
|||||||
:param sam_address: (optional) SAM API address
|
:param sam_address: (optional) SAM API address
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, local_address, destination=None, session_name=None,
|
def __init__(self, local_address, destination=None, session_name=None,
|
||||||
options={}, loop=None, sam_address=sam.DEFAULT_ADDRESS):
|
options={}, loop=None, sam_address=sam.DEFAULT_ADDRESS):
|
||||||
self.local_address = local_address
|
self.local_address = local_address
|
||||||
self.destination = destination
|
self.destination = destination
|
||||||
@ -57,7 +57,7 @@ class I2PTunnel(object):
|
|||||||
sam_address=self.sam_address, loop=self.loop)
|
sam_address=self.sam_address, loop=self.loop)
|
||||||
_, self.session_writer = await aiosam.create_session(
|
_, self.session_writer = await aiosam.create_session(
|
||||||
self.session_name, style=self.style, options=self.options,
|
self.session_name, style=self.style, options=self.options,
|
||||||
sam_address=self.sam_address,
|
sam_address=self.sam_address,
|
||||||
loop=self.loop, destination=self.destination)
|
loop=self.loop, destination=self.destination)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
@ -68,11 +68,11 @@ class ClientTunnel(I2PTunnel):
|
|||||||
"""Client tunnel, a subclass of tunnel.I2PTunnel
|
"""Client tunnel, a subclass of tunnel.I2PTunnel
|
||||||
|
|
||||||
If you run a client tunnel with a local address ("127.0.0.1", 6668) and
|
If you run a client tunnel with a local address ("127.0.0.1", 6668) and
|
||||||
a remote destination "irc.echelon.i2p", all connections to 127.0.0.1:6668
|
a remote destination "irc.echelon.i2p", all connections to 127.0.0.1:6668
|
||||||
will be proxied to irc.echelon.i2p.
|
will be proxied to irc.echelon.i2p.
|
||||||
|
|
||||||
:param remote_destination: Remote I2P destination, can be either .i2p
|
:param remote_destination: Remote I2P destination, can be either .i2p
|
||||||
domain, .b32.i2p address, base64 destination or
|
domain, .b32.i2p address, base64 destination or
|
||||||
:class:`Destination` instance
|
:class:`Destination` instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -90,12 +90,12 @@ class ClientTunnel(I2PTunnel):
|
|||||||
"""Handle local client connection"""
|
"""Handle local client connection"""
|
||||||
try:
|
try:
|
||||||
sc_task = aiosam.stream_connect(
|
sc_task = aiosam.stream_connect(
|
||||||
self.session_name, self.remote_destination,
|
self.session_name, self.remote_destination,
|
||||||
sam_address=self.sam_address, loop=self.loop)
|
sam_address=self.sam_address, loop=self.loop)
|
||||||
self.status["connect_tasks"].append(sc_task)
|
self.status["connect_tasks"].append(sc_task)
|
||||||
|
|
||||||
remote_reader, remote_writer = await sc_task
|
remote_reader, remote_writer = await sc_task
|
||||||
asyncio.ensure_future(proxy_data(remote_reader, client_writer),
|
asyncio.ensure_future(proxy_data(remote_reader, client_writer),
|
||||||
loop=self.loop)
|
loop=self.loop)
|
||||||
asyncio.ensure_future(proxy_data(client_reader, remote_writer),
|
asyncio.ensure_future(proxy_data(client_reader, remote_writer),
|
||||||
loop=self.loop)
|
loop=self.loop)
|
||||||
@ -123,8 +123,8 @@ class ServerTunnel(I2PTunnel):
|
|||||||
"""Server tunnel, a subclass of tunnel.I2PTunnel
|
"""Server tunnel, a subclass of tunnel.I2PTunnel
|
||||||
|
|
||||||
If you want to expose a local service 127.0.0.1:80 to the I2P network, run
|
If you want to expose a local service 127.0.0.1:80 to the I2P network, run
|
||||||
a server tunnel with a local address ("127.0.0.1", 80). If you don't
|
a server tunnel with a local address ("127.0.0.1", 80). If you don't
|
||||||
provide a private key or a session name, it will use a TRANSIENT
|
provide a private key or a session name, it will use a TRANSIENT
|
||||||
destination.
|
destination.
|
||||||
"""
|
"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -139,11 +139,10 @@ class ServerTunnel(I2PTunnel):
|
|||||||
async def handle_client(incoming, client_reader, client_writer):
|
async def handle_client(incoming, client_reader, client_writer):
|
||||||
try:
|
try:
|
||||||
# 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
|
||||||
self.status["setup_failed"] = True
|
self.status["setup_failed"] = True
|
||||||
@ -152,7 +151,7 @@ class ServerTunnel(I2PTunnel):
|
|||||||
try:
|
try:
|
||||||
sc_task = asyncio.wait_for(
|
sc_task = asyncio.wait_for(
|
||||||
asyncio.open_connection(
|
asyncio.open_connection(
|
||||||
host=self.local_address[0],
|
host=self.local_address[0],
|
||||||
port=self.local_address[1]),
|
port=self.local_address[1]),
|
||||||
timeout=5)
|
timeout=5)
|
||||||
self.status["connect_tasks"].append(sc_task)
|
self.status["connect_tasks"].append(sc_task)
|
||||||
@ -173,7 +172,7 @@ class ServerTunnel(I2PTunnel):
|
|||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
client_reader, client_writer = await aiosam.stream_accept(
|
client_reader, client_writer = await aiosam.stream_accept(
|
||||||
self.session_name, sam_address=self.sam_address,
|
self.session_name, sam_address=self.sam_address,
|
||||||
loop=self.loop)
|
loop=self.loop)
|
||||||
incoming = await client_reader.read(BUFFER_SIZE)
|
incoming = await client_reader.read(BUFFER_SIZE)
|
||||||
asyncio.ensure_future(handle_client(
|
asyncio.ensure_future(handle_client(
|
||||||
@ -193,13 +192,13 @@ if __name__ == '__main__':
|
|||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('type', metavar="TYPE", choices=('server', 'client'),
|
parser.add_argument('type', metavar="TYPE", choices=('server', 'client'),
|
||||||
help="Tunnel type (server or client)")
|
help="Tunnel type (server or client)")
|
||||||
parser.add_argument('address', metavar="ADDRESS",
|
parser.add_argument('address', metavar="ADDRESS",
|
||||||
help="Local address (e.g. 127.0.0.1:8000)")
|
help="Local address (e.g. 127.0.0.1:8000)")
|
||||||
parser.add_argument('--debug', '-d', action='store_true',
|
parser.add_argument('--debug', '-d', action='store_true',
|
||||||
help='Debugging')
|
help='Debugging')
|
||||||
parser.add_argument('--key', '-k', default='', metavar='PRIVATE_KEY',
|
parser.add_argument('--key', '-k', default='', metavar='PRIVATE_KEY',
|
||||||
help='Path to private key file')
|
help='Path to private key file')
|
||||||
parser.add_argument('--destination', '-D', default='',
|
parser.add_argument('--destination', '-D', default='',
|
||||||
metavar='DESTINATION', help='Remote destination')
|
metavar='DESTINATION', help='Remote destination')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@ -217,10 +216,10 @@ if __name__ == '__main__':
|
|||||||
local_address = utils.address_from_string(args.address)
|
local_address = utils.address_from_string(args.address)
|
||||||
|
|
||||||
if args.type == "client":
|
if args.type == "client":
|
||||||
tunnel = ClientTunnel(args.destination, local_address, loop=loop,
|
tunnel = ClientTunnel(args.destination, local_address, loop=loop,
|
||||||
destination=destination, sam_address=SAM_ADDRESS)
|
destination=destination, sam_address=SAM_ADDRESS)
|
||||||
elif args.type == "server":
|
elif args.type == "server":
|
||||||
tunnel = ServerTunnel(local_address, loop=loop, destination=destination,
|
tunnel = ServerTunnel(local_address, loop=loop, destination=destination,
|
||||||
sam_address=SAM_ADDRESS)
|
sam_address=SAM_ADDRESS)
|
||||||
|
|
||||||
asyncio.ensure_future(tunnel.run(), loop=loop)
|
asyncio.ensure_future(tunnel.run(), loop=loop)
|
||||||
|
2
RNS/vendor/i2plib/utils.py
vendored
2
RNS/vendor/i2plib/utils.py
vendored
@ -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)}"
|
||||||
|
|
||||||
|
2
RNS/vendor/ifaddr/__init__.py
vendored
2
RNS/vendor/ifaddr/__init__.py
vendored
@ -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']
|
||||||
|
2
RNS/vendor/ifaddr/_posix.py
vendored
2
RNS/vendor/ifaddr/_posix.py
vendored
@ -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)
|
||||||
|
12
RNS/vendor/ifaddr/_shared.py
vendored
12
RNS/vendor/ifaddr/_shared.py
vendored
@ -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():
|
||||||
|
2
RNS/vendor/ifaddr/niwrapper.py
vendored
2
RNS/vendor/ifaddr/niwrapper.py
vendored
@ -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
55
RNS/vendor/six.py
vendored
@ -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
|
||||||
|
70
RNS/vendor/umsgpack.py
vendored
70
RNS/vendor/umsgpack.py
vendored
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 = [
|
||||||
|
6
setup.py
6
setup.py
@ -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']
|
||||||
|
@ -62,7 +62,7 @@ class Packet:
|
|||||||
|
|
||||||
def set_delivered_callback(self, callback: Callable[[Packet], None]):
|
def set_delivered_callback(self, callback: Callable[[Packet], None]):
|
||||||
self.delivered_callback = callback
|
self.delivered_callback = callback
|
||||||
|
|
||||||
def delivered(self):
|
def delivered(self):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
self.state = MessageState.MSGSTATE_DELIVERED
|
self.state = MessageState.MSGSTATE_DELIVERED
|
||||||
@ -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
|
||||||
|
@ -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")
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -187,7 +187,7 @@ class TestIdentity(unittest.TestCase):
|
|||||||
lb = 1
|
lb = 1
|
||||||
else:
|
else:
|
||||||
lb = 8
|
lb = 8
|
||||||
|
|
||||||
for i in range(1, lb):
|
for i in range(1, lb):
|
||||||
msg = os.urandom(mlen)
|
msg = os.urandom(mlen)
|
||||||
b += mlen
|
b += mlen
|
||||||
@ -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)
|
||||||
|
108
tests/link.py
108
tests/link.py
@ -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:
|
||||||
@ -105,7 +105,7 @@ class TestLink(unittest.TestCase):
|
|||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
|
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
|
||||||
l1 = RNS.Link(dest)
|
l1 = RNS.Link(dest)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||||
@ -129,7 +129,7 @@ class TestLink(unittest.TestCase):
|
|||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
|
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
|
||||||
l1 = RNS.Link(dest)
|
l1 = RNS.Link(dest)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||||
@ -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)
|
||||||
@ -201,7 +201,7 @@ class TestLink(unittest.TestCase):
|
|||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
|
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
|
||||||
l1 = RNS.Link(dest)
|
l1 = RNS.Link(dest)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||||
@ -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)
|
||||||
@ -241,7 +241,7 @@ class TestLink(unittest.TestCase):
|
|||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
|
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
|
||||||
l1 = RNS.Link(dest)
|
l1 = RNS.Link(dest)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||||
@ -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)
|
||||||
@ -280,7 +280,7 @@ class TestLink(unittest.TestCase):
|
|||||||
|
|
||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
|
||||||
l1 = RNS.Link(dest)
|
l1 = RNS.Link(dest)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||||
@ -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)
|
||||||
@ -310,7 +310,7 @@ class TestLink(unittest.TestCase):
|
|||||||
if RNS.Cryptography.backend() == "internal":
|
if RNS.Cryptography.backend() == "internal":
|
||||||
print("Skipping medium resource test...")
|
print("Skipping medium resource test...")
|
||||||
return
|
return
|
||||||
|
|
||||||
init_rns(self)
|
init_rns(self)
|
||||||
print("")
|
print("")
|
||||||
print("Medium resource test")
|
print("Medium resource test")
|
||||||
@ -324,7 +324,7 @@ class TestLink(unittest.TestCase):
|
|||||||
|
|
||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
|
||||||
l1 = RNS.Link(dest)
|
l1 = RNS.Link(dest)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||||
@ -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)
|
||||||
@ -371,7 +371,7 @@ class TestLink(unittest.TestCase):
|
|||||||
|
|
||||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||||
|
|
||||||
l1 = RNS.Link(dest)
|
l1 = RNS.Link(dest)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||||
@ -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)
|
||||||
|
|
||||||
@ -553,26 +553,26 @@ class TestLink(unittest.TestCase):
|
|||||||
target_bytes = 3000
|
target_bytes = 3000
|
||||||
else:
|
else:
|
||||||
target_bytes = BUFFER_TEST_TARGET
|
target_bytes = BUFFER_TEST_TARGET
|
||||||
|
|
||||||
random.seed(154889)
|
random.seed(154889)
|
||||||
message = random.randbytes(target_bytes)
|
message = random.randbytes(target_bytes)
|
||||||
buffer_read_target = len(message)
|
buffer_read_target = len(message)
|
||||||
|
|
||||||
# the return message will have an appendage string " back at you"
|
# the return message will have an appendage string " back at you"
|
||||||
# for every StreamDataMessage that arrives. To verify, we need
|
# for every StreamDataMessage that arrives. To verify, we need
|
||||||
# to insert that string every MAX_DATA_LEN and also at the end.
|
# to insert that string every MAX_DATA_LEN and also at the end.
|
||||||
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
|
||||||
|
|
||||||
@ -723,7 +723,7 @@ def profile_resource():
|
|||||||
resource_profiling()
|
resource_profiling()
|
||||||
|
|
||||||
def profile_targets():
|
def profile_targets():
|
||||||
|
|
||||||
targets_profiling(yp=True)
|
targets_profiling(yp=True)
|
||||||
# cProfile.runctx("entry()", {"entry": targets_profiling, "size_str": size_str}, {}, "profile-targets.data")
|
# cProfile.runctx("entry()", {"entry": targets_profiling, "size_str": size_str}, {}, "profile-targets.data")
|
||||||
# p = pstats.Stats("profile-targets.data")
|
# p = pstats.Stats("profile-targets.data")
|
||||||
@ -745,11 +745,11 @@ 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()
|
||||||
|
|
||||||
resource = RNS.Resource(data, l1, timeout=resource_timeout)
|
resource = RNS.Resource(data, l1, timeout=resource_timeout)
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
@ -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}"
|
Loading…
Reference in New Issue
Block a user