diff --git a/LXMF/LXMF.py b/LXMF/LXMF.py index ede9c3a..cdb90a5 100644 --- a/LXMF/LXMF.py +++ b/LXMF/LXMF.py @@ -103,6 +103,10 @@ PN_META_AUTH_BAND = 0x04 PN_META_UTIL_PRESSURE = 0x05 PN_META_CUSTOM = 0xFF +# Supported functionality codes for signalling +# feature and capability support. +SF_COMPRESSION = 0x00 + ########################################################## # The following helper functions makes it easier to # # handle and operate on LXMF data in client programs # @@ -147,6 +151,21 @@ def stamp_cost_from_app_data(app_data=None): # Original announce format else: return None +def compression_support_from_app_data(app_data=None): + if app_data == None or app_data == b"": return None + else: + # Version 0.5.0+ announce format + if (app_data[0] >= 0x90 and app_data[0] <= 0x9f) or app_data[0] == 0xdc: + peer_data = msgpack.unpackb(app_data) + if type(peer_data) == list: + if len(peer_data) < 3: return True + else: + if not type(peer_data[2]) == list: return True + else: return SF_COMPRESSION in peer_data[2] + + # Original announce format + else: return True + def pn_name_from_app_data(app_data=None): if app_data == None: return None else: diff --git a/LXMF/LXMRouter.py b/LXMF/LXMRouter.py index cccd1e4..fb19ad8 100644 --- a/LXMF/LXMRouter.py +++ b/LXMF/LXMRouter.py @@ -16,6 +16,7 @@ import RNS.vendor.umsgpack as msgpack from .LXMF import APP_NAME from .LXMF import FIELD_TICKET from .LXMF import PN_META_NAME +from .LXMF import SF_COMPRESSION from .LXMF import pn_announce_data_is_valid from .LXMPeer import LXMPeer @@ -995,6 +996,7 @@ class LXMRouter: if delivery_destination.stamp_cost > 0 and delivery_destination.stamp_cost < 255: stamp_cost = delivery_destination.stamp_cost + supported_functionality = [SF_COMPRESSION] peer_data = [display_name, stamp_cost] return msgpack.packb(peer_data) diff --git a/LXMF/LXMessage.py b/LXMF/LXMessage.py index baf951a..37186b0 100644 --- a/LXMF/LXMessage.py +++ b/LXMF/LXMessage.py @@ -7,7 +7,7 @@ import base64 import multiprocessing import LXMF.LXStamper as LXStamper -from .LXMF import APP_NAME +from .LXMF import APP_NAME, compression_support_from_app_data class LXMessage: @@ -113,35 +113,26 @@ class LXMessage: def __init__(self, destination, source, content = "", title = "", fields = None, desired_method = None, destination_hash = None, source_hash = None, stamp_cost=None, include_ticket=False): if isinstance(destination, RNS.Destination) or destination == None: - self.__destination = destination - if destination != None: - self.destination_hash = destination.hash - else: - self.destination_hash = destination_hash - else: - raise ValueError("LXMessage initialised with invalid destination") + self.__destination = destination + if destination != None: self.destination_hash = destination.hash + else: self.destination_hash = destination_hash + + else: raise ValueError("LXMessage initialised with invalid destination") if isinstance(source, RNS.Destination) or source == None: - self.__source = source - if source != None: - self.source_hash = source.hash - else: - self.source_hash = source_hash - else: - raise ValueError("LXMessage initialised with invalid source") + self.__source = source + if source != None: self.source_hash = source.hash + else: self.source_hash = source_hash + + else: raise ValueError("LXMessage initialised with invalid source") - if title == None: - title = "" + if title == None: title = "" - if type(title) == bytes: - self.set_title_from_bytes(title) - else: - self.set_title_from_string(title) + if type(title) == bytes: self.set_title_from_bytes(title) + else: self.set_title_from_string(title) - if type(content) == bytes: - self.set_content_from_bytes(content) - else: - self.set_content_from_string(content) + if type(content) == bytes: self.set_content_from_bytes(content) + else: self.set_content_from_string(content) self.set_fields(fields) @@ -151,6 +142,7 @@ class LXMessage: self.hash = None self.transient_id = None self.packed = None + self.auto_compress = True self.state = LXMessage.GENERATING self.method = LXMessage.UNKNOWN self.progress = 0.0 @@ -467,6 +459,7 @@ class LXMessage: def send(self): self.determine_transport_encryption() + self.determine_compression_support() if self.method == LXMessage.OPPORTUNISTIC: lxm_packet = self.__as_packet() @@ -511,6 +504,15 @@ class LXMessage: self.resource_representation = self.__as_resource() self.progress = 0.10 + def determine_compression_support(self): + app_data = RNS.Identity.recall_app_data(self.destination_hash) + if app_data: self.auto_compress = compression_support_from_app_data(app_data) + else: self.auto_compress = True + + ###### TODO: Remove debug logging + if app_data: RNS.log(f"Set compression support from app data to: {self.auto_compress}", RNS.LOG_DEBUG) + else: RNS.log(f"Defaulting compression support to {self.auto_compress}", RNS.LOG_DEBUG) + ###### def determine_transport_encryption(self): # TODO: These descriptions are old and outdated. @@ -646,7 +648,7 @@ class LXMessage: raise ConnectionError("Tried to synthesize resource for LXMF message on a link that was not active") if self.method == LXMessage.DIRECT: - return RNS.Resource(self.packed, self.__delivery_destination, callback = self.__resource_concluded, progress_callback = self.__update_transfer_progress) + return RNS.Resource(self.packed, self.__delivery_destination, callback = self.__resource_concluded, progress_callback = self.__update_transfer_progress, auto_compress=self.auto_compress) elif self.method == LXMessage.PROPAGATED: return RNS.Resource(self.propagation_packed, self.__delivery_destination, callback = self.__propagation_resource_concluded, progress_callback = self.__update_transfer_progress) else: