diff --git a/nomadnet/Directory.py b/nomadnet/Directory.py index 875f621..64eaf07 100644 --- a/nomadnet/Directory.py +++ b/nomadnet/Directory.py @@ -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: diff --git a/nomadnet/NomadNetworkApp.py b/nomadnet/NomadNetworkApp.py index 76695be..d0ac8a5 100644 --- a/nomadnet/NomadNetworkApp.py +++ b/nomadnet/NomadNetworkApp.py @@ -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: diff --git a/nomadnet/_version.py b/nomadnet/_version.py index fe404ae..01ef120 100644 --- a/nomadnet/_version.py +++ b/nomadnet/_version.py @@ -1 +1 @@ -__version__ = "0.2.5" +__version__ = "0.2.6" diff --git a/nomadnet/ui/textui/Conversations.py b/nomadnet/ui/textui/Conversations.py index 12645e5..cac9b89 100644 --- a/nomadnet/ui/textui/Conversations.py +++ b/nomadnet/ui/textui/Conversations.py @@ -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" diff --git a/nomadnet/ui/textui/Network.py b/nomadnet/ui/textui/Network.py index 525fc0b..ebc9e2a 100644 --- a/nomadnet/ui/textui/Network.py +++ b/nomadnet/ui/textui/Network.py @@ -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)