Archived
86 lines
3.6 KiB
Markdown
86 lines
3.6 KiB
Markdown
# DynaLab Architecture and Naming
|
|
|
|
## Goals
|
|
|
|
DynaLab accepts live data from multiple connector implementations and presents it in a
|
|
desktop UI. The architecture keeps transport code, application state, and Dear PyGui
|
|
code independent so that adding a connector or UI feature does not require edits across
|
|
unrelated modules.
|
|
|
|
## Data Flow
|
|
|
|
```text
|
|
connector session -> ConnectorEvent queue -> UI feature controller -> feature state -> view
|
|
```
|
|
|
|
The connector thread owns sockets, handshakes, and heartbeat bookkeeping. It communicates
|
|
with the main thread only through immutable events. The main thread owns application state
|
|
and all Dear PyGui calls.
|
|
|
|
## Package Layout
|
|
|
|
```text
|
|
src/dynalab/
|
|
app.py composition, lifecycle, frame loop, shutdown
|
|
state.py focused application, signal, and recording state
|
|
connectors/
|
|
events.py typed connector-to-application events
|
|
protocol_server.py asyncio server and connector sessions
|
|
ui/
|
|
shell.py top-level window, menus, and feature navigation
|
|
loading/ loading view and tags
|
|
errors/ error modal view and tags
|
|
live_data/ gauge view, event controller, and tags
|
|
recording/ recording view, controller, presenter, and tags
|
|
```
|
|
|
|
Feature folders own their widgets, tags, callbacks, and model-to-widget synchronization.
|
|
Avoid global tag collections and modules named after generic implementation techniques,
|
|
such as `windows`, `routines`, or `render`.
|
|
|
|
## Naming
|
|
|
|
- `build_*` creates widgets once.
|
|
- `refresh_*` synchronizes existing widgets from state.
|
|
- `on_*` is a thin Dear PyGui callback.
|
|
- `handle_*` processes an application event or user intent.
|
|
- `start_*` and `stop_*` control service lifecycle.
|
|
- `load_*` and `save_*` access persistent storage.
|
|
- `*_tag` functions generate dynamic Dear PyGui identifiers.
|
|
- `*State` holds mutable state owned by the main thread.
|
|
- `*Event` is immutable communication across a boundary.
|
|
|
|
Tags are feature-qualified strings, for example `recording.dialog` and
|
|
`live_data.gauge.<uuid>`. Display labels are never parsed to recover domain identifiers;
|
|
features maintain explicit label-to-ID mappings.
|
|
|
|
## Ownership Rules
|
|
|
|
- Only the connector thread accesses streams, sessions, and heartbeat timestamps.
|
|
- Only the main thread mutates `ApplicationState` and calls Dear PyGui.
|
|
- `app.py` composes services and dispatches events; it does not build feature widgets.
|
|
- Controllers translate intent or events into state changes and view operations.
|
|
- Views construct widgets and contain no connector logic.
|
|
- Presenters format state for existing widgets and contain no networking logic.
|
|
|
|
## Adding a Connector
|
|
|
|
A connector adapts its transport into the event types in `connectors/events.py`. It must
|
|
not mutate application state or invoke Dear PyGui. Connector-specific handshake and
|
|
framing stay within its own server/session implementation.
|
|
|
|
## Adding a UI Feature
|
|
|
|
Create a folder under `ui/` containing only the pieces the feature needs. A typical
|
|
feature has `view.py`, `controller.py`, `presenter.py`, and `tags.py`; small features may
|
|
use fewer files. Register its top-level view in `ui/shell.py` and dispatch relevant events
|
|
from the application loop.
|
|
|
|
## Testing Boundaries
|
|
|
|
- Test event and state behavior without importing Dear PyGui.
|
|
- Test controllers with a stubbed gauge or Dear PyGui adapter.
|
|
- Test connector sessions with local asyncio streams or protocol fakes.
|
|
- Keep manual connector simulators under `test/` or move them to `tools/` when the
|
|
automated integration suite is introduced.
|