From 5608a11bf2c163874256bf56c5a94091385187b3 Mon Sep 17 00:00:00 2001 From: SebastianObi Date: Tue, 17 Dec 2024 14:11:16 +0100 Subject: [PATCH] Improved method settings --- lxmf_bridge_matrix/lxmf_bridge_matrix.py | 95 +++++++------ lxmf_bridge_mqtt/lxmf_bridge_mqtt.py | 95 +++++++------ lxmf_chatbot/lxmf_chatbot.py | 95 +++++++------ lxmf_cmd/lxmf_cmd.py | 95 +++++++------ .../lxmf_distribution_group.py | 96 ++++++++------ .../lxmf_distribution_group_extended.py | 125 +++++++++--------- .../lxmf_distribution_group_minimal.py | 96 ++++++++------ lxmf_echo/lxmf_echo.py | 95 +++++++------ lxmf_provisioning/lxmf_provisioning.py | 95 +++++++------ lxmf_terminal/lxmf_terminal.py | 95 +++++++------ lxmf_test/lxmf_test.py | 86 +++++++----- lxmf_welcome/lxmf_welcome.py | 95 +++++++------ 12 files changed, 647 insertions(+), 516 deletions(-) diff --git a/lxmf_bridge_matrix/lxmf_bridge_matrix.py b/lxmf_bridge_matrix/lxmf_bridge_matrix.py index eba5a1b..5f146fe 100755 --- a/lxmf_bridge_matrix/lxmf_bridge_matrix.py +++ b/lxmf_bridge_matrix/lxmf_bridge_matrix.py @@ -164,7 +164,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -180,15 +180,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -349,7 +345,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -368,20 +364,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -393,14 +418,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -413,19 +437,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -436,13 +464,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -601,7 +622,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -614,7 +634,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -647,10 +666,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1630,11 +1646,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -1755,7 +1770,7 @@ destination_type = delivery display_name = # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -1766,10 +1781,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = Yes - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = No diff --git a/lxmf_bridge_mqtt/lxmf_bridge_mqtt.py b/lxmf_bridge_mqtt/lxmf_bridge_mqtt.py index 540d2d1..b5d3742 100755 --- a/lxmf_bridge_mqtt/lxmf_bridge_mqtt.py +++ b/lxmf_bridge_mqtt/lxmf_bridge_mqtt.py @@ -158,7 +158,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -174,15 +174,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -343,7 +339,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -362,20 +358,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -387,14 +412,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -407,19 +431,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -430,13 +458,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -595,7 +616,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -608,7 +628,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -641,10 +660,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1408,11 +1424,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -1527,7 +1542,7 @@ destination_type = delivery display_name = # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -1538,10 +1553,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = Yes - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = No diff --git a/lxmf_chatbot/lxmf_chatbot.py b/lxmf_chatbot/lxmf_chatbot.py index b0329b4..65b3b23 100755 --- a/lxmf_chatbot/lxmf_chatbot.py +++ b/lxmf_chatbot/lxmf_chatbot.py @@ -156,7 +156,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -172,15 +172,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -341,7 +337,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -360,20 +356,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -385,14 +410,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -405,19 +429,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -428,13 +456,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -593,7 +614,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -606,7 +626,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -639,10 +658,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1234,11 +1250,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -1347,7 +1362,7 @@ destination_type = delivery display_name = Chatbot # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -1358,10 +1373,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = No - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = No diff --git a/lxmf_cmd/lxmf_cmd.py b/lxmf_cmd/lxmf_cmd.py index 8ee092f..e619ddc 100755 --- a/lxmf_cmd/lxmf_cmd.py +++ b/lxmf_cmd/lxmf_cmd.py @@ -154,7 +154,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -170,15 +170,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -339,7 +335,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -358,20 +354,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -383,14 +408,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -403,19 +427,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -426,13 +454,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -591,7 +612,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -604,7 +624,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -637,10 +656,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1265,11 +1281,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -1368,7 +1383,7 @@ destination_type = delivery display_name = CMD # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -1379,10 +1394,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = No - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = No diff --git a/lxmf_distribution_group/lxmf_distribution_group.py b/lxmf_distribution_group/lxmf_distribution_group.py index 59aebe5..57933e5 100755 --- a/lxmf_distribution_group/lxmf_distribution_group.py +++ b/lxmf_distribution_group/lxmf_distribution_group.py @@ -163,7 +163,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -179,15 +179,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -348,7 +344,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -367,20 +363,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -392,14 +417,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -412,19 +436,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -435,13 +463,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -600,7 +621,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -613,7 +633,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -646,10 +665,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -2185,11 +2201,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -2286,7 +2301,6 @@ DEFAULT_CONFIG_OVERRIDE = '''# This is the user configuration file to override t [lxmf] display_name = Distribution Group propagation_node_auto = True -try_propagation_on_fail = Yes [telemetry] @@ -2352,7 +2366,7 @@ destination_type_conv = #4=Group, 6=Channel (Only for use with Communicator-Soft display_name = Distribution Group # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -2363,10 +2377,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = Yes - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = Yes diff --git a/lxmf_distribution_group_extended/lxmf_distribution_group_extended.py b/lxmf_distribution_group_extended/lxmf_distribution_group_extended.py index 25d6fb1..e951d14 100755 --- a/lxmf_distribution_group_extended/lxmf_distribution_group_extended.py +++ b/lxmf_distribution_group_extended/lxmf_distribution_group_extended.py @@ -165,7 +165,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -181,15 +181,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -350,7 +346,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -369,20 +365,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -394,14 +419,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -414,19 +438,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -437,13 +465,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -602,7 +623,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -615,7 +635,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -648,10 +667,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1120,7 +1136,7 @@ def lxmf_message_received_callback(message): fields = fields(fields) if CONFIG["statistic"].getboolean("enabled") and CONFIG["statistic"].getboolean("cluster"): - statistic("add", "cluster_in_" + message.desired_method_str) + statistic("add", "cluster_in_" + str(message.desired_method)) if fields["m_t"] == "message": for section in sections: @@ -1303,7 +1319,7 @@ def lxmf_message_received_callback(message): if CONFIG["statistic"].getboolean("enabled"): if CONFIG["statistic"].getboolean("interface"): - statistic("add", "interface_received_" + message.desired_method_str) + statistic("add", "interface_received_" + str(message.desired_method)) if CONFIG["statistic"].getboolean("user"): statistic("value_set", source_hash, "activity", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))) statistic("value_set", source_hash, "activity_receive", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))) @@ -1430,7 +1446,7 @@ def lxmf_message_received_callback(message): if CONFIG["statistic"].getboolean("enabled"): if CONFIG["statistic"].getboolean("cluster"): - statistic("add", "cluster_received_" + message.desired_method_str) + statistic("add", "cluster_received_" + str(message.desired_method)) if CONFIG["statistic"].getboolean("user"): statistic("add", source_hash) statistic("value_set", source_hash, "activity", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))) @@ -1539,7 +1555,7 @@ def lxmf_message_received_callback(message): if CONFIG["statistic"].getboolean("enabled"): if CONFIG["statistic"].getboolean("local"): - statistic("add", "local_received_" + message.desired_method_str) + statistic("add", "local_received_" + str(message.desired_method)) if CONFIG["statistic"].getboolean("user"): statistic("add", source_hash) statistic("value_set", source_hash, "activity", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))) @@ -1573,16 +1589,16 @@ def lxmf_message_received_callback(message): def lxmf_message_notification_success_callback(message): if CONFIG["statistic"].getboolean("enabled"): if message.app_data.startswith("cluster") and CONFIG["statistic"].getboolean("cluster"): - statistic("add", message.app_data + "_" + message.desired_method_str + "_success") + statistic("add", message.app_data + "_" + str(message.desired_method) + "_success") elif message.app_data.startswith("router") and CONFIG["statistic"].getboolean("router"): - statistic("add", message.app_data + "_" + message.desired_method_str + "_success") + statistic("add", message.app_data + "_" + str(message.desired_method) + "_success") elif message.app_data.startswith("local") and CONFIG["statistic"].getboolean("local"): - statistic("add", message.app_data + "_" + message.desired_method_str + "_success") + statistic("add", message.app_data + "_" + str(message.desired_method) + "_success") elif message.app_data.startswith("interface") and CONFIG["statistic"].getboolean("interface"): - statistic("add", message.app_data + "_" + message.desired_method_str + "_success") + statistic("add", message.app_data + "_" + str(message.desired_method) + "_success") if CONFIG["statistic"].getboolean("user"): - if message.desired_method_str == "direct": + if message.desired_method == LXMF.LXMessage.DIRECT: destination_hash = RNS.hexrep(message.destination_hash, False) statistic("value_set", destination_hash, "activity", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))) statistic("value_set", destination_hash, "activity_send", time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))) @@ -1593,13 +1609,13 @@ def lxmf_message_notification_success_callback(message): def lxmf_message_notification_failed_callback(message): if CONFIG["statistic"].getboolean("enabled"): if message.app_data.startswith("cluster") and CONFIG["statistic"].getboolean("cluster"): - statistic("add", message.app_data + "_" + message.desired_method_str + "_failed") + statistic("add", message.app_data + "_" + str(message.desired_method) + "_failed") elif message.app_data.startswith("router") and CONFIG["statistic"].getboolean("router"): - statistic("add", message.app_data + "_" + message.desired_method_str + "_failed") + statistic("add", message.app_data + "_" + str(message.desired_method) + "_failed") elif message.app_data.startswith("local") and CONFIG["statistic"].getboolean("local"): - statistic("add", message.app_data + "_" + message.desired_method_str + "_failed") + statistic("add", message.app_data + "_" + str(message.desired_method) + "_failed") elif message.app_data.startswith("interface") and CONFIG["statistic"].getboolean("interface"): - statistic("add", message.app_data + "_" + message.desired_method_str + "_failed") + statistic("add", message.app_data + "_" + str(message.desired_method) + "_failed") return @@ -4277,11 +4293,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -4436,10 +4451,6 @@ display_name = Distribution Group # Set propagation node automatically. propagation_node_auto = True -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = Yes - [telemetry] location_enabled = False @@ -4556,7 +4567,7 @@ destination_type_conv = #4=Group, 6=Channel (Only for use with Communicator-Soft display_name = Distribution Group # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -4567,10 +4578,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = Yes - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = Yes diff --git a/lxmf_distribution_group_minimal/lxmf_distribution_group_minimal.py b/lxmf_distribution_group_minimal/lxmf_distribution_group_minimal.py index 57e7958..eafe604 100755 --- a/lxmf_distribution_group_minimal/lxmf_distribution_group_minimal.py +++ b/lxmf_distribution_group_minimal/lxmf_distribution_group_minimal.py @@ -152,7 +152,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -168,15 +168,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -337,7 +333,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -356,20 +352,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -381,14 +406,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -401,19 +425,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -424,13 +452,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -589,7 +610,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -602,7 +622,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -635,10 +654,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1354,11 +1370,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -1439,7 +1454,6 @@ DEFAULT_CONFIG_OVERRIDE = '''# This is the user configuration file to override t [lxmf] display_name = Distribution Group propagation_node_auto = True -try_propagation_on_fail = Yes [telemetry] @@ -1482,7 +1496,7 @@ destination_type = delivery display_name = Distribution Group # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -1493,10 +1507,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = Yes - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = Yes diff --git a/lxmf_echo/lxmf_echo.py b/lxmf_echo/lxmf_echo.py index a6bf1c8..06fe4cc 100755 --- a/lxmf_echo/lxmf_echo.py +++ b/lxmf_echo/lxmf_echo.py @@ -151,7 +151,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -167,15 +167,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -336,7 +332,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -355,20 +351,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -380,14 +405,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -400,19 +424,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -423,13 +451,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -588,7 +609,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -601,7 +621,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -634,10 +653,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1375,11 +1391,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -1491,7 +1506,7 @@ destination_type = delivery display_name = Echo Test # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -1502,10 +1517,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = No - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = Yes diff --git a/lxmf_provisioning/lxmf_provisioning.py b/lxmf_provisioning/lxmf_provisioning.py index 873ccec..61273d1 100755 --- a/lxmf_provisioning/lxmf_provisioning.py +++ b/lxmf_provisioning/lxmf_provisioning.py @@ -170,7 +170,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -186,15 +186,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -355,7 +351,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -374,20 +370,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -399,14 +424,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -419,19 +443,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -442,13 +470,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -607,7 +628,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -620,7 +640,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -653,10 +672,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1521,11 +1537,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -1676,7 +1691,7 @@ destination_type_conv = 174 display_name = LXMF Provisioning Server # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -1687,10 +1702,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = Yes - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = Yes diff --git a/lxmf_terminal/lxmf_terminal.py b/lxmf_terminal/lxmf_terminal.py index f392bd3..1cac186 100755 --- a/lxmf_terminal/lxmf_terminal.py +++ b/lxmf_terminal/lxmf_terminal.py @@ -271,7 +271,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -287,15 +287,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -456,7 +452,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -475,20 +471,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -500,14 +525,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -520,19 +544,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -543,13 +571,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -708,7 +729,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -721,7 +741,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -754,10 +773,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1421,11 +1437,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) announce_data=announce_data, announce_hidden=CONFIG["lxmf"].getboolean("announce_hidden"), send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail"), announce_startup=CONFIG["lxmf"].getboolean("announce_startup"), announce_startup_delay=CONFIG["lxmf"]["announce_startup_delay"], announce_periodic=CONFIG["lxmf"].getboolean("announce_periodic"), @@ -1528,7 +1543,7 @@ destination_type = delivery display_name = CMD # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -1539,10 +1554,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = No - # The peer is announced at startup # to let other peers reach it immediately. announce_startup = No diff --git a/lxmf_test/lxmf_test.py b/lxmf_test/lxmf_test.py index 8bc143d..43b1a02 100755 --- a/lxmf_test/lxmf_test.py +++ b/lxmf_test/lxmf_test.py @@ -95,7 +95,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -111,15 +111,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -280,7 +276,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -299,20 +295,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -324,14 +349,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -344,19 +368,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -367,13 +395,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -532,7 +553,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -545,7 +565,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -578,10 +597,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) diff --git a/lxmf_welcome/lxmf_welcome.py b/lxmf_welcome/lxmf_welcome.py index aaf4cd3..201d949 100755 --- a/lxmf_welcome/lxmf_welcome.py +++ b/lxmf_welcome/lxmf_welcome.py @@ -151,7 +151,7 @@ class lxmf_connection: config_set_callback = None - def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, desired_method="direct", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, try_propagation_on_fail=False, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): + def __init__(self, storage_path=None, identity_file="identity", identity=None, destination_name="lxmf", destination_type="delivery", display_name="", announce_data=None, announce_hidden=False, send_delay=0, method="auto", propagation_node=None, propagation_node_auto=False, propagation_node_active=None, announce_startup=False, announce_startup_delay=0, announce_periodic=False, announce_periodic_interval=360, sync_startup=False, sync_startup_delay=0, sync_limit=8, sync_periodic=False, sync_periodic_interval=360): self.storage_path = storage_path self.identity_file = identity_file @@ -167,15 +167,11 @@ class lxmf_connection: self.announce_hidden = announce_hidden self.send_delay = int(send_delay) + self.method = method - if desired_method == "propagated" or desired_method == "PROPAGATED": - self.desired_method_direct = False - else: - self.desired_method_direct = True self.propagation_node = propagation_node self.propagation_node_auto = propagation_node_auto self.propagation_node_active = propagation_node_active - self.try_propagation_on_fail = try_propagation_on_fail self.announce_startup = announce_startup self.announce_startup_delay = int(announce_startup_delay) @@ -336,7 +332,7 @@ class lxmf_connection: return "" - def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None): + def send(self, destination, content="", title="", fields=None, timestamp=None, app_data="", destination_name=None, destination_type=None, method=None): if type(destination) is not bytes: if len(destination) == ((RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2)+2: destination = destination[1:-1] @@ -355,20 +351,49 @@ class lxmf_connection: destination_name = self.destination_name if destination_type == None: destination_type = self.destination_type + if method == None: + method = self.method destination_identity = RNS.Identity.recall(destination) destination = RNS.Destination(destination_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, destination_name, destination_type) - return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data) + return self.send_message(destination, self.destination, content, title, fields, timestamp, app_data, method) - def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data=""): + def send_message(self, destination, source, content="", title="", fields=None, timestamp=None, app_data="", method=None): if destination == self.destination: return None - if self.desired_method_direct: - desired_method = LXMF.LXMessage.DIRECT + if method.lower() == "auto": + opportunistic = True + propagation = False + propagation_on_fail = True + elif method.lower() == "opportunistic": + opportunistic = True + propagation = False + propagation_on_fail = False + elif method.lower() == "direct": + opportunistic = False + propagation = False + propagation_on_fail = False + elif method.lower() == "propagated": + opportunistic = False + propagation = True + propagation_on_fail = False + elif method.lower() == "command": + opportunistic = True + propagation = False + propagation_on_fail = False else: + opportunistic = True + propagation = False + propagation_on_fail = True + + if propagation: desired_method = LXMF.LXMessage.PROPAGATED + elif opportunistic and not self.message_router.delivery_link_available(destination.hash) and RNS.Identity.current_ratchet_id(destination.hash) != None: + desired_method = LXMF.LXMessage.OPPORTUNISTIC + else: + desired_method = LXMF.LXMessage.DIRECT message = LXMF.LXMessage(destination, source, content, title=title, desired_method=desired_method) @@ -380,14 +405,13 @@ class lxmf_connection: message.app_data = app_data - self.message_method(message) self.log_message(message, "LXMF - Message send") message.register_delivery_callback(self.message_notification) message.register_failed_callback(self.message_notification) if self.message_router.get_outbound_propagation_node() != None: - message.try_propagation_on_fail = self.try_propagation_on_fail + message.try_propagation_on_fail = propagation_on_fail try: self.message_router.handle_outbound(message) @@ -400,19 +424,23 @@ class lxmf_connection: def message_notification(self, message): - self.message_method(message) - if self.message_notification_callback is not None: self.message_notification_callback(message) if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail: - self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") - message.try_propagation_on_fail = None - message.delivery_attempts = 0 - del message.next_delivery_attempt - message.packed = None - message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_router.handle_outbound(message) + if hasattr(message, "stamp_generation_failed") and message.stamp_generation_failed == True: + self.log_message(message, "LXMF - Delivery receipt (failed)") + if self.message_notification_failed_callback is not None: + self.message_notification_failed_callback(message) + else: + self.log_message(message, "LXMF - Delivery receipt (failed) Retrying as propagated message") + message.try_propagation_on_fail = None + message.delivery_attempts = 0 + if hasattr(message, "next_delivery_attempt"): + del message.next_delivery_attempt + message.packed = None + message.desired_method = LXMF.LXMessage.PROPAGATED + self.message_router.handle_outbound(message) elif message.state == LXMF.LXMessage.FAILED: self.log_message(message, "LXMF - Delivery receipt (failed)") if self.message_notification_failed_callback is not None: @@ -423,13 +451,6 @@ class lxmf_connection: self.message_notification_success_callback(message) - def message_method(self, message): - if message.desired_method == LXMF.LXMessage.DIRECT: - message.desired_method_str = "direct" - elif message.desired_method == LXMF.LXMessage.PROPAGATED: - message.desired_method_str = "propagated" - - def announce(self, app_data=None, attached_interface=None, initial=False): announce_timer = None @@ -588,7 +609,6 @@ class lxmf_connection: message.desired_method = LXMF.LXMessage.DIRECT - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -601,7 +621,6 @@ class lxmf_connection: def process_lxmf_message_propagated(self, message): message.desired_method = LXMF.LXMessage.PROPAGATED - self.message_method(message) self.log_message(message, "LXMF - Message received") if self.message_received_callback is not None: @@ -634,10 +653,7 @@ class lxmf_connection: log("- Destination: " + RNS.prettyhexrep(message.destination_hash), LOG_DEBUG) log("- Signature: " + signature_string, LOG_DEBUG) log("- Attempts: " + str(message.delivery_attempts), LOG_DEBUG) - if hasattr(message, "desired_method_str"): - log("- Method: " + message.desired_method_str + " (" + str(message.desired_method) + ")", LOG_DEBUG) - else: - log("- Method: " + str(message.desired_method), LOG_DEBUG) + log("- Method: " + str(message.desired_method), LOG_DEBUG) if hasattr(message, "app_data"): log("- App Data: " + message.app_data, LOG_DEBUG) @@ -1245,11 +1261,10 @@ def setup(path=None, path_rns=None, path_log=None, loglevel=None, service=False) destination_name=CONFIG["lxmf"]["destination_name"], destination_type=CONFIG["lxmf"]["destination_type"], send_delay=CONFIG["lxmf"]["send_delay"], - desired_method=CONFIG["lxmf"]["desired_method"], + method=CONFIG["lxmf"]["method"], propagation_node=config_propagation_node, propagation_node_auto=CONFIG["lxmf"].getboolean("propagation_node_auto"), propagation_node_active=config_propagation_node_active, - try_propagation_on_fail=CONFIG["lxmf"].getboolean("try_propagation_on_fail") ) LXMF_CONNECTION.register_announce_callback(lxmf_announce_callback) @@ -1351,7 +1366,7 @@ destination_name = lxmf destination_type = delivery # Default send method. -desired_method = direct #direct/propagated +method = auto #auto/opportunistic/direct/propagated/command # Propagation node address/hash. propagation_node = @@ -1362,10 +1377,6 @@ propagation_node_auto = True # Current propagation node (Automatically set by the software). propagation_node_active = -# Try to deliver a message via the LXMF propagation network, -# if a direct delivery to the recipient is not possible. -try_propagation_on_fail = Yes - # Hop count filter. Allow only from certain min/max hops. hop_min = 0 hop_max = 0