diff --git a/LXMF/LXMF.py b/LXMF/LXMF.py index fd2abf0..dbc0ab1 100644 --- a/LXMF/LXMF.py +++ b/LXMF/LXMF.py @@ -147,6 +147,28 @@ def stamp_cost_from_app_data(app_data=None): # Original announce format else: return None +def pn_name_from_app_data(app_data=None): + if app_data == None: return None + else: + if pn_announce_data_is_valid(app_data): + data = msgpack.unpackb(app_data) + metadata = data[6] + if not PN_META_NAME in metadata: return None + else: + try: return metadata[PN_META_NAME].decode("utf-8") + except: return None + + return None + +def pn_stamp_cost_from_app_data(app_data=None): + if app_data == None: return None + else: + if pn_announce_data_is_valid(app_data): + data = msgpack.unpackb(app_data) + return data[5][0] + else: + return None + def pn_announce_data_is_valid(data): try: if type(data) != bytes: return False diff --git a/LXMF/LXMPeer.py b/LXMF/LXMPeer.py index 199ee2d..a67d3b2 100644 --- a/LXMF/LXMPeer.py +++ b/LXMF/LXMPeer.py @@ -8,6 +8,7 @@ import LXMF.LXStamper as LXStamper from collections import deque from .LXMF import APP_NAME +from .LXMF import PN_META_NAME class LXMPeer: OFFER_REQUEST_PATH = "/offer" @@ -110,6 +111,8 @@ class LXMPeer: else: peer.last_sync_attempt = 0 if "peering_key" in dictionary: peer.peering_key = dictionary["peering_key"] else: peer.peering_key = None + if "metadata" in dictionary: peer.metadata = dictionary["metadata"] + else: peer.metadata = None hm_count = 0 for transient_id in dictionary["handled_ids"]: @@ -135,6 +138,7 @@ class LXMPeer: dictionary = {} dictionary["peering_timebase"] = self.peering_timebase dictionary["alive"] = self.alive + dictionary["metadata"] = self.metadata dictionary["last_heard"] = self.last_heard dictionary["sync_strategy"] = self.sync_strategy dictionary["peering_key"] = self.peering_key @@ -175,6 +179,7 @@ class LXMPeer: self.sync_strategy = sync_strategy self.peering_key = None self.peering_cost = None + self.metadata = None self.next_sync_attempt = 0 self.last_sync_attempt = 0 @@ -616,6 +621,15 @@ class LXMPeer: self.router.propagation_entries[transient_id][5].remove(self.destination_hash) self._um_counts_synced = False + @property + def name(self): + if type(self.metadata) != dict: return None + else: + if not PN_META_NAME in self.metadata: return None + else: + try: return self.metadata[PN_META_NAME].decode("utf-8") + except: return None + def __str__(self): if self.destination_hash: return RNS.prettyhexrep(self.destination_hash) else: return "" \ No newline at end of file diff --git a/LXMF/LXMRouter.py b/LXMF/LXMRouter.py index 39ee7ec..3ab85e8 100644 --- a/LXMF/LXMRouter.py +++ b/LXMF/LXMRouter.py @@ -15,6 +15,7 @@ import RNS.vendor.umsgpack as msgpack from .LXMF import APP_NAME from .LXMF import FIELD_TICKET +from .LXMF import PN_META_NAME from .LXMF import pn_announce_data_is_valid from .LXMPeer import LXMPeer @@ -84,7 +85,7 @@ class LXMRouter: enforce_ratchets=False, enforce_stamps=False, static_peers = [], max_peers=None, from_static_only=False, sync_strategy=LXMPeer.STRATEGY_PERSISTENT, propagation_cost=PROPAGATION_COST, propagation_cost_flexibility=PROPAGATION_COST_FLEX, - peering_cost=PEERING_COST): + peering_cost=PEERING_COST, name=None): random.seed(os.urandom(10)) @@ -105,9 +106,10 @@ class LXMRouter: self.processing_outbound = False self.processing_inbound = False self.processing_count = 0 + self.name = name self.propagation_node = False - self.propagation_node_start_time = None + self.propagation_node_start_time = None if storagepath == None: raise ValueError("LXMF cannot be initialised without a storage path") else: @@ -287,10 +289,15 @@ class LXMRouter: if destination_hash in self.delivery_destinations: self.delivery_destinations[destination_hash].announce(app_data=self.get_announce_app_data(destination_hash), attached_interface=attached_interface) + def get_propagation_node_announce_metadata(self): + metadata = {} + if self.name: metadata[PN_META_NAME] = str(self.name).encode("utf-8") + return metadata + def get_propagation_node_app_data(self): + metadata = self.get_propagation_node_announce_metadata() node_state = self.propagation_node and not self.from_static_only stamp_cost = [self.propagation_stamp_cost, self.propagation_stamp_cost_flexibility, self.peering_cost] - metadata = {} announce_data = [ False, # 0: Legacy LXMF PN support int(time.time()), # 1: Current node timebase node_state, # 2: Boolean flag signalling propagation node state @@ -737,6 +744,7 @@ class LXMRouter: "type": "static" if peer_id in self.static_peers else "discovered", "state": peer.state, "alive": peer.alive, + "name": peer.name, "last_heard": int(peer.last_heard), "next_sync_attempt": peer.next_sync_attempt, "last_sync_attempt": peer.last_sync_attempt, @@ -1834,6 +1842,7 @@ class LXMRouter: peer = self.peers[destination_hash] if timestamp > peer.peering_timebase: peer.alive = True + peer.metadata = metadata peer.sync_backoff = 0 peer.next_sync_attempt = 0 peer.peering_timebase = timestamp @@ -1852,6 +1861,7 @@ class LXMRouter: else: peer = LXMPeer(self, destination_hash, sync_strategy=self.default_sync_strategy) peer.alive = True + peer.metadata = metadata peer.last_heard = time.time() peer.propagation_stamp_cost = propagation_stamp_cost peer.propagation_stamp_cost_flexibility = propagation_stamp_cost_flexibility diff --git a/LXMF/Utilities/lxmd.py b/LXMF/Utilities/lxmd.py index 69bb26e..5d21bd3 100644 --- a/LXMF/Utilities/lxmd.py +++ b/LXMF/Utilities/lxmd.py @@ -97,6 +97,11 @@ def apply_config(): else: active_configuration["enable_propagation_node"] = False + if "propagation" in lxmd_config and "node_name" in lxmd_config["propagation"]: + active_configuration["node_name"] = lxmd_config["propagation"].get("node_name") + else: + active_configuration["node_name"] = None + if "propagation" in lxmd_config and "auth_required" in lxmd_config["propagation"]: active_configuration["auth_required"] = lxmd_config["propagation"].as_bool("auth_required") else: @@ -371,7 +376,8 @@ def program_setup(configdir = None, rnsconfigdir = None, run_pn = False, on_inbo delivery_limit = active_configuration["delivery_transfer_max_accepted_size"], max_peers = active_configuration["max_peers"], static_peers = active_configuration["static_peers"], - from_static_only = active_configuration["from_static_only"]) + from_static_only = active_configuration["from_static_only"], + name = active_configuration["node_name"]) message_router.register_delivery_callback(lxmf_delivery) @@ -647,8 +653,12 @@ def get_status(configdir = None, rnsconfigdir = None, verbosity = 0, quietness = sstr = RNS.prettyspeed(p["str"]); sler = RNS.prettyspeed(p["ler"]) stl = RNS.prettysize(p["transfer_limit"]*1000); ssl = RNS.prettysize(p["sync_limit"]*1000) srxb = RNS.prettysize(p["rx_bytes"]); stxb = RNS.prettysize(p["tx_bytes"]); pmo = pm["offered"]; pmout = pm["outgoing"] - pmi = pm["incoming"]; pmuh = pm["unhandled"] + pmi = pm["incoming"]; pmuh = pm["unhandled"]; + if p["name"] == None: nn = "" + else: nn = p["name"].strip().replace("\n", "").replace("\r", "") + if len(nn) > 45: nn = f"{nn[:45]}..." print(f"{ind}{t}{RNS.prettyhexrep(peer_id)}") + if len(nn): print(f"{ind*2}Name : {nn}") print(f"{ind*2}Status : {a}, {hs}, last heard {RNS.prettytime(h)} ago") print(f"{ind*2}Costs : Propagation {psc} (flex {psf}), peering {pc}") print(f"{ind*2}Sync key : {pk}") @@ -717,6 +727,11 @@ __default_lxmd_config__ = """# This is an example LXM Daemon config file. enable_node = no +# An optional name for this node, included +# in announces. + +# node_name = Anonymous Propagation Node + # Automatic announce interval in minutes. # 6 hours by default.