From 6c8c969b677bb013a49eef774ebc5f9b70886976 Mon Sep 17 00:00:00 2001 From: Andrea Santaniello Date: Wed, 8 May 2024 17:39:51 +0200 Subject: [PATCH] added a random id to each recived message to make duplicate detection easier, also added a delete message endpoint --- README.md | 4 +++ meshttpd.py | 72 +++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3ed50eb..d180c95 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,10 @@ This will start the server locally. To expose it to the internet, it's recommend - `/api/mesh/get_last_messages`: GET endpoint to retrieve the last cached messages. +- `/api/mesh/delete_message`: POST endpoint to delete a message from the local cache. + - Parameters: + - `message_id` (str): The messageid to be deleted. + - `/api/mesh/nodes`: GET endpoint to list all seen nodes. - `/api/mesh/status`: GET endpoint to check connection status. diff --git a/meshttpd.py b/meshttpd.py index 3cea511..70e7488 100644 --- a/meshttpd.py +++ b/meshttpd.py @@ -6,6 +6,8 @@ import meshtastic import meshtastic.tcp_interface import json import datetime +import hashlib +import random class MeshAPI(object): def __init__(self, hostname='meshtastic.local'): @@ -17,12 +19,12 @@ class MeshAPI(object): """ self.hostname = hostname self.iface = None - self.device_telemetry_cache = {} - self.environment_telemetry_cache = {} - self.message_cache = [] - self.seen_nodes = {} - self.connection_attempts = 0 - self.last_connection_time = None + self.device_telemetry_cache = {} # Cache to store device telemetry data + self.environment_telemetry_cache = {} # Cache to store environment telemetry data + self.message_cache = {} # Cache to store messages + self.seen_nodes = {} # Dictionary to store information about seen nodes + self.connection_attempts = 0 # Number of connection attempts made + self.last_connection_time = None # Time of the last successful connection self.connection_thread = threading.Thread(target=self.connect_to_mesh, daemon=True) def on_receive(self, packet, interface): @@ -64,7 +66,8 @@ class MeshAPI(object): if 'decoded' in packet and 'text' in packet['decoded']: node_id = packet['from'] message_data = packet['decoded']['text'] - self.message_cache.append({"node_id": node_id, "message": message_data}) + internal_message_id = self.generate_internal_message_id(node_id, message_data) + self.message_cache[internal_message_id] = {"node_id": node_id, "message": message_data} if len(self.message_cache) > 100: self.message_cache.pop(0) @@ -78,7 +81,6 @@ class MeshAPI(object): def on_connection(self, interface, topic=pub.AUTO_TOPIC): """ Callback function called when we (re)connect to the radio. - If you have poor wifi coverage like in my case this is essential. """ self.last_connection_time = time.time() self.connection_attempts += 1 @@ -87,7 +89,7 @@ class MeshAPI(object): @cherrypy.expose def index(self): """ - Exposed endpoint for the poors man swagger! + Exposed endpoint for the index page. """ html = """ @@ -140,6 +142,16 @@ class MeshAPI(object):
  • /api/mesh/get_last_messages: GET endpoint to retrieve the last cached messages
  • +
  • + /api/mesh/delete_message: POST endpoint to delete a message from the cache + +
  • /api/mesh/nodes: GET endpoint to list all seen nodes
  • @@ -147,7 +159,7 @@ class MeshAPI(object): /api/mesh/status: GET endpoint to check connection status -

    Made by luhf for Monocul.us Mesh

    +

    Made by luhf for Monocul.us Mesh

    """ @@ -212,6 +224,30 @@ class MeshAPI(object): """ return self.message_cache + @cherrypy.expose + @cherrypy.tools.json_out() + def delete_message(self, message_id=None): + """ + Exposed endpoint for deleting a message from the cache. + + Args: + message_id (str): The ID of the message to be deleted. + + Returns: + dict: A JSON object containing the status of the operation. + + Raises: + 404 (Missing parameters): If the `message_id` parameter is missing. + 400 (Invalid message ID): If the specified message ID is invalid. + """ + if message_id is None: + cherrypy.response.status = 404 + return {"error": "Missing parameters: message_id"} + if message_id not in self.message_cache: + raise cherrypy.HTTPError(400, "Invalid message ID") + del self.message_cache[message_id] + return {"status": "success", "message": "Message deleted successfully"} + @cherrypy.expose @cherrypy.tools.json_out() def nodes(self): @@ -244,6 +280,22 @@ class MeshAPI(object): print(f"Error: Could not connect to {self.hostname} {ex}") time.sleep(1) # Wait for 1 second before attempting to reconnect + def generate_internal_message_id(self, node_id, message): + """ + Function to generate an internal message ID using MD5 hashing of random data, node ID, and message. + + Args: + node_id (str): The ID of the node. + message (str): The message. + + Returns: + str: The generated internal message ID. + """ + random_data = str(random.random()).encode() + hash_input = random_data + node_id.encode() + message.encode() + hash_object = hashlib.md5(hash_input) + return hash_object.hexdigest()[:10] + def start(self): """ Function to start the connection thread.