diff --git a/sbapp/sideband/core.py b/sbapp/sideband/core.py index e0753fe..85134c9 100644 --- a/sbapp/sideband/core.py +++ b/sbapp/sideband/core.py @@ -45,7 +45,7 @@ class PropagationNodeDetector(): aspect_filter = "lxmf.propagation" - def received_announce(self, destination_hash, announced_identity, app_data): + def received_announce(self, destination_hash, announced_identity, app_data, announce_packet_hash): try: if app_data != None and len(app_data) > 0: if pn_announce_data_is_valid(app_data): @@ -64,8 +64,12 @@ class PropagationNodeDetector(): # age = 0 pass + link_stats = {"rssi": self.reticulum.get_packet_rssi(announce_packet_hash), + "snr": self.reticulum.get_packet_snr(announce_packet_hash), + "q": self.reticulum.get_packet_q(announce_packet_hash)} + RNS.log("Detected active propagation node "+RNS.prettyhexrep(destination_hash)+" emission "+str(age)+" seconds ago, "+str(hops)+" hops away") - self.owner.log_announce(destination_hash, app_data, dest_type=PropagationNodeDetector.aspect_filter) + self.owner.log_announce(destination_hash, app_data, dest_type=PropagationNodeDetector.aspect_filter, link_stats=link_stats) if self.owner.config["lxmf_propagation_node"] == None: if self.owner.active_propagation_node == None: @@ -114,10 +118,14 @@ class SidebandCore(): LOG_DEQUE_MAXLEN = 128 aspect_filter = "lxmf.delivery" - def received_announce(self, destination_hash, announced_identity, app_data): + def received_announce(self, destination_hash, announced_identity, app_data, announce_packet_hash): # Add the announce to the directory announce # stream logger + link_stats = {"rssi": self.reticulum.get_packet_rssi(announce_packet_hash), + "snr": self.reticulum.get_packet_snr(announce_packet_hash), + "q": self.reticulum.get_packet_q(announce_packet_hash)} + # This reformats the new v0.5.0 announce data back to the expected format # for Sidebands database and other handling functions. dn = LXMF.display_name_from_app_data(app_data) @@ -126,7 +134,7 @@ class SidebandCore(): if dn != None: app_data = dn.encode("utf-8") - self.log_announce(destination_hash, app_data, dest_type=SidebandCore.aspect_filter, stamp_cost=sc) + self.log_announce(destination_hash, app_data, dest_type=SidebandCore.aspect_filter, stamp_cost=sc, link_stats=link_stats) def __init__(self, owner_app, config_path = None, is_service=False, is_client=False, android_app_dir=None, verbose=False, owner_service=None, service_context=None, is_daemon=False, load_config_only=False): self.is_service = is_service @@ -961,14 +969,14 @@ class SidebandCore(): else: plyer.notification.notify(title, content, app_icon=self.icon_32) - def log_announce(self, dest, app_data, dest_type, stamp_cost=None): + def log_announce(self, dest, app_data, dest_type, stamp_cost=None, link_stats=None): try: if app_data == None: app_data = b"" if type(app_data) != bytes: app_data = msgpack.packb([app_data, stamp_cost]) RNS.log("Received "+str(dest_type)+" announce for "+RNS.prettyhexrep(dest)+" with data: "+str(app_data), RNS.LOG_DEBUG) - self._db_save_announce(dest, app_data, dest_type) + self._db_save_announce(dest, app_data, dest_type, link_stats) self.setstate("app.flags.new_announces", True) except Exception as e: @@ -1980,10 +1988,10 @@ class SidebandCore(): # TODO: Remove this again at some point in the future db = self.__db_connect() dbc = db.cursor() - dbc.execute("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'lxm' AND sql LIKE '%extra%'") + dbc.execute("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'announce' AND sql LIKE '%extra%'") result = dbc.fetchall() if len(result) == 0: - dbc.execute("ALTER TABLE lxm ADD COLUMN extra BLOB") + dbc.execute("ALTER TABLE announce ADD COLUMN extra BLOB") db.commit() def _db_initstate(self): @@ -2540,8 +2548,16 @@ class SidebandCore(): for entry in result: try: if not entry[2] in added_dests: - app_data = entry[3] + app_data = entry[3] dest_type = entry[4] + if entry[5] != None: + try: + extras = msgpack.unpackb(entry[5]) + except Exception as e: + RNS.log(f"Error while unpacking extras from announce: {e}", RNS.LOG_ERROR) + extras = None + else: + extras = None if dest_type == "lxmf.delivery": announced_name = LXMF.display_name_from_app_data(app_data) announced_cost = self.message_router.get_outbound_stamp_cost(entry[2]) @@ -2549,11 +2565,12 @@ class SidebandCore(): announced_name = None announced_cost = None announce = { - "dest": entry[2], - "name": announced_name, - "cost": announced_cost, - "time": entry[1], - "type": dest_type + "dest" : entry[2], + "name" : announced_name, + "cost" : announced_cost, + "time" : entry[1], + "type" : dest_type, + "extras": extras, } added_dests.append(entry[2]) announces.append(announce) @@ -2967,7 +2984,7 @@ class SidebandCore(): self.__event_conversation_changed(context_dest) - def _db_save_announce(self, destination_hash, app_data, dest_type="lxmf.delivery"): + def _db_save_announce(self, destination_hash, app_data, dest_type="lxmf.delivery", link_stats = None): with self.db_lock: db = self.__db_connect() dbc = db.cursor() @@ -2981,14 +2998,16 @@ class SidebandCore(): now = time.time() hash_material = str(time).encode("utf-8")+destination_hash+app_data+dest_type.encode("utf-8") announce_hash = RNS.Identity.full_hash(hash_material) + extras = msgpack.packb({"link_stats": link_stats}) - query = "INSERT INTO announce (id, received, source, data, dest_type) values (?, ?, ?, ?, ?)" + query = "INSERT INTO announce (id, received, source, data, dest_type, extra) values (?, ?, ?, ?, ?, ?)" data = ( announce_hash, now, destination_hash, app_data, dest_type, + extras, ) dbc.execute(query, data) diff --git a/sbapp/ui/announces.py b/sbapp/ui/announces.py index 5e58dbb..be88712 100644 --- a/sbapp/ui/announces.py +++ b/sbapp/ui/announces.py @@ -18,9 +18,9 @@ from kivy.lang.builder import Builder from kivy.utils import escape_markup if RNS.vendor.platformutils.get_platform() == "android": - from ui.helpers import multilingual_markup + from ui.helpers import multilingual_markup, sig_icon_for_q else: - from .helpers import multilingual_markup + from .helpers import multilingual_markup, sig_icon_for_q if RNS.vendor.platformutils.get_platform() == "android": from ui.helpers import ts_format @@ -92,6 +92,25 @@ class Announces(): a_name = announce["name"] a_cost = announce["cost"] dest_type = announce["type"] + a_rssi = None + a_snr = None + a_q = None + + link_extras_str = "" + link_extras_full = "" + if "extras" in announce and announce["extras"] != None: + extras = announce["extras"] + RNS.log("Announce has extras: "+str(announce["extras"])) + if "link_stats" in extras: + link_stats = extras["link_stats"] + if "rssi" in link_stats and "snr" in link_stats and "q" in link_stats: + a_rssi = link_stats["rssi"] + a_snr = link_stats["snr"] + a_q = link_stats["q"] + link_extras_str = f" ([b]RSSI[/b] {a_rssi} [b]SNR[/b] {a_snr})" + link_extras_full = f"\n[b]Link Quality[/b] {a_q}%[/b]\n[b]RSSI[/b] {a_rssi}\n[b]SNR[/b] {a_snr}" + + sig_icon = multilingual_markup(sig_icon_for_q(a_q).encode("utf-8")).decode("utf-8") if not context_dest in self.added_item_dests: if self.app.sideband.is_trusted(context_dest): @@ -99,16 +118,16 @@ class Announces(): else: trust_icon = "account-question" - def gen_info(ts, dest, name, cost, dtype): + def gen_info(ts, dest, name, cost, dtype, link_extras): name = multilingual_markup(escape_markup(str(name)).encode("utf-8")).decode("utf-8") cost = str(cost) def x(sender): yes_button = MDRectangleFlatButton(text="OK",font_size=dp(18)) if dtype == "lxmf.delivery": - ad_text = "[size=22dp]LXMF Peer[/size]\n\n[b]Received[/b] "+ts+"\n[b]Address[/b] "+RNS.prettyhexrep(dest)+"\n[b]Name[/b] "+name+"\n[b]Stamp Cost[/b] "+cost + ad_text = "[size=22dp]LXMF Peer[/size]\n\n[b]Received[/b] "+ts+"\n[b]Address[/b] "+RNS.prettyhexrep(dest)+"\n[b]Name[/b] "+name+"\n[b]Stamp Cost[/b] "+cost+link_extras if dtype == "lxmf.propagation": - ad_text = "[size=22dp]LXMF Propagation Node[/size]\n\n[b]Received[/b] "+ts+"\n[b]Address[/b] "+RNS.prettyhexrep(dest) + ad_text = "[size=22dp]LXMF Propagation Node[/size]\n\n[b]Received[/b] "+ts+"\n[b]Address[/b] "+RNS.prettyhexrep(dest)+link_extras dialog = MDDialog( text=ad_text, @@ -123,7 +142,8 @@ class Announces(): dialog.open() return x - time_string = time.strftime(ts_format, time.localtime(ts)) + time_string = sig_icon + " " + time.strftime(ts_format, time.localtime(ts)) + link_extras_str + time_string_plain = time.strftime(ts_format, time.localtime(ts)) if dest_type == "lxmf.delivery": disp_name = multilingual_markup(escape_markup(str(self.app.sideband.peer_display_name(context_dest))).encode("utf-8")).decode("utf-8") @@ -137,7 +157,7 @@ class Announces(): disp_name = "Unknown Announce" iconl = IconLeftWidget(icon="progress-question") - item = TwoLineAvatarIconListItem(text=time_string, secondary_text=disp_name, on_release=gen_info(time_string, context_dest, a_name, a_cost, dest_type)) + item = TwoLineAvatarIconListItem(text=time_string, secondary_text=disp_name, on_release=gen_info(time_string_plain, context_dest, a_name, a_cost, dest_type, link_extras_full)) item.add_widget(iconl) item.sb_uid = context_dest item.ts = ts diff --git a/sbapp/ui/helpers.py b/sbapp/ui/helpers.py index c02a2f5..80d2971 100644 --- a/sbapp/ui/helpers.py +++ b/sbapp/ui/helpers.py @@ -111,6 +111,20 @@ def multilingual_markup(data): return do.encode("utf-8") +def sig_icon_for_q(q): + if q == None: + return "󰴽" + elif q > 90: + return "󰣺" + elif q > 70: + return "󰣸" + elif q > 50: + return "󰣶" + elif q > 30: + return "󰣴" + elif q > 10: + return "󰣾" + persistent_fonts = ["nf", "term"] nf_mapped = "nf"