From d3b0b90e185ffc151554bafb09b4deedea4b573b Mon Sep 17 00:00:00 2001 From: tapedeck Date: Fri, 15 May 2026 08:58:04 -0700 Subject: [PATCH 1/3] Refactor Reaction Grouping and Enhance Traceroute Responses --- mqttbridge/mqtt.py | 107 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 6 deletions(-) diff --git a/mqttbridge/mqtt.py b/mqttbridge/mqtt.py index e733cb3..5ad8262 100644 --- a/mqttbridge/mqtt.py +++ b/mqttbridge/mqtt.py @@ -225,6 +225,12 @@ async def setup_database(self): WHERE length(node_id_hex) < 9 """) + # Add discord_message_id to traceroute if it doesn't exist + try: + c.execute("ALTER TABLE traceroute ADD COLUMN discord_message_id INTEGER") + except sqlite3.OperationalError: + pass + conn.commit() except Exception as e: print(f"Error setting up database: {str(e)}") @@ -806,7 +812,7 @@ async def append_reaction_to_discord(self, mp, message_text, discord_msg_id): node_name = node_row[0] settings = await self.config.all() - reaction_str = f"{message_text} - [{node_name}]({settings['meshview_domain']}/packet/{mp.id})" + user_link = f"[{node_name}]({settings['meshview_domain']}/packet/{mp.id})" # Find existing Reactions field reactions_idx = -1 @@ -818,14 +824,28 @@ async def append_reaction_to_discord(self, mp, message_text, discord_msg_id): REACTIONS_FIELD_LIMIT = 1024 if reactions_idx >= 0: - # Append to existing current_value = embed.fields[reactions_idx].value - new_value = f"{current_value}\n{reaction_str}" + lines = current_value.split('\n') + + updated = False + for i, line in enumerate(lines): + if line.startswith(f"{message_text} - ") or line.startswith(f"{message_text}- "): + lines[i] = f"{line}, {user_link}" + updated = True + break + + if not updated: + lines.append(f"{message_text} - {user_link}") + + # Sort lines natively + lines.sort() + new_value = '\n'.join(lines) + if len(new_value) > REACTIONS_FIELD_LIMIT: new_value = new_value[:REACTIONS_FIELD_LIMIT - 3] + "..." embed.set_field_at(reactions_idx, name="Reactions", value=new_value, inline=False) else: - # Add new field + reaction_str = f"{message_text} - {user_link}" if len(reaction_str) > REACTIONS_FIELD_LIMIT: reaction_str = reaction_str[:REACTIONS_FIELD_LIMIT - 3] + "..." embed.add_field(name="Reactions", value=reaction_str, inline=False) @@ -1195,12 +1215,87 @@ async def process_traceroute(self, mp, se): if self.traceroute_channel: if "owner" in sender_info and sender_info['owner'] and sender_info['owner']['notifications']: - await self.traceroute_channel.send(f"<@{sender_info['owner']['discord_id']}>", embed=embed) + message = await self.traceroute_channel.send(f"<@{sender_info['owner']['discord_id']}>", embed=embed) else: - await self.traceroute_channel.send(embed=embed) + message = await self.traceroute_channel.send(embed=embed) + + with self.get_db() as conn: + c = conn.cursor() + c.execute(""" + UPDATE traceroute + SET discord_message_id = ? + WHERE trace_id = ? AND from_id = ? AND to_id = ? + """, (message.id, mp.id, getattr(mp, "from", 0), getattr(mp, "to", 0))) + conn.commit() else: return + elif trace_direction == "REPLY": + original_trace_id = mp.decoded.request_id + discord_msg_id = None + with self.get_db() as conn: + c = conn.cursor() + c.execute("SELECT discord_message_id FROM traceroute WHERE trace_id = ?", (original_trace_id,)) + row = c.fetchone() + if row and row[0]: + discord_msg_id = row[0] + + # Parse RouteDiscovery + route_discovery = mesh_pb2.RouteDiscovery() + route_names = [] + try: + route_discovery.ParseFromString(mp.decoded.payload) + with self.get_db() as conn: + c = conn.cursor() + for hop_num in route_discovery.route: + hop_str = str(hop_num) + c.execute("SELECT short_name, node_id_hex FROM nodes WHERE node_id = ?", (hop_str,)) + node_row = c.fetchone() + if node_row and node_row[0]: + route_names.append(node_row[0]) + elif node_row and node_row[1]: + route_names.append(node_row[1]) + else: + route_names.append(f"!{format(hop_num, '08x')}") + except Exception as e: + print(f"Error parsing RouteDiscovery: {e}") + + route_display = " → ".join(route_names) if route_names else "Unknown" + + if discord_msg_id and self.traceroute_channel: + try: + original_msg = await self.traceroute_channel.fetch_message(discord_msg_id) + if original_msg.embeds: + embed = original_msg.embeds[0] + # Update Description + desc = embed.description + if desc: + desc = desc.replace("Direction: SEND", "Direction: REPLY (Complete)") + else: + desc = "Direction: REPLY (Complete)" + embed.description = desc + + embed.add_field(name="Route Taken", value=route_display, inline=False) + await original_msg.edit(embed=embed) + # Flag that we successfully edited the message + else: + discord_msg_id = None # Fallback to new message + except (discord.NotFound, discord.HTTPException): + # Fallback if message not found + discord_msg_id = None + + # If we couldn't find/edit the message, post a new one + if not discord_msg_id and self.traceroute_channel: + settings = await self.config.all() + embed = discord.Embed( + title=f"Traceroute Reply Received", + description=f"Response to trace ID [{original_trace_id}]({settings['meshview_domain']}/packet/{original_trace_id})", + color=discord.Color.purple(), + timestamp=datetime.now() + ) + embed.add_field(name="Route Taken", value=route_display, inline=False) + await self.traceroute_channel.send(embed=embed) + except Exception as e: print(f"Error processing traceroute: {str(e)}") From 0eea1ee459134a2a3aaa50369cb170ef7a3f3826 Mon Sep 17 00:00:00 2001 From: tapedeck Date: Fri, 15 May 2026 14:14:41 -0700 Subject: [PATCH 2/3] fix: increase message history retention to 10k for late reactions --- mqttbridge/mqtt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mqttbridge/mqtt.py b/mqttbridge/mqtt.py index 5ad8262..e9f2764 100644 --- a/mqttbridge/mqtt.py +++ b/mqttbridge/mqtt.py @@ -1419,12 +1419,12 @@ async def store_message_history(self, mp, se, message_text): timestamp )) - # Prune old messages if we have too many (keep last 50) + # Prune old messages if we have too many (keep last 10000) c.execute("SELECT COUNT(*) FROM message_history") count = c.fetchone()[0] - if count > 50: - # Delete oldest messages to keep only the newest 45 + if count > 10000: + # Delete oldest messages to keep only the newest 9500 c.execute(""" DELETE FROM message_history WHERE timestamp IN ( @@ -1432,7 +1432,7 @@ async def store_message_history(self, mp, se, message_text): ORDER BY timestamp ASC LIMIT ? ) - """, (count - 45,)) + """, (count - 9500,)) conn.commit() From 2030f08477fe2249088af4213134efd73de757e5 Mon Sep 17 00:00:00 2001 From: tapedeck Date: Fri, 15 May 2026 16:08:49 -0700 Subject: [PATCH 3/3] fix(traceroute): strip from/to from db matching and make discord embed edit safer --- mqttbridge/mqtt.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/mqttbridge/mqtt.py b/mqttbridge/mqtt.py index e9f2764..54255a1 100644 --- a/mqttbridge/mqtt.py +++ b/mqttbridge/mqtt.py @@ -1224,8 +1224,8 @@ async def process_traceroute(self, mp, se): c.execute(""" UPDATE traceroute SET discord_message_id = ? - WHERE trace_id = ? AND from_id = ? AND to_id = ? - """, (message.id, mp.id, getattr(mp, "from", 0), getattr(mp, "to", 0))) + WHERE trace_id = ? + """, (message.id, mp.id)) conn.commit() else: return @@ -1238,7 +1238,7 @@ async def process_traceroute(self, mp, se): c.execute("SELECT discord_message_id FROM traceroute WHERE trace_id = ?", (original_trace_id,)) row = c.fetchone() if row and row[0]: - discord_msg_id = row[0] + discord_msg_id = int(row[0]) # Parse RouteDiscovery route_discovery = mesh_pb2.RouteDiscovery() @@ -1266,22 +1266,25 @@ async def process_traceroute(self, mp, se): try: original_msg = await self.traceroute_channel.fetch_message(discord_msg_id) if original_msg.embeds: - embed = original_msg.embeds[0] + # Create a new embed from the original to ensure safe editing + new_embed = discord.Embed.from_dict(original_msg.embeds[0].to_dict()) + # Update Description - desc = embed.description + desc = new_embed.description if desc: desc = desc.replace("Direction: SEND", "Direction: REPLY (Complete)") else: desc = "Direction: REPLY (Complete)" - embed.description = desc + new_embed.description = desc - embed.add_field(name="Route Taken", value=route_display, inline=False) - await original_msg.edit(embed=embed) + new_embed.add_field(name="Route Taken", value=route_display, inline=False) + await original_msg.edit(embed=new_embed) # Flag that we successfully edited the message else: discord_msg_id = None # Fallback to new message - except (discord.NotFound, discord.HTTPException): - # Fallback if message not found + except (discord.NotFound, discord.HTTPException) as e: + print(f"Error editing original traceroute message: {e}") + # Fallback if message not found or edit fails discord_msg_id = None # If we couldn't find/edit the message, post a new one