mirror of
https://github.com/pe1hvh/meshcore-gui.git
synced 2026-10-31 01:42:04 +01:00
WHAT - route_page: _default_reply_channel() derives the reply select default from msg.channel instead of the first entry in the channel list - models: new Message.date field, now_date() and display_timestamp(); format_line() and incoming()/outgoing() use them - message_archive: persist "date" alongside "time" and "timestamp_utc" - room_server_panel + route_page info header use display_timestamp() - VERSION 1.22.2 -> 1.22.3 WHY The route page exists to show one specific message, so that message — not the ordering of the channel list — is the correct source for the reply default. The date could not be fixed at the render site because Message had no date at all: now_timestamp() yields HH:MM:SS and the date lived only as timestamp_utc inside the archive layer, unread by from_dict(). A first-class field plus a single formatting helper fixes the cause and keeps the format in one place. NOTES No breaking changes. The archive schema gains one additive field; pre-1.22.3 entries have their date derived from timestamp_utc (converted to local time) and fall back to time-only when absent. Message.incoming() gained an optional keyword-only date parameter. Message display lines are ~11 characters wider.
3.0 KiB
3.0 KiB
ADR-002: Protocol-interfaces (typing.Protocol) i.p.v. abc.ABC
Status: Accepted — 2026-02
Context
De applicatie heeft één centrale, thread-safe data-store (SharedData)
die door meerdere consumenten wordt gebruikt:
BLEWorkerschrijft device-info, contacten, channels, messages en RX-log entries.DashboardPageleest snapshots en plaatst commands.RouteBuilderzoekt contacten op prefix.RoutePageenArchivePagedoen beide read en lookup.- Widget-klassen ontvangen alleen plain dicts en callbacks.
Vóór de SOLID-refactor importeerden al deze consumenten direct
shared_data.SharedData. Dat:
- Verstopte dat de meeste consumenten maar een fractie van de 15+ publieke methoden gebruiken (ISP-violation).
- Maakte testen lastig — een test-stub moest alle methoden bieden, ook de niet-gebruikte.
- Bond consumenten aan de concrete implementatie i.p.v. aan het contract dat ze nodig hebben (DIP-violation).
Decision
Definieer per consument een smal Protocol-contract in protocols.py;
consumenten typen tegen het contract, niet tegen SharedData.
Geïntroduceerde Protocols:
| Protocol | Consument | Methoden |
|---|---|---|
SharedDataWriter |
BLEWorker |
10–15 (write + lookup) |
SharedDataReader |
DashboardPage |
4–6 (snapshot + commands) |
ContactLookup |
RouteBuilder |
1 |
SharedDataReadAndLookup |
RoutePage, ArchivePage |
Reader + Lookup |
CommandSink |
MeshBot, GUI-pages |
put_command |
SharedData blijft één concrete klasse die alle Protocols
structureel implementeert (zonder from typing import Protocol-
inheritance). De composition root (meshcore_gui.py) is de enige
plek die de concrete klasse kent.
typing.Protocol is gekozen boven abc.ABC omdat:
| Aspect | abc.ABC (nominal) |
typing.Protocol (structural) |
|---|---|---|
| Subclassing nodig | ja | nee |
| Duck typing | nee | ja |
| Test-stubs | moeten erven | hoeven alleen methoden te hebben |
Consequences
Plus
- Elke consument ziet alleen wat hij nodig heeft (ISP).
- Test-stubs zijn lichtgewicht: alleen de methoden van het smalle contract.
- Refactoring van
SharedData-internen raakt consumenten niet zolang de Protocol-signatures stabiel blijven (DIP). - Widget-klassen hebben nul kennis van
SharedData— ze krijgen plain dicts en callbacks.
Min
typing.Protocolwerkt vanaf Python 3.8 — geen probleem in deze codebase (3.10+).- Vijf interface-classes zijn extra onderhoud bij echt brede signature- wijzigingen. Drempel voor nieuwe Protocols: alleen wanneer een consument een meetbaar smaller contract heeft, niet preventief.
Niet introduceren
- Geen
abc.ABCmet@abstractmethodvoor deze use-case. De Protocol- variant levert hetzelfde type-veiligheidsniveau zonder verplichte subclassing.
References
SOLID_ANALYSIS.mdmeshcore_gui/core/protocols.pymeshcore_gui/core/shared_data.py- PEP 544 — Protocols: Structural subtyping