added a random id to each recived message to make duplicate detection easier, also added a delete message endpoint

This commit is contained in:
Andrea Santaniello 2024-05-08 17:39:51 +02:00
parent 70f0599c63
commit 6c8c969b67
2 changed files with 66 additions and 10 deletions

View File

@ -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/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/nodes`: GET endpoint to list all seen nodes.
- `/api/mesh/status`: GET endpoint to check connection status. - `/api/mesh/status`: GET endpoint to check connection status.

View File

@ -6,6 +6,8 @@ import meshtastic
import meshtastic.tcp_interface import meshtastic.tcp_interface
import json import json
import datetime import datetime
import hashlib
import random
class MeshAPI(object): class MeshAPI(object):
def __init__(self, hostname='meshtastic.local'): def __init__(self, hostname='meshtastic.local'):
@ -17,12 +19,12 @@ class MeshAPI(object):
""" """
self.hostname = hostname self.hostname = hostname
self.iface = None self.iface = None
self.device_telemetry_cache = {} self.device_telemetry_cache = {} # Cache to store device telemetry data
self.environment_telemetry_cache = {} self.environment_telemetry_cache = {} # Cache to store environment telemetry data
self.message_cache = [] self.message_cache = {} # Cache to store messages
self.seen_nodes = {} self.seen_nodes = {} # Dictionary to store information about seen nodes
self.connection_attempts = 0 self.connection_attempts = 0 # Number of connection attempts made
self.last_connection_time = None self.last_connection_time = None # Time of the last successful connection
self.connection_thread = threading.Thread(target=self.connect_to_mesh, daemon=True) self.connection_thread = threading.Thread(target=self.connect_to_mesh, daemon=True)
def on_receive(self, packet, interface): def on_receive(self, packet, interface):
@ -64,7 +66,8 @@ class MeshAPI(object):
if 'decoded' in packet and 'text' in packet['decoded']: if 'decoded' in packet and 'text' in packet['decoded']:
node_id = packet['from'] node_id = packet['from']
message_data = packet['decoded']['text'] 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: if len(self.message_cache) > 100:
self.message_cache.pop(0) self.message_cache.pop(0)
@ -78,7 +81,6 @@ class MeshAPI(object):
def on_connection(self, interface, topic=pub.AUTO_TOPIC): def on_connection(self, interface, topic=pub.AUTO_TOPIC):
""" """
Callback function called when we (re)connect to the radio. 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.last_connection_time = time.time()
self.connection_attempts += 1 self.connection_attempts += 1
@ -87,7 +89,7 @@ class MeshAPI(object):
@cherrypy.expose @cherrypy.expose
def index(self): def index(self):
""" """
Exposed endpoint for the poors man swagger! Exposed endpoint for the index page.
""" """
html = """ html = """
<html> <html>
@ -140,6 +142,16 @@ class MeshAPI(object):
<li> <li>
<a href="/api/mesh/get_last_messages">/api/mesh/get_last_messages</a>: GET endpoint to retrieve the last cached messages <a href="/api/mesh/get_last_messages">/api/mesh/get_last_messages</a>: GET endpoint to retrieve the last cached messages
</li> </li>
<li>
<a href="/api/mesh/delete_message">/api/mesh/delete_message</a>: POST endpoint to delete a message from the cache
<ul>
<li>Parameters:
<ul>
<li><b>message_id</b> (str): The ID of the message to be deleted.</li>
</ul>
</li>
</ul>
</li>
<li> <li>
<a href="/api/mesh/nodes">/api/mesh/nodes</a>: GET endpoint to list all seen nodes <a href="/api/mesh/nodes">/api/mesh/nodes</a>: GET endpoint to list all seen nodes
</li> </li>
@ -212,6 +224,30 @@ class MeshAPI(object):
""" """
return self.message_cache 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.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
def nodes(self): def nodes(self):
@ -244,6 +280,22 @@ class MeshAPI(object):
print(f"Error: Could not connect to {self.hostname} {ex}") print(f"Error: Could not connect to {self.hostname} {ex}")
time.sleep(1) # Wait for 1 second before attempting to reconnect 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): def start(self):
""" """
Function to start the connection thread. Function to start the connection thread.