Implemented support for standalone LXMF propagation nodes

This commit is contained in:
Mark Qvist 2022-10-25 12:52:02 +02:00
parent fe257a63c0
commit 4fcf37ac86
5 changed files with 121 additions and 48 deletions

View File

@ -5,6 +5,29 @@ import time
import nomadnet
import RNS.vendor.umsgpack as msgpack
class PNAnnounceHandler:
def __init__(self, owner):
self.aspect_filter = "lxmf.propagation"
self.owner = owner
def received_announce(self, destination_hash, announced_identity, app_data):
try:
if type(app_data) == bytes:
data = msgpack.unpackb(app_data)
if data[0] == True:
RNS.log("Received active propagation node announce from "+RNS.prettyhexrep(destination_hash))
associated_peer = RNS.Destination.hash_from_name_and_identity("lxmf.delivery", announced_identity)
associated_node = RNS.Destination.hash_from_name_and_identity("nomadnetwork.node", announced_identity)
self.owner.app.directory.pn_announce_received(destination_hash, app_data, associated_peer, associated_node)
self.owner.app.autoselect_propagation_node()
except Exception as e:
RNS.log("Error while evaluating propagation node announce, ignoring announce.", RNS.LOG_DEBUG)
RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG)
class Directory:
ANNOUNCE_STREAM_MAXLENGTH = 64
@ -14,8 +37,6 @@ class Directory:
app = nomadnet.NomadNetworkApp.get_shared_instance()
if not destination_hash in app.ignored_list:
destination_hash_text = RNS.hexrep(destination_hash, delimit=False)
associated_peer = RNS.Destination.hash_from_name_and_identity("lxmf.delivery", announced_identity)
app.directory.node_announce_received(destination_hash, app_data, associated_peer)
@ -31,6 +52,9 @@ class Directory:
self.app = app
self.load_from_disk()
self.pn_announce_handler = PNAnnounceHandler(self)
RNS.Transport.register_announce_handler(self.pn_announce_handler)
def save_to_disk(self):
try:
@ -90,7 +114,7 @@ class Directory:
def lxmf_announce_received(self, source_hash, app_data):
if app_data != None:
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, False))
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "peer"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
@ -100,7 +124,7 @@ class Directory:
def node_announce_received(self, source_hash, app_data, associated_peer):
if app_data != None:
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, True))
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "node"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
@ -113,6 +137,27 @@ class Directory:
if hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
def pn_announce_received(self, source_hash, app_data, associated_peer, associated_node):
found_node = None
for sh in self.directory_entries:
if sh == associated_node:
found_node = True
break
for e in self.announce_stream:
if e[1] == associated_node:
found_node = True
break
if not found_node:
timestamp = time.time()
self.announce_stream.insert(0, (timestamp, source_hash, app_data, "pn"))
while len(self.announce_stream) > Directory.ANNOUNCE_STREAM_MAXLENGTH:
self.announce_stream.pop()
if hasattr(self.app.ui, "main_display"):
self.app.ui.main_display.sub_displays.network_display.directory_change_callback()
def remove_announce_with_timestamp(self, timestamp):
selected_announce = None
for announce in self.announce_stream:
@ -250,11 +295,6 @@ class DirectoryEntry:
def __init__(self, source_hash, display_name=None, trust_level=UNKNOWN, hosts_node=False, preferred_delivery=None, identify_on_connect=False):
if len(source_hash) == RNS.Identity.TRUNCATED_HASHLENGTH//8:
self.source_hash = source_hash
# TODO: Clean
# if display_name == None:
# display_name = source_hash
self.display_name = display_name
if preferred_delivery == None:

View File

@ -436,8 +436,9 @@ class NomadNetworkApp:
def autoselect_propagation_node(self):
selected_node = None
if "propagation_node" in self.peer_settings and self.directory.find(self.peer_settings["propagation_node"]):
selected_node = self.directory.find(self.peer_settings["propagation_node"])
if "propagation_node" in self.peer_settings:
selected_node = self.peer_settings["propagation_node"]
else:
nodes = self.directory.known_nodes()
trusted_nodes = []
@ -450,19 +451,14 @@ class NomadNetworkApp:
if hops < best_hops:
best_hops = hops
selected_node = node
selected_node = node.source_hash
if selected_node == None:
RNS.log("Could not autoselect a propagation node! LXMF propagation will not be available until a trusted node announces on the network.", RNS.LOG_WARNING)
RNS.log("Could not autoselect a propagation node! LXMF propagation will not be available until a trusted node announces on the network, or a propagation node is manually selected.", RNS.LOG_WARNING)
else:
node_identity = RNS.Identity.recall(selected_node.source_hash)
if node_identity != None:
propagation_hash = RNS.Destination.hash_from_name_and_identity("lxmf.propagation", node_identity)
RNS.log("Selecting "+selected_node.display_name+" "+RNS.prettyhexrep(propagation_hash)+" as default LXMF propagation node", RNS.LOG_INFO)
self.message_router.set_outbound_propagation_node(propagation_hash)
else:
RNS.log("Could not recall identity for autoselected LXMF propagation node "+RNS.prettyhexrep(selected_node.source_hash), RNS.LOG_WARNING)
RNS.log("LXMF propagation will not be available until a trusted node announces on the network.", RNS.LOG_WARNING)
pn_name_str = ""
RNS.log("Selecting "+RNS.prettyhexrep(selected_node)+pn_name_str+" as default LXMF propagation node", RNS.LOG_INFO)
self.message_router.set_outbound_propagation_node(selected_node)
def get_user_selected_propagation_node(self):
if "propagation_node" in self.peer_settings:

View File

@ -1 +1 @@
__version__ = "0.2.5"
__version__ = "0.2.6"

View File

@ -398,10 +398,15 @@ class ConversationsDisplay():
if pn_ident != None:
node_hash = RNS.Destination.hash_from_name_and_identity("nomadnetwork.node", pn_ident)
pn_entry = self.app.directory.find(node_hash)
pn_display_str = " "
if pn_entry != None:
pn_display_str += " "+str(pn_entry.display_name)
else:
pn_display_str += " "+RNS.prettyhexrep(pn_hash)
dialog = DialogLineBox(
urwid.Pile([
urwid.Text(""+g["node"]+" "+str(pn_entry.display_name), align="center"),
urwid.Text(""+g["node"]+pn_display_str, align="center"),
urwid.Divider(g["divider1"]),
sync_progress,
urwid.Divider(g["divider1"]),
@ -417,7 +422,7 @@ class ConversationsDisplay():
urwid.Pile([
urwid.Text(""),
urwid.Text("No trusted nodes found, cannot sync!\n", align="center"),
urwid.Text("To syncronise messages from the network, one or more nodes must be marked as trusted in the Known Nodes list. Nomad Network will then automatically sync from the nearest trusted node.", align="left"),
urwid.Text("To syncronise messages from the network, one or more nodes must be marked as trusted in the Known Nodes list, or a node must manually be selected as the default propagation node. Nomad Network will then automatically sync from the nearest trusted node, or the manually selected one.", align="left"),
urwid.Text(""),
button_columns
]), title="Message Sync"

View File

@ -71,11 +71,17 @@ class AnnounceInfo(urwid.WidgetWrap):
trust_str = ""
display_str = self.app.directory.simplest_display_str(source_hash)
addr_str = "<"+RNS.hexrep(source_hash, delimit=False)+">"
is_node = announce[3]
info_type = announce[3]
if is_node:
type_string = "Node " + g["node"]
else:
is_node = False
is_pn = False
if info_type == "node" or info_type == True:
type_string = "Nomad Network Node " + g["node"]
is_node = True
elif info_type == "pn":
type_string = "LXMF Propagation Node " + g["sent"]
is_pn = True
elif info_type == "peer" or info_type == False:
type_string = "Peer " + g["peer"]
try:
@ -174,10 +180,20 @@ class AnnounceInfo(urwid.WidgetWrap):
except Exception as e:
RNS.log("Error while starting conversation from announce. The contained exception was: "+str(e), RNS.LOG_ERROR)
def use_pn(sender):
show_announce_stream(None)
try:
self.app.set_user_selected_propagation_node(source_hash)
except Exception as e:
RNS.log("Error while setting active propagation node from announce. The contained exception was: "+str(e), RNS.LOG_ERROR)
if is_node:
type_button = ("weight", 0.45, urwid.Button("Connect", on_press=connect))
msg_button = ("weight", 0.45, urwid.Button("Msg Op", on_press=msg_op))
save_button = ("weight", 0.45, urwid.Button("Save", on_press=save_node))
elif is_pn:
type_button = ("weight", 0.45, urwid.Button("Use as default", on_press=use_pn))
save_button = None
else:
type_button = ("weight", 0.45, urwid.Button("Converse", on_press=converse))
save_button = None
@ -187,21 +203,33 @@ class AnnounceInfo(urwid.WidgetWrap):
else:
button_columns = urwid.Columns([("weight", 0.45, urwid.Button("Back", on_press=show_announce_stream)), ("weight", 0.1, urwid.Text("")), type_button])
pile_widgets = [
urwid.Text("Time : "+ts_string, align="left"),
urwid.Text("Addr : "+addr_str, align="left"),
urwid.Text("Type : "+type_string, align="left"),
urwid.Text("Name : "+display_str, align="left"),
urwid.Text(["Trust : ", (style, trust_str)], align="left"),
urwid.Divider(g["divider1"]),
urwid.Text(["Announce Data: \n", (data_style, data_str)], align="left"),
urwid.Divider(g["divider1"]),
button_columns
]
pile_widgets = []
if is_node:
operator_entry = urwid.Text("Oprtr : "+op_str, align="left")
pile_widgets.insert(4, operator_entry)
if is_pn:
pile_widgets = [
urwid.Text("Time : "+ts_string, align="left"),
urwid.Text("Addr : "+addr_str, align="left"),
urwid.Text("Type : "+type_string, align="left"),
urwid.Divider(g["divider1"]),
button_columns
]
else:
pile_widgets = [
urwid.Text("Time : "+ts_string, align="left"),
urwid.Text("Addr : "+addr_str, align="left"),
urwid.Text("Type : "+type_string, align="left"),
urwid.Text("Name : "+display_str, align="left"),
urwid.Text(["Trust : ", (style, trust_str)], align="left"),
urwid.Divider(g["divider1"]),
urwid.Text(["Announce Data: \n", (data_style, data_str)], align="left"),
urwid.Divider(g["divider1"]),
button_columns
]
if is_node:
operator_entry = urwid.Text("Oprtr : "+op_str, align="left")
pile_widgets.insert(4, operator_entry)
pile = urwid.Pile(pile_widgets)
@ -220,7 +248,7 @@ class AnnounceStreamEntry(urwid.WidgetWrap):
timestamp = announce[0]
source_hash = announce[1]
is_node = announce[3]
announce_type = announce[3]
self.app = app
self.timestamp = timestamp
time_format = app.time_format
@ -257,10 +285,12 @@ class AnnounceStreamEntry(urwid.WidgetWrap):
style = "list_untrusted"
focus_style = "list_focus_untrusted"
if is_node:
if announce_type == "node" or announce_type == True:
type_symbol = g["node"]
else:
elif announce_type == "peer" or announce_type == False:
type_symbol = g["peer"]
elif announce_type == "pn":
type_symbol = g["sent"]
widget = ListEntry(ts_string+" "+type_symbol+" "+display_str)
urwid.connect_signal(widget, "click", self.display_announce, announce)
@ -425,13 +455,15 @@ class KnownNodeInfo(urwid.WidgetWrap):
if display_str == None:
display_str = addr_str
pn_hash = RNS.Destination.hash_from_name_and_identity("lxmf.propagation", node_ident)
if node_ident != None:
lxmf_addr_str = g["sent"]+" LXMF Propagation Node Address is "+RNS.prettyhexrep(RNS.Destination.hash_from_name_and_identity("lxmf.propagation", node_ident))
lxmf_addr_str = g["sent"]+" LXMF Propagation Node Address is "+RNS.prettyhexrep(pn_hash)
else:
lxmf_addr_str = "No associated Propagation Node known"
type_string = "Node " + g["node"]
type_string = "Nomad Network Node " + g["node"]
if trust_level == DirectoryEntry.UNTRUSTED:
trust_str = "Untrusted"
@ -525,7 +557,7 @@ class KnownNodeInfo(urwid.WidgetWrap):
def save_node(sender):
if self.pn_changed:
if propagation_node_checkbox.get_state():
self.app.set_user_selected_propagation_node(source_hash)
self.app.set_user_selected_propagation_node(pn_hash)
else:
self.app.set_user_selected_propagation_node(None)