mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-07-06 18:01:22 +02:00
Websocket for contact deletion, radio contact deletion flag fix, resent message now appends sender name
This commit is contained in:
@@ -215,6 +215,19 @@ class ContactRepository:
|
|||||||
)
|
)
|
||||||
await db.conn.commit()
|
await db.conn.commit()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def clear_on_radio_except(keep_keys: list[str]) -> None:
|
||||||
|
"""Set on_radio=False for all contacts NOT in keep_keys."""
|
||||||
|
if not keep_keys:
|
||||||
|
await db.conn.execute("UPDATE contacts SET on_radio = 0 WHERE on_radio = 1")
|
||||||
|
else:
|
||||||
|
placeholders = ",".join("?" * len(keep_keys))
|
||||||
|
await db.conn.execute(
|
||||||
|
f"UPDATE contacts SET on_radio = 0 WHERE on_radio = 1 AND public_key NOT IN ({placeholders})",
|
||||||
|
keep_keys,
|
||||||
|
)
|
||||||
|
await db.conn.commit()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def delete(public_key: str) -> None:
|
async def delete(public_key: str) -> None:
|
||||||
normalized = public_key.lower()
|
normalized = public_key.lower()
|
||||||
|
|||||||
@@ -127,4 +127,9 @@ async def delete_channel(key: str) -> dict:
|
|||||||
"""
|
"""
|
||||||
logger.info("Deleting channel %s from database", key)
|
logger.info("Deleting channel %s from database", key)
|
||||||
await ChannelRepository.delete(key)
|
await ChannelRepository.delete(key)
|
||||||
|
|
||||||
|
from app.websocket import broadcast_event
|
||||||
|
|
||||||
|
broadcast_event("channel_deleted", {"key": key})
|
||||||
|
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|||||||
@@ -271,16 +271,21 @@ async def sync_contacts_from_radio() -> dict:
|
|||||||
contacts = result.payload
|
contacts = result.payload
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
|
synced_keys: list[str] = []
|
||||||
for public_key, contact_data in contacts.items():
|
for public_key, contact_data in contacts.items():
|
||||||
lower_key = public_key.lower()
|
lower_key = public_key.lower()
|
||||||
await ContactRepository.upsert(
|
await ContactRepository.upsert(
|
||||||
Contact.from_radio_dict(lower_key, contact_data, on_radio=True)
|
Contact.from_radio_dict(lower_key, contact_data, on_radio=True)
|
||||||
)
|
)
|
||||||
|
synced_keys.append(lower_key)
|
||||||
claimed = await MessageRepository.claim_prefix_messages(lower_key)
|
claimed = await MessageRepository.claim_prefix_messages(lower_key)
|
||||||
if claimed > 0:
|
if claimed > 0:
|
||||||
logger.info("Claimed %d prefix DM message(s) for contact %s", claimed, public_key[:12])
|
logger.info("Claimed %d prefix DM message(s) for contact %s", claimed, public_key[:12])
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
|
# Clear on_radio for contacts not found on the radio
|
||||||
|
await ContactRepository.clear_on_radio_except(synced_keys)
|
||||||
|
|
||||||
logger.info("Synced %d contacts from radio", count)
|
logger.info("Synced %d contacts from radio", count)
|
||||||
return {"synced": count}
|
return {"synced": count}
|
||||||
|
|
||||||
@@ -368,6 +373,10 @@ async def delete_contact(public_key: str) -> dict:
|
|||||||
await ContactRepository.delete(contact.public_key)
|
await ContactRepository.delete(contact.public_key)
|
||||||
logger.info("Deleted contact %s", contact.public_key[:12])
|
logger.info("Deleted contact %s", contact.public_key[:12])
|
||||||
|
|
||||||
|
from app.websocket import broadcast_event
|
||||||
|
|
||||||
|
broadcast_event("contact_deleted", {"public_key": contact.public_key})
|
||||||
|
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -399,6 +399,7 @@ async def resend_channel_message(
|
|||||||
sender_timestamp=now,
|
sender_timestamp=now,
|
||||||
received_at=now,
|
received_at=now,
|
||||||
outgoing=True,
|
outgoing=True,
|
||||||
|
sender_name=radio_name or None,
|
||||||
)
|
)
|
||||||
if new_msg_id is None:
|
if new_msg_id is None:
|
||||||
# Timestamp-second collision (same text+channel within the same second).
|
# Timestamp-second collision (same text+channel within the same second).
|
||||||
|
|||||||
@@ -287,6 +287,14 @@ export function App() {
|
|||||||
onContact: (contact: Contact) => {
|
onContact: (contact: Contact) => {
|
||||||
setContacts((prev) => mergeContactIntoList(prev, contact));
|
setContacts((prev) => mergeContactIntoList(prev, contact));
|
||||||
},
|
},
|
||||||
|
onContactDeleted: (publicKey: string) => {
|
||||||
|
setContacts((prev) => prev.filter((c) => c.public_key !== publicKey));
|
||||||
|
messageCache.remove(publicKey);
|
||||||
|
},
|
||||||
|
onChannelDeleted: (key: string) => {
|
||||||
|
setChannels((prev) => prev.filter((c) => c.key !== key));
|
||||||
|
messageCache.remove(key);
|
||||||
|
},
|
||||||
onRawPacket: (packet: RawPacket) => {
|
onRawPacket: (packet: RawPacket) => {
|
||||||
setRawPackets((prev) => appendRawPacketUnique(prev, packet, MAX_RAW_PACKETS));
|
setRawPackets((prev) => appendRawPacketUnique(prev, packet, MAX_RAW_PACKETS));
|
||||||
},
|
},
|
||||||
@@ -306,6 +314,7 @@ export function App() {
|
|||||||
setConfig,
|
setConfig,
|
||||||
activeConversationRef,
|
activeConversationRef,
|
||||||
setContacts,
|
setContacts,
|
||||||
|
setChannels,
|
||||||
triggerReconcile,
|
triggerReconcile,
|
||||||
refreshUnreads,
|
refreshUnreads,
|
||||||
fetchAllContacts,
|
fetchAllContacts,
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ interface UseWebSocketOptions {
|
|||||||
onHealth?: (health: HealthStatus) => void;
|
onHealth?: (health: HealthStatus) => void;
|
||||||
onMessage?: (message: Message) => void;
|
onMessage?: (message: Message) => void;
|
||||||
onContact?: (contact: Contact) => void;
|
onContact?: (contact: Contact) => void;
|
||||||
|
onContactDeleted?: (publicKey: string) => void;
|
||||||
|
onChannelDeleted?: (key: string) => void;
|
||||||
onRawPacket?: (packet: RawPacket) => void;
|
onRawPacket?: (packet: RawPacket) => void;
|
||||||
onMessageAcked?: (messageId: number, ackCount: number, paths?: MessagePath[]) => void;
|
onMessageAcked?: (messageId: number, ackCount: number, paths?: MessagePath[]) => void;
|
||||||
onError?: (error: ErrorEvent) => void;
|
onError?: (error: ErrorEvent) => void;
|
||||||
@@ -103,6 +105,12 @@ export function useWebSocket(options: UseWebSocketOptions) {
|
|||||||
case 'contact':
|
case 'contact':
|
||||||
handlers.onContact?.(msg.data as Contact);
|
handlers.onContact?.(msg.data as Contact);
|
||||||
break;
|
break;
|
||||||
|
case 'contact_deleted':
|
||||||
|
handlers.onContactDeleted?.((msg.data as { public_key: string }).public_key);
|
||||||
|
break;
|
||||||
|
case 'channel_deleted':
|
||||||
|
handlers.onChannelDeleted?.((msg.data as { key: string }).key);
|
||||||
|
break;
|
||||||
case 'raw_packet':
|
case 'raw_packet':
|
||||||
handlers.onRawPacket?.(msg.data as RawPacket);
|
handlers.onRawPacket?.(msg.data as RawPacket);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user