Files
meshcore-gui/meshcore_gui/services/contact_cleaner.py
2026-03-09 17:53:29 +01:00

76 lines
2.1 KiB
Python

"""
Contact cleaner service for MeshCore GUI.
Provides business logic for bulk-deleting unpinned contacts from the
MeshCore device. All decision logic (which contacts to purge, counting
pinned vs unpinned) lives here — the GUI only calls this service and
displays results.
Thread safety
~~~~~~~~~~~~~
Methods read from SharedData (thread-safe) and PinStore (thread-safe).
No mutable state is stored in this service.
"""
from dataclasses import dataclass
from typing import Dict, List, Set
from meshcore_gui.services.pin_store import PinStore
@dataclass
class PurgeStats:
"""Statistics for a planned contact purge operation.
Attributes:
unpinned_keys: Public keys of contacts that will be removed.
pinned_count: Number of pinned contacts that will be kept.
total_count: Total number of contacts on the device.
"""
unpinned_keys: List[str]
pinned_count: int
total_count: int
@property
def unpinned_count(self) -> int:
"""Number of contacts that will be removed."""
return len(self.unpinned_keys)
class ContactCleanerService:
"""Business logic for bulk-deleting unpinned contacts.
Args:
pin_store: PinStore instance for checking pin status.
"""
def __init__(self, pin_store: PinStore) -> None:
self._pin_store = pin_store
def get_purge_stats(self, contacts: Dict) -> PurgeStats:
"""Calculate which contacts would be purged.
Iterates all contacts and separates them into pinned (kept)
and unpinned (to be removed).
Args:
contacts: Contacts dict from SharedData snapshot
(``{pubkey: contact_dict}``).
Returns:
PurgeStats with the list of unpinned keys and counts.
"""
pinned_keys: Set[str] = self._pin_store.get_pinned()
unpinned_keys: List[str] = []
for pubkey in contacts:
if pubkey not in pinned_keys:
unpinned_keys.append(pubkey)
return PurgeStats(
unpinned_keys=unpinned_keys,
pinned_count=len(contacts) - len(unpinned_keys),
total_count=len(contacts),
)