Refactor: Adjust formatting and structure in database.py and meshchat.py

- Improved readability by restructuring function arguments and parameters across multiple files.
- Enhanced consistency in the formatting of method signatures and exception handling.
- Minor adjustments to comments for clarity and alignment with code style.
This commit is contained in:
2025-11-30 22:38:07 -06:00
parent ba47e16b75
commit 19854e59da
5 changed files with 187 additions and 91 deletions

View File

@@ -17,7 +17,9 @@ def migrate(current_version):
if current_version < 2: if current_version < 2:
migrate_database( migrate_database(
migrator.add_column( migrator.add_column(
"lxmf_messages", "delivery_attempts", LxmfMessage.delivery_attempts, "lxmf_messages",
"delivery_attempts",
LxmfMessage.delivery_attempts,
), ),
migrator.add_column( migrator.add_column(
"lxmf_messages", "lxmf_messages",
@@ -85,7 +87,7 @@ class Announce(BaseModel):
identity_hash = CharField( # noqa: F405 identity_hash = CharField( # noqa: F405
index=True, index=True,
) # identity hash that announced the destination ) # identity hash that announced the destination
identity_public_key = ( # noqa: F405 identity_public_key = (
CharField() # noqa: F405 CharField() # noqa: F405
) # base64 encoded public key, incase we want to recreate the identity manually ) # base64 encoded public key, incase we want to recreate the identity manually
app_data = TextField(null=True) # noqa: F405 # base64 encoded app data bytes app_data = TextField(null=True) # noqa: F405 # base64 encoded app data bytes
@@ -133,7 +135,7 @@ class LxmfMessage(BaseModel):
hash = CharField(unique=True) # noqa: F405 # unique lxmf message hash hash = CharField(unique=True) # noqa: F405 # unique lxmf message hash
source_hash = CharField(index=True) # noqa: F405 source_hash = CharField(index=True) # noqa: F405
destination_hash = CharField(index=True) # noqa: F405 destination_hash = CharField(index=True) # noqa: F405
state = ( # noqa: F405 state = (
CharField() # noqa: F405 CharField() # noqa: F405
) # state is converted from internal int to a human friendly string ) # state is converted from internal int to a human friendly string
progress = FloatField() # noqa: F405 # progress is converted from internal float 0.00-1.00 to float between 0.00/100 (2 decimal places) progress = FloatField() # noqa: F405 # progress is converted from internal float 0.00-1.00 to float between 0.00/100 (2 decimal places)
@@ -150,7 +152,7 @@ class LxmfMessage(BaseModel):
title = TextField() # noqa: F405 title = TextField() # noqa: F405
content = TextField() # noqa: F405 content = TextField() # noqa: F405
fields = TextField() # noqa: F405 # json string fields = TextField() # noqa: F405 # json string
timestamp = ( # noqa: F405 timestamp = (
FloatField() # noqa: F405 FloatField() # noqa: F405
) # timestamp of when the message was originally created (before ever being sent) ) # timestamp of when the message was originally created (before ever being sent)
rssi = IntegerField(null=True) # noqa: F405 rssi = IntegerField(null=True) # noqa: F405
@@ -183,7 +185,7 @@ class LxmfUserIcon(BaseModel):
destination_hash = CharField(unique=True) # noqa: F405 # unique destination hash destination_hash = CharField(unique=True) # noqa: F405 # unique destination hash
icon_name = CharField() # noqa: F405 # material design icon name for the destination hash icon_name = CharField() # noqa: F405 # material design icon name for the destination hash
foreground_colour = CharField() # noqa: F405 # hex colour to use for foreground (icon colour) foreground_colour = CharField() # noqa: F405 # hex colour to use for foreground (icon colour)
background_colour = ( # noqa: F405 background_colour = (
CharField() # noqa: F405 CharField() # noqa: F405
) # hex colour to use for background (background colour) ) # hex colour to use for background (background colour)
@@ -198,7 +200,8 @@ class LxmfUserIcon(BaseModel):
class BlockedDestination(BaseModel): class BlockedDestination(BaseModel):
id = BigAutoField() # noqa: F405 id = BigAutoField() # noqa: F405
destination_hash = CharField( # noqa: F405 destination_hash = CharField( # noqa: F405
unique=True, index=True, unique=True,
index=True,
) # unique destination hash that is blocked ) # unique destination hash that is blocked
created_at = DateTimeField(default=lambda: datetime.now(timezone.utc)) # noqa: F405 created_at = DateTimeField(default=lambda: datetime.now(timezone.utc)) # noqa: F405
updated_at = DateTimeField(default=lambda: datetime.now(timezone.utc)) # noqa: F405 updated_at = DateTimeField(default=lambda: datetime.now(timezone.utc)) # noqa: F405
@@ -211,7 +214,8 @@ class BlockedDestination(BaseModel):
class SpamKeyword(BaseModel): class SpamKeyword(BaseModel):
id = BigAutoField() # noqa: F405 id = BigAutoField() # noqa: F405
keyword = CharField( # noqa: F405 keyword = CharField( # noqa: F405
unique=True, index=True, unique=True,
index=True,
) # keyword to match against message content ) # keyword to match against message content
created_at = DateTimeField(default=lambda: datetime.now(timezone.utc)) # noqa: F405 created_at = DateTimeField(default=lambda: datetime.now(timezone.utc)) # noqa: F405
updated_at = DateTimeField(default=lambda: datetime.now(timezone.utc)) # noqa: F405 updated_at = DateTimeField(default=lambda: datetime.now(timezone.utc)) # noqa: F405

View File

@@ -64,7 +64,9 @@ class ReticulumMeshChat:
# ensure a storage path exists for the loaded identity # ensure a storage path exists for the loaded identity
self.storage_dir = storage_dir or os.path.join("storage") self.storage_dir = storage_dir or os.path.join("storage")
self.storage_path = os.path.join( self.storage_path = os.path.join(
self.storage_dir, "identities", identity.hash.hex(), self.storage_dir,
"identities",
identity.hash.hex(),
) )
print(f"Using Storage Path: {self.storage_path}") print(f"Using Storage Path: {self.storage_path}")
os.makedirs(self.storage_path, exist_ok=True) os.makedirs(self.storage_path, exist_ok=True)
@@ -177,12 +179,14 @@ class ReticulumMeshChat:
) )
RNS.Transport.register_announce_handler( RNS.Transport.register_announce_handler(
AnnounceHandler( AnnounceHandler(
"lxmf.propagation", self.on_lxmf_propagation_announce_received, "lxmf.propagation",
self.on_lxmf_propagation_announce_received,
), ),
) )
RNS.Transport.register_announce_handler( RNS.Transport.register_announce_handler(
AnnounceHandler( AnnounceHandler(
"nomadnetwork.node", self.on_nomadnet_node_announce_received, "nomadnetwork.node",
self.on_nomadnet_node_announce_received,
), ),
) )
@@ -215,7 +219,8 @@ class ReticulumMeshChat:
# start background thread for auto syncing propagation nodes # start background thread for auto syncing propagation nodes
thread = threading.Thread( thread = threading.Thread(
target=asyncio.run, args=(self.announce_sync_propagation_nodes(),), target=asyncio.run,
args=(self.announce_sync_propagation_nodes(),),
) )
thread.daemon = True thread.daemon = True
thread.start() thread.start()
@@ -299,7 +304,7 @@ class ReticulumMeshChat:
self.message_router.set_outbound_propagation_node( self.message_router.set_outbound_propagation_node(
bytes.fromhex(destination_hash), bytes.fromhex(destination_hash),
) )
except Exception: # noqa: E722 except Exception:
# failed to set propagation node, clear it to ensure we don't use an old one by mistake # failed to set propagation node, clear it to ensure we don't use an old one by mistake
self.remove_active_propagation_node() self.remove_active_propagation_node()
@@ -326,7 +331,7 @@ class ReticulumMeshChat:
self.message_router.enable_propagation() self.message_router.enable_propagation()
else: else:
self.message_router.disable_propagation() self.message_router.disable_propagation()
except Exception: # noqa: E722 except Exception:
print("failed to enable or disable propagation node") print("failed to enable or disable propagation node")
def _get_reticulum_section(self): def _get_reticulum_section(self):
@@ -459,7 +464,8 @@ class ReticulumMeshChat:
if "image" in fields or "audio" in fields: if "image" in fields or "audio" in fields:
return True return True
if "file_attachments" in fields and isinstance( if "file_attachments" in fields and isinstance(
fields["file_attachments"], list, fields["file_attachments"],
list,
): ):
return len(fields["file_attachments"]) > 0 return len(fields["file_attachments"]) > 0
return False return False
@@ -473,7 +479,8 @@ class ReticulumMeshChat:
matches = set() matches = set()
query = database.LxmfMessage.select( query = database.LxmfMessage.select(
database.LxmfMessage.source_hash, database.LxmfMessage.destination_hash, database.LxmfMessage.source_hash,
database.LxmfMessage.destination_hash,
).where( ).where(
( (
(database.LxmfMessage.source_hash == local_hash) (database.LxmfMessage.source_hash == local_hash)
@@ -810,7 +817,9 @@ class ReticulumMeshChat:
# set optional AutoInterface options # set optional AutoInterface options
InterfaceEditor.update_value(interface_details, data, "group_id") InterfaceEditor.update_value(interface_details, data, "group_id")
InterfaceEditor.update_value( InterfaceEditor.update_value(
interface_details, data, "multicast_address_type", interface_details,
data,
"multicast_address_type",
) )
InterfaceEditor.update_value(interface_details, data, "devices") InterfaceEditor.update_value(interface_details, data, "devices")
InterfaceEditor.update_value(interface_details, data, "ignored_devices") InterfaceEditor.update_value(interface_details, data, "ignored_devices")
@@ -1008,10 +1017,14 @@ class ReticulumMeshChat:
InterfaceEditor.update_value(interface_details, data, "callsign") InterfaceEditor.update_value(interface_details, data, "callsign")
InterfaceEditor.update_value(interface_details, data, "id_interval") InterfaceEditor.update_value(interface_details, data, "id_interval")
InterfaceEditor.update_value( InterfaceEditor.update_value(
interface_details, data, "airtime_limit_long", interface_details,
data,
"airtime_limit_long",
) )
InterfaceEditor.update_value( InterfaceEditor.update_value(
interface_details, data, "airtime_limit_short", interface_details,
data,
"airtime_limit_short",
) )
# handle RNodeMultiInterface # handle RNodeMultiInterface
@@ -1200,7 +1213,7 @@ class ReticulumMeshChat:
try: try:
data = await request.json() data = await request.json()
selected_interface_names = data.get("selected_interface_names") selected_interface_names = data.get("selected_interface_names")
except Exception: # noqa: E722 except Exception:
# request data was not json, but we don't care # request data was not json, but we don't care
pass pass
@@ -1609,7 +1622,8 @@ class ReticulumMeshChat:
# initiate audio call # initiate audio call
try: try:
audio_call = await self.audio_call_manager.initiate( audio_call = await self.audio_call_manager.initiate(
destination_hash, timeout_seconds, destination_hash,
timeout_seconds,
) )
return web.json_response( return web.json_response(
{ {
@@ -1652,7 +1666,7 @@ class ReticulumMeshChat:
if websocket_response.closed is False: if websocket_response.closed is False:
try: try:
AsyncUtils.run_async(websocket_response.send_bytes(data)) AsyncUtils.run_async(websocket_response.send_bytes(data))
except Exception: # noqa: E722 except Exception:
# ignore errors sending audio packets to websocket # ignore errors sending audio packets to websocket
pass pass
@@ -1663,7 +1677,7 @@ class ReticulumMeshChat:
AsyncUtils.run_async( AsyncUtils.run_async(
websocket_response.close(code=WSCloseCode.GOING_AWAY), websocket_response.close(code=WSCloseCode.GOING_AWAY),
) )
except Exception: # noqa: E722 except Exception:
# ignore errors closing websocket # ignore errors closing websocket
pass pass
@@ -1983,21 +1997,27 @@ class ReticulumMeshChat:
and lxmf_delivery_announce.app_data is not None and lxmf_delivery_announce.app_data is not None
): ):
operator_display_name = self.parse_lxmf_display_name( operator_display_name = self.parse_lxmf_display_name(
lxmf_delivery_announce.app_data, None, lxmf_delivery_announce.app_data,
None,
) )
elif ( elif (
nomadnetwork_node_announce is not None nomadnetwork_node_announce is not None
and nomadnetwork_node_announce.app_data is not None and nomadnetwork_node_announce.app_data is not None
): ):
operator_display_name = ReticulumMeshChat.parse_nomadnetwork_node_display_name( operator_display_name = (
nomadnetwork_node_announce.app_data, None, ReticulumMeshChat.parse_nomadnetwork_node_display_name(
nomadnetwork_node_announce.app_data,
None,
)
) )
# parse app_data so we can see if propagation is enabled or disabled for this node # parse app_data so we can see if propagation is enabled or disabled for this node
is_propagation_enabled = None is_propagation_enabled = None
per_transfer_limit = None per_transfer_limit = None
propagation_node_data = ReticulumMeshChat.parse_lxmf_propagation_node_app_data( propagation_node_data = (
announce.app_data, ReticulumMeshChat.parse_lxmf_propagation_node_app_data(
announce.app_data,
)
) )
if propagation_node_data is not None: if propagation_node_data is not None:
is_propagation_enabled = propagation_node_data["enabled"] is_propagation_enabled = propagation_node_data["enabled"]
@@ -2312,7 +2332,8 @@ class ReticulumMeshChat:
# update display name if provided # update display name if provided
if len(display_name) > 0: if len(display_name) > 0:
self.db_upsert_custom_destination_display_name( self.db_upsert_custom_destination_display_name(
destination_hash, display_name, destination_hash,
display_name,
) )
return web.json_response( return web.json_response(
{ {
@@ -2756,7 +2777,9 @@ class ReticulumMeshChat:
other_user_hash, other_user_hash,
), ),
"destination_hash": other_user_hash, "destination_hash": other_user_hash,
"is_unread": ReticulumMeshChat.is_lxmf_conversation_unread(other_user_hash), "is_unread": ReticulumMeshChat.is_lxmf_conversation_unread(
other_user_hash,
),
"failed_messages_count": ReticulumMeshChat.lxmf_conversation_failed_messages_count( "failed_messages_count": ReticulumMeshChat.lxmf_conversation_failed_messages_count(
other_user_hash, other_user_hash,
), ),
@@ -2878,7 +2901,8 @@ class ReticulumMeshChat:
destination_hash = data.get("destination_hash", "") destination_hash = data.get("destination_hash", "")
if not destination_hash or len(destination_hash) != 32: if not destination_hash or len(destination_hash) != 32:
return web.json_response( return web.json_response(
{"error": "Invalid destination hash"}, status=400, {"error": "Invalid destination hash"},
status=400,
) )
try: try:
@@ -2886,12 +2910,13 @@ class ReticulumMeshChat:
# drop any existing paths to this destination # drop any existing paths to this destination
try: try:
RNS.Transport.drop_path(bytes.fromhex(destination_hash)) RNS.Transport.drop_path(bytes.fromhex(destination_hash))
except Exception: # noqa: E722 except Exception:
pass pass
return web.json_response({"message": "ok"}) return web.json_response({"message": "ok"})
except Exception: # noqa: E722 except Exception:
return web.json_response( return web.json_response(
{"error": "Destination already blocked"}, status=400, {"error": "Destination already blocked"},
status=400,
) )
# remove blocked destination # remove blocked destination
@@ -2900,7 +2925,8 @@ class ReticulumMeshChat:
destination_hash = request.match_info.get("destination_hash", "") destination_hash = request.match_info.get("destination_hash", "")
if not destination_hash or len(destination_hash) != 32: if not destination_hash or len(destination_hash) != 32:
return web.json_response( return web.json_response(
{"error": "Invalid destination hash"}, status=400, {"error": "Invalid destination hash"},
status=400,
) )
try: try:
@@ -2911,7 +2937,8 @@ class ReticulumMeshChat:
blocked.delete_instance() blocked.delete_instance()
return web.json_response({"message": "ok"}) return web.json_response({"message": "ok"})
return web.json_response( return web.json_response(
{"error": "Destination not blocked"}, status=404, {"error": "Destination not blocked"},
status=404,
) )
except Exception as e: except Exception as e:
return web.json_response({"error": str(e)}, status=500) return web.json_response({"error": str(e)}, status=500)
@@ -2945,9 +2972,10 @@ class ReticulumMeshChat:
try: try:
database.SpamKeyword.create(keyword=keyword) database.SpamKeyword.create(keyword=keyword)
return web.json_response({"message": "ok"}) return web.json_response({"message": "ok"})
except Exception: # noqa: E722 except Exception:
return web.json_response( return web.json_response(
{"error": "Keyword already exists"}, status=400, {"error": "Keyword already exists"},
status=400,
) )
# remove spam keyword # remove spam keyword
@@ -2956,7 +2984,7 @@ class ReticulumMeshChat:
keyword_id = request.match_info.get("keyword_id", "") keyword_id = request.match_info.get("keyword_id", "")
try: try:
keyword_id = int(keyword_id) keyword_id = int(keyword_id)
except (ValueError, TypeError): # noqa: E722 except (ValueError, TypeError):
return web.json_response({"error": "Invalid keyword ID"}, status=400) return web.json_response({"error": "Invalid keyword ID"}, status=400)
try: try:
@@ -2999,7 +3027,7 @@ class ReticulumMeshChat:
if launch_browser: if launch_browser:
try: try:
webbrowser.open(f"http://127.0.0.1:{port}") webbrowser.open(f"http://127.0.0.1:{port}")
except Exception: # noqa: E722 except Exception:
print("failed to launch web browser") print("failed to launch web browser")
# create and run web app # create and run web app
@@ -3106,7 +3134,8 @@ class ReticulumMeshChat:
self.config.lxmf_inbound_stamp_cost.set(value) self.config.lxmf_inbound_stamp_cost.set(value)
# update the inbound stamp cost on the delivery destination # update the inbound stamp cost on the delivery destination
self.message_router.set_inbound_stamp_cost( self.message_router.set_inbound_stamp_cost(
self.local_lxmf_destination.hash, value, self.local_lxmf_destination.hash,
value,
) )
# re-announce to update the stamp cost in announces # re-announce to update the stamp cost in announces
self.local_lxmf_destination.display_name = self.config.display_name.get() self.local_lxmf_destination.display_name = self.config.display_name.get()
@@ -3504,7 +3533,7 @@ class ReticulumMeshChat:
for websocket_client in self.websocket_clients: for websocket_client in self.websocket_clients:
try: try:
await websocket_client.send_str(data) await websocket_client.send_str(data)
except Exception: # noqa: E722 except Exception:
# do nothing if failed to broadcast to a specific websocket client # do nothing if failed to broadcast to a specific websocket client
pass pass
@@ -3571,7 +3600,9 @@ class ReticulumMeshChat:
remote_destination_hash_hex = None remote_destination_hash_hex = None
if remote_identity is not None: if remote_identity is not None:
remote_destination_hash = RNS.Destination.hash( remote_destination_hash = RNS.Destination.hash(
remote_identity, "call", "audio", remote_identity,
"call",
"audio",
) )
remote_destination_hash_hex = remote_destination_hash.hex() remote_destination_hash_hex = remote_destination_hash.hex()
@@ -3674,7 +3705,9 @@ class ReticulumMeshChat:
"method": self.convert_lxmf_method_to_string(lxmf_message), "method": self.convert_lxmf_method_to_string(lxmf_message),
"delivery_attempts": lxmf_message.delivery_attempts, "delivery_attempts": lxmf_message.delivery_attempts,
"next_delivery_attempt_at": getattr( "next_delivery_attempt_at": getattr(
lxmf_message, "next_delivery_attempt", None, lxmf_message,
"next_delivery_attempt",
None,
), # attribute may not exist yet ), # attribute may not exist yet
"title": lxmf_message.title.decode("utf-8"), "title": lxmf_message.title.decode("utf-8"),
"content": lxmf_message.content.decode("utf-8"), "content": lxmf_message.content.decode("utf-8"),
@@ -3757,7 +3790,9 @@ class ReticulumMeshChat:
if announce.aspect == "lxmf.delivery": if announce.aspect == "lxmf.delivery":
display_name = self.parse_lxmf_display_name(announce.app_data) display_name = self.parse_lxmf_display_name(announce.app_data)
elif announce.aspect == "nomadnetwork.node": elif announce.aspect == "nomadnetwork.node":
display_name = ReticulumMeshChat.parse_nomadnetwork_node_display_name(announce.app_data) display_name = ReticulumMeshChat.parse_nomadnetwork_node_display_name(
announce.app_data,
)
# find lxmf user icon from database # find lxmf user icon from database
lxmf_user_icon = None lxmf_user_icon = None
@@ -3857,7 +3892,8 @@ class ReticulumMeshChat:
# upsert to database # upsert to database
query = database.LxmfUserIcon.insert(data) query = database.LxmfUserIcon.insert(data)
query = query.on_conflict( query = query.on_conflict(
conflict_target=[database.LxmfUserIcon.destination_hash], update=data, conflict_target=[database.LxmfUserIcon.destination_hash],
update=data,
) )
query.execute() query.execute()
@@ -3869,7 +3905,7 @@ class ReticulumMeshChat:
database.BlockedDestination.destination_hash == destination_hash, database.BlockedDestination.destination_hash == destination_hash,
) )
return blocked is not None return blocked is not None
except Exception: # noqa: E722 except Exception:
return False return False
# check if message content matches spam keywords # check if message content matches spam keywords
@@ -3882,7 +3918,7 @@ class ReticulumMeshChat:
if keyword.keyword.lower() in search_text: if keyword.keyword.lower() in search_text:
return True return True
return False return False
except Exception: # noqa: E722 except Exception:
return False return False
# check if message has attachments and should be rejected # check if message has attachments and should be rejected
@@ -3896,7 +3932,7 @@ class ReticulumMeshChat:
if LXMF.FIELD_AUDIO in lxmf_fields: if LXMF.FIELD_AUDIO in lxmf_fields:
return True return True
return False return False
except Exception: # noqa: E722 except Exception:
return False return False
# handle an lxmf delivery from reticulum # handle an lxmf delivery from reticulum
@@ -4046,7 +4082,9 @@ class ReticulumMeshChat:
# upserts the provided lxmf message to the database # upserts the provided lxmf message to the database
def db_upsert_lxmf_message( def db_upsert_lxmf_message(
self, lxmf_message: LXMF.LXMessage, is_spam: bool = False, self,
lxmf_message: LXMF.LXMessage,
is_spam: bool = False,
): ):
# convert lxmf message to dict # convert lxmf message to dict
lxmf_message_dict = self.convert_lxmf_message_to_dict(lxmf_message) lxmf_message_dict = self.convert_lxmf_message_to_dict(lxmf_message)
@@ -4076,7 +4114,8 @@ class ReticulumMeshChat:
# upsert to database # upsert to database
query = database.LxmfMessage.insert(data) query = database.LxmfMessage.insert(data)
query = query.on_conflict( query = query.on_conflict(
conflict_target=[database.LxmfMessage.hash], update=data, conflict_target=[database.LxmfMessage.hash],
update=data,
) )
query.execute() query.execute()
@@ -4116,14 +4155,16 @@ class ReticulumMeshChat:
# upsert to database # upsert to database
query = database.Announce.insert(data) query = database.Announce.insert(data)
query = query.on_conflict( query = query.on_conflict(
conflict_target=[database.Announce.destination_hash], update=data, conflict_target=[database.Announce.destination_hash],
update=data,
) )
query.execute() query.execute()
# upserts a custom destination display name to the database # upserts a custom destination display name to the database
@staticmethod @staticmethod
def db_upsert_custom_destination_display_name( def db_upsert_custom_destination_display_name(
destination_hash: str, display_name: str, destination_hash: str,
display_name: str,
): ):
# prepare data to insert or update # prepare data to insert or update
data = { data = {
@@ -4143,7 +4184,9 @@ class ReticulumMeshChat:
# upserts a custom destination display name to the database # upserts a custom destination display name to the database
@staticmethod @staticmethod
def db_upsert_favourite( def db_upsert_favourite(
destination_hash: str, display_name: str, aspect: str, destination_hash: str,
display_name: str,
aspect: str,
): ):
# prepare data to insert or update # prepare data to insert or update
data = { data = {
@@ -4397,7 +4440,11 @@ class ReticulumMeshChat:
# upsert announce to database # upsert announce to database
self.db_upsert_announce( self.db_upsert_announce(
announced_identity, destination_hash, aspect, app_data, announce_packet_hash, announced_identity,
destination_hash,
aspect,
app_data,
announce_packet_hash,
) )
# find announce from database # find announce from database
@@ -4448,7 +4495,11 @@ class ReticulumMeshChat:
# upsert announce to database # upsert announce to database
self.db_upsert_announce( self.db_upsert_announce(
announced_identity, destination_hash, aspect, app_data, announce_packet_hash, announced_identity,
destination_hash,
aspect,
app_data,
announce_packet_hash,
) )
# find announce from database # find announce from database
@@ -4498,7 +4549,11 @@ class ReticulumMeshChat:
# upsert announce to database # upsert announce to database
self.db_upsert_announce( self.db_upsert_announce(
announced_identity, destination_hash, aspect, app_data, announce_packet_hash, announced_identity,
destination_hash,
aspect,
app_data,
announce_packet_hash,
) )
# find announce from database # find announce from database
@@ -4626,7 +4681,11 @@ class ReticulumMeshChat:
# upsert announce to database # upsert announce to database
self.db_upsert_announce( self.db_upsert_announce(
announced_identity, destination_hash, aspect, app_data, announce_packet_hash, announced_identity,
destination_hash,
aspect,
app_data,
announce_packet_hash,
) )
# find announce from database # find announce from database
@@ -4676,7 +4735,9 @@ class ReticulumMeshChat:
# if app data is available in database, it should be base64 encoded text that was announced # if app data is available in database, it should be base64 encoded text that was announced
# we will return the parsed lxmf display name as the conversation name # we will return the parsed lxmf display name as the conversation name
if lxmf_announce is not None and lxmf_announce.app_data is not None: if lxmf_announce is not None and lxmf_announce.app_data is not None:
return ReticulumMeshChat.parse_lxmf_display_name(app_data_base64=lxmf_announce.app_data) return ReticulumMeshChat.parse_lxmf_display_name(
app_data_base64=lxmf_announce.app_data,
)
# announce did not have app data, so provide a fallback name # announce did not have app data, so provide a fallback name
return "Anonymous Peer" return "Anonymous Peer"
@@ -4684,14 +4745,15 @@ class ReticulumMeshChat:
# reads the lxmf display name from the provided base64 app data # reads the lxmf display name from the provided base64 app data
@staticmethod @staticmethod
def parse_lxmf_display_name( def parse_lxmf_display_name(
app_data_base64: str, default_value: str | None = "Anonymous Peer", app_data_base64: str,
default_value: str | None = "Anonymous Peer",
): ):
try: try:
app_data_bytes = base64.b64decode(app_data_base64) app_data_bytes = base64.b64decode(app_data_base64)
display_name = LXMF.display_name_from_app_data(app_data_bytes) display_name = LXMF.display_name_from_app_data(app_data_bytes)
if display_name is not None: if display_name is not None:
return display_name return display_name
except Exception: # noqa: E722 except Exception:
pass pass
return default_value return default_value
@@ -4702,18 +4764,19 @@ class ReticulumMeshChat:
try: try:
app_data_bytes = base64.b64decode(app_data_base64) app_data_bytes = base64.b64decode(app_data_base64)
return LXMF.stamp_cost_from_app_data(app_data_bytes) return LXMF.stamp_cost_from_app_data(app_data_bytes)
except Exception: # noqa: E722 except Exception:
return None return None
# reads the nomadnetwork node display name from the provided base64 app data # reads the nomadnetwork node display name from the provided base64 app data
@staticmethod @staticmethod
def parse_nomadnetwork_node_display_name( def parse_nomadnetwork_node_display_name(
app_data_base64: str, default_value: str | None = "Anonymous Node", app_data_base64: str,
default_value: str | None = "Anonymous Node",
): ):
try: try:
app_data_bytes = base64.b64decode(app_data_base64) app_data_bytes = base64.b64decode(app_data_base64)
return app_data_bytes.decode("utf-8") return app_data_bytes.decode("utf-8")
except Exception: # noqa: E722 except Exception:
return default_value return default_value
# parses lxmf propagation node app data # parses lxmf propagation node app data
@@ -4727,7 +4790,7 @@ class ReticulumMeshChat:
"timebase": int(data[1]), "timebase": int(data[1]),
"per_transfer_limit": int(data[3]), "per_transfer_limit": int(data[3]),
} }
except Exception: # noqa: E722 except Exception:
return None return None
# returns true if the conversation has messages newer than the last read at timestamp # returns true if the conversation has messages newer than the last read at timestamp
@@ -4760,10 +4823,12 @@ class ReticulumMeshChat:
# conversation is unread if last read at is before the latest incoming message creation date # conversation is unread if last read at is before the latest incoming message creation date
conversation_last_read_at = datetime.strptime( conversation_last_read_at = datetime.strptime(
lxmf_conversation_read_state.last_read_at, "%Y-%m-%d %H:%M:%S.%f%z", lxmf_conversation_read_state.last_read_at,
"%Y-%m-%d %H:%M:%S.%f%z",
) )
conversation_latest_message_at = datetime.strptime( conversation_latest_message_at = datetime.strptime(
latest_incoming_lxmf_message.created_at, "%Y-%m-%d %H:%M:%S.%f%z", latest_incoming_lxmf_message.created_at,
"%Y-%m-%d %H:%M:%S.%f%z",
) )
return conversation_last_read_at < conversation_latest_message_at return conversation_last_read_at < conversation_latest_message_at
@@ -4882,44 +4947,57 @@ class Config:
last_announced_at = IntConfig("last_announced_at", None) last_announced_at = IntConfig("last_announced_at", None)
theme = StringConfig("theme", "light") theme = StringConfig("theme", "light")
auto_resend_failed_messages_when_announce_received = BoolConfig( auto_resend_failed_messages_when_announce_received = BoolConfig(
"auto_resend_failed_messages_when_announce_received", True, "auto_resend_failed_messages_when_announce_received",
True,
) )
allow_auto_resending_failed_messages_with_attachments = BoolConfig( allow_auto_resending_failed_messages_with_attachments = BoolConfig(
"allow_auto_resending_failed_messages_with_attachments", False, "allow_auto_resending_failed_messages_with_attachments",
False,
) )
auto_send_failed_messages_to_propagation_node = BoolConfig( auto_send_failed_messages_to_propagation_node = BoolConfig(
"auto_send_failed_messages_to_propagation_node", False, "auto_send_failed_messages_to_propagation_node",
False,
) )
show_suggested_community_interfaces = BoolConfig( show_suggested_community_interfaces = BoolConfig(
"show_suggested_community_interfaces", True, "show_suggested_community_interfaces",
True,
) )
lxmf_delivery_transfer_limit_in_bytes = IntConfig( lxmf_delivery_transfer_limit_in_bytes = IntConfig(
"lxmf_delivery_transfer_limit_in_bytes", 1000 * 1000 * 10, "lxmf_delivery_transfer_limit_in_bytes",
1000 * 1000 * 10,
) # 10MB ) # 10MB
lxmf_preferred_propagation_node_destination_hash = StringConfig( lxmf_preferred_propagation_node_destination_hash = StringConfig(
"lxmf_preferred_propagation_node_destination_hash", None, "lxmf_preferred_propagation_node_destination_hash",
None,
) )
lxmf_preferred_propagation_node_auto_sync_interval_seconds = IntConfig( lxmf_preferred_propagation_node_auto_sync_interval_seconds = IntConfig(
"lxmf_preferred_propagation_node_auto_sync_interval_seconds", 0, "lxmf_preferred_propagation_node_auto_sync_interval_seconds",
0,
) )
lxmf_preferred_propagation_node_last_synced_at = IntConfig( lxmf_preferred_propagation_node_last_synced_at = IntConfig(
"lxmf_preferred_propagation_node_last_synced_at", None, "lxmf_preferred_propagation_node_last_synced_at",
None,
) )
lxmf_local_propagation_node_enabled = BoolConfig( lxmf_local_propagation_node_enabled = BoolConfig(
"lxmf_local_propagation_node_enabled", False, "lxmf_local_propagation_node_enabled",
False,
) )
lxmf_user_icon_name = StringConfig("lxmf_user_icon_name", None) lxmf_user_icon_name = StringConfig("lxmf_user_icon_name", None)
lxmf_user_icon_foreground_colour = StringConfig( lxmf_user_icon_foreground_colour = StringConfig(
"lxmf_user_icon_foreground_colour", None, "lxmf_user_icon_foreground_colour",
None,
) )
lxmf_user_icon_background_colour = StringConfig( lxmf_user_icon_background_colour = StringConfig(
"lxmf_user_icon_background_colour", None, "lxmf_user_icon_background_colour",
None,
) )
lxmf_inbound_stamp_cost = IntConfig( lxmf_inbound_stamp_cost = IntConfig(
"lxmf_inbound_stamp_cost", 8, "lxmf_inbound_stamp_cost",
8,
) # for direct delivery messages ) # for direct delivery messages
lxmf_propagation_node_stamp_cost = IntConfig( lxmf_propagation_node_stamp_cost = IntConfig(
"lxmf_propagation_node_stamp_cost", 16, "lxmf_propagation_node_stamp_cost",
16,
) # for propagation node messages ) # for propagation node messages
@@ -4959,14 +5037,14 @@ class NomadnetDownloader:
if self.request_receipt is not None: if self.request_receipt is not None:
try: try:
self.request_receipt.cancel() self.request_receipt.cancel()
except Exception: # noqa: E722 except Exception:
pass pass
# clean up the link if we created it # clean up the link if we created it
if self.link is not None: if self.link is not None:
try: try:
self.link.teardown() self.link.teardown()
except Exception: # noqa: E722 except Exception:
pass pass
# notify that download was cancelled # notify that download was cancelled
@@ -4974,7 +5052,9 @@ class NomadnetDownloader:
# setup link to destination and request download # setup link to destination and request download
async def download( async def download(
self, path_lookup_timeout: int = 15, link_establishment_timeout: int = 15, self,
path_lookup_timeout: int = 15,
link_establishment_timeout: int = 15,
): ):
# check if cancelled before starting # check if cancelled before starting
if self.is_cancelled: if self.is_cancelled:
@@ -5175,7 +5255,7 @@ class NomadnetFileDownloader(NomadnetDownloader):
file_name: str = response[0] file_name: str = response[0]
file_data: bytes = response[1] file_data: bytes = response[1]
self.on_file_download_success(file_name, file_data) self.on_file_download_success(file_name, file_data)
except Exception: # noqa: E722 except Exception:
self.on_download_failure("unsupported_response") self.on_download_failure("unsupported_response")
# page download failed, send error to provided callback # page download failed, send error to provided callback
@@ -5241,7 +5321,8 @@ def main():
help="Throws an exception. Used for testing the electron error dialog", help="Throws an exception. Used for testing the electron error dialog",
) )
parser.add_argument( parser.add_argument(
"args", nargs=argparse.REMAINDER, "args",
nargs=argparse.REMAINDER,
) # allow unknown command line args ) # allow unknown command line args
args = parser.parse_args() args = parser.parse_args()
@@ -5313,7 +5394,9 @@ def main():
# init app # init app
reticulum_meshchat = ReticulumMeshChat( reticulum_meshchat = ReticulumMeshChat(
identity, args.storage_dir, args.reticulum_config_dir, identity,
args.storage_dir,
args.reticulum_config_dir,
) )
reticulum_meshchat.run(args.host, args.port, launch_browser=args.headless is False) reticulum_meshchat.run(args.host, args.port, launch_browser=args.headless is False)

View File

@@ -7,7 +7,11 @@ class AnnounceHandler:
# we will just pass the received announce back to the provided callback # we will just pass the received announce back to the provided callback
def received_announce( def received_announce(
self, destination_hash, announced_identity, app_data, announce_packet_hash, self,
destination_hash,
announced_identity,
app_data,
announce_packet_hash,
): ):
try: try:
# handle received announce # handle received announce
@@ -18,6 +22,6 @@ class AnnounceHandler:
app_data, app_data,
announce_packet_hash, announce_packet_hash,
) )
except Exception: # noqa: E722 except Exception:
# ignore failure to handle received announce # ignore failure to handle received announce
pass pass

View File

@@ -146,7 +146,9 @@ class AudioCallManager:
# attempts to initiate a call to the provided destination and returns the link hash on success # attempts to initiate a call to the provided destination and returns the link hash on success
async def initiate( async def initiate(
self, destination_hash: bytes, timeout_seconds: int = 15, self,
destination_hash: bytes,
timeout_seconds: int = 15,
) -> AudioCall: ) -> AudioCall:
# determine when to timeout # determine when to timeout
timeout_after_seconds = time.time() + timeout_seconds timeout_after_seconds = time.time() + timeout_seconds
@@ -240,7 +242,7 @@ class AudioCallReceiver:
) )
link.teardown() link.teardown()
return return
except Exception: # noqa: E722 except Exception:
# if we can't get identity yet, we'll check later # if we can't get identity yet, we'll check later
pass pass

View File

@@ -71,7 +71,8 @@ class WebsocketClientInterface(Interface):
self.websocket.send(data) self.websocket.send(data)
except Exception as e: except Exception as e:
RNS.log( RNS.log(
f"Exception occurred while transmitting via {self!s}", RNS.LOG_ERROR, f"Exception occurred while transmitting via {self!s}",
RNS.LOG_ERROR,
) )
RNS.log(f"The contained exception was: {e!s}", RNS.LOG_ERROR) RNS.log(f"The contained exception was: {e!s}", RNS.LOG_ERROR)
return return
@@ -93,7 +94,9 @@ class WebsocketClientInterface(Interface):
try: try:
RNS.log(f"Connecting to Websocket for {self!s}...", RNS.LOG_DEBUG) RNS.log(f"Connecting to Websocket for {self!s}...", RNS.LOG_DEBUG)
self.websocket = connect( self.websocket = connect(
f"{self.target_url}", max_size=None, compression=None, f"{self.target_url}",
max_size=None,
compression=None,
) )
RNS.log(f"Connected to Websocket for {self!s}", RNS.LOG_DEBUG) RNS.log(f"Connected to Websocket for {self!s}", RNS.LOG_DEBUG)
self.read_loop() self.read_loop()