mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-04 00:26:07 +02:00
docs: Update documentation for 145 files
Generated by AurionDocs
Job ID: 934f8c39-8082-4942-8d17-72ed8f5f8d50
Source commit: 40aea9a
This commit is contained in:
@@ -1,99 +1,93 @@
|
||||
# Architecture — HueByte/EchoHub
|
||||
|
||||
> *Auto-synthesized from 598 documented symbols across 128 files on `master`.*
|
||||
> *Auto-synthesized from 617 documented symbols across 128 files on `master`.*
|
||||
|
||||
## Topic Guides
|
||||
|
||||
Deep-dives into cross-cutting concerns synthesized from the per-symbol corpus.
|
||||
|
||||
- [API client and authentication](api-client-authentication.md) — How the EchoHub client authenticates with the server, handles tokens, and defines authentication DTOs.
|
||||
- [Theming and UI color management](ui-theming.md) — Representing themes, color palettes, and runtime theme application.
|
||||
- [Real-time connection management](real-time-connection.md) — Managing the SignalR hub connection lifecycle and connection state.
|
||||
- [Encryption and room key management](encryption-roomkeys.md) — End-to-end encryption plumbing and secure handling of per-channel room keys.
|
||||
- [Command handling](command-handling.md) — Slash-command parsing and dispatching command actions from UI and orchestrator.
|
||||
- [Attachments and file transfers](attachments-transfer.md) — Staging and sending attachments in chat messages and coordinating outbound attachments.
|
||||
- [Clipboard utilities](clipboard-tools.md) — Helpers for clipboard interactions: files and images.
|
||||
- [Update management](update-management.md) — Data and update flow: backup prior to updates and update checks.
|
||||
- [API client authentication](api-client-authentication.md) — How the client authenticates with the server, including login, token refresh, and token usage across API calls.
|
||||
- [Real-time connection and messaging](real-time-connection.md) — How the client establishes and maintains a real-time connection to the server and handles channel messaging.
|
||||
- [UI theming and theme management](ui-theming.md) — Theme data models and the system that loads, stores, and applies themes to the UI.
|
||||
- [Slash command handling](command-handling.md) — Parsing and executing user commands entered as slash commands in chat.
|
||||
- [Attachments transfer](attachments-transfer.md) — Attachment handling for staged files and outgoing attachments in chat messages.
|
||||
- [Clipboard utilities](clipboard-tools.md) — Clipboard helpers for files and images used in the UI.
|
||||
- [Update management](update-management.md) — Checking for updates and backing up state related to updates.
|
||||
- [Encryption and room keys](encryption-roomkeys.md) — Client-side encryption and per-room key protection for secure messaging.
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme':'base','themeVariables':{'background':'#faf7ef','primaryColor':'#f0e2c2','primaryTextColor':'#1f2840','primaryBorderColor':'#8a7548','secondaryColor':'#d9efec','secondaryBorderColor':'#1d8a80','secondaryTextColor':'#1f2840','tertiaryColor':'#f2ebd8','tertiaryBorderColor':'#8a7548','tertiaryTextColor':'#1f2840','lineColor':'#1d8a80','titleColor':'#1f2840','fontSize':'14px','edgeLabelBackground':'#faf7ef','clusterBkg':'#f2ebd8','clusterBorder':'#8a7548','actorBkg':'#f0e2c2','actorBorder':'#8a7548','actorTextColor':'#1f2840','actorLineColor':'#8a7548','signalColor':'#1d8a80','signalTextColor':'#1f2840','activationBkgColor':'#d9efec','activationBorderColor':'#1d8a80','noteBkgColor':'#f2ebd8','noteBorderColor':'#8a7548','noteTextColor':'#1f2840','labelBoxBkgColor':'#f0e2c2','labelBoxBorderColor':'#8a7548','labelTextColor':'#1f2840','transitionColor':'#1d8a80','transitionLabelColor':'#1f2840','stateLabelColor':'#1f2840','altBackground':'#f2ebd8'}}}%%
|
||||
flowchart TB
|
||||
n0["src/EchoHub.Core/DTOs · ChatService (11 files)"]
|
||||
n1["src/EchoHub.Client/Services · AppOrchestrator (14 files)"]
|
||||
n2["src/EchoHub.Client/UI · MainWindow (18 files)"]
|
||||
n3["src/EchoHub.Core/DTOs · ApiClient (10 files)"]
|
||||
n4["src/EchoHub.Server · User (12 files)"]
|
||||
n5["src/EchoHub.Core/DTOs · ChannelService (7 files)"]
|
||||
n6["src/EchoHub.Server · Program (12 files)"]
|
||||
n7["src/EchoHub.Client/Config (5 files)"]
|
||||
n8["src/EchoHub.Client/UI · Channel (4 files)"]
|
||||
n0["src/EchoHub.Client/Services · AppOrchestrator (22 files)"]
|
||||
n1["src/EchoHub.Client/UI · MainWindow (18 files)"]
|
||||
n2["src/EchoHub.Core/DTOs · ApiClient (10 files)"]
|
||||
n3["src/EchoHub.Server · User (13 files)"]
|
||||
n4["src/EchoHub.Core/DTOs · ChannelService (7 files)"]
|
||||
n5["src/EchoHub.Server · Program (12 files)"]
|
||||
n6["src/EchoHub.Core/Contracts · ChannelDto (6 files)"]
|
||||
n7["src/EchoHub.Client/UI · Channel (4 files)"]
|
||||
n8["src/EchoHub.Client/UI · UserStatus (3 files)"]
|
||||
n9["src/EchoHub.Core/DTOs · ChannelsController (2 files)"]
|
||||
n10["src/EchoHub.Core/Models (5 files)"]
|
||||
n0 -->|5| n10
|
||||
n0 -->|6| n4
|
||||
n0 -->|8| n1
|
||||
n0 -->|4| n10
|
||||
n0 -->|5| n2
|
||||
n0 -->|9| n3
|
||||
n0 -->|4| n5
|
||||
n0 -->|7| n6
|
||||
n0 -->|4| n7
|
||||
n0 -->|7| n7
|
||||
n0 -->|6| n8
|
||||
n1 -->|14| n0
|
||||
n1 -->|5| n2
|
||||
n1 -->|4| n0
|
||||
n1 -->|4| n3
|
||||
n1 -->|6| n4
|
||||
n1 -->|8| n7
|
||||
n1 -->|5| n8
|
||||
n2 -->|8| n0
|
||||
n2 -->|4| n4
|
||||
n3 -->|6| n0
|
||||
n3 -->|8| n4
|
||||
n3 -->|4| n9
|
||||
n4 -->|9| n3
|
||||
n5 -->|7| n0
|
||||
n5 -->|4| n4
|
||||
n5 -->|5| n8
|
||||
n6 -->|6| n0
|
||||
n6 -->|7| n4
|
||||
n2 -->|5| n0
|
||||
n2 -->|9| n3
|
||||
n2 -->|4| n9
|
||||
n3 -->|9| n2
|
||||
n4 -->|4| n3
|
||||
n4 -->|5| n6
|
||||
n4 -->|5| n7
|
||||
n5 -->|7| n3
|
||||
n5 -->|4| n6
|
||||
n6 -->|9| n0
|
||||
n6 -->|4| n7
|
||||
n6 -->|4| n8
|
||||
n9 -->|4| n3
|
||||
n9 -->|4| n4
|
||||
n9 -->|4| n5
|
||||
```
|
||||
|
||||
## System Overview
|
||||
EchoHub is a client/server chat system that exposes an HTTP API implemented by multiple controllers and a realtime messaging surface via a hub (ChatHub), with client-side components for connecting and playback. The server hosts application services and background workers (e.g. file cleanup, data migrations) that implement business logic and maintenance tasks. Persistent state is stored in the Entity Framework DbContext (EchoHubDbContext) which is used by controllers and services. Clients interact with the server through the ApiClient and implement messaging callbacks against the IEchoHubClient contract.
|
||||
This repository implements a chat and file-sharing server with a desktop client: server-side controllers expose an HTTP API (e.g. `AuthController`, `UsersController`, `FilesController`) while a real-time hub (`ChatHub`) handles live messaging and presence. Background workers and maintenance tasks run as hosted services (for example `FileCleanupService` and `DataMigrationService`), and persistent state is stored in the Entity Framework DbContext (`EchoHubDbContext`). The desktop client communicates with the server via an API client (`ApiClient`) and includes local services like audio playback and message encryption.
|
||||
|
||||
## Key Components
|
||||
**Controllers** — HTTP API surface for client and administrative actions. Implemented by [`AuthController`](../Code/src/EchoHub.Server/Controllers/AuthController.cs.md), [`ChannelsController`](../Code/src/EchoHub.Server/Controllers/ChannelsController.cs.md), [`FilesController`](../Code/src/EchoHub.Server/Controllers/FilesController.cs.md), [`InvitesController`](../Code/src/EchoHub.Server/Controllers/InvitesController.cs.md), [`ModerationController`](../Code/src/EchoHub.Server/Controllers/ModerationController.cs.md), [`ServerController`](../Code/src/EchoHub.Server/Controllers/ServerController.cs.md), [`UsersController`](../Code/src/EchoHub.Server/Controllers/UsersController.cs.md).
|
||||
**Controllers** — HTTP API surface for authentication, user and channel management, file operations and moderation. Implemented by [`AuthController`](../Code/src/EchoHub.Server/Controllers/AuthController.cs.md), [`ChannelsController`](../Code/src/EchoHub.Server/Controllers/ChannelsController.cs.md), [`FilesController`](../Code/src/EchoHub.Server/Controllers/FilesController.cs.md), [`InvitesController`](../Code/src/EchoHub.Server/Controllers/InvitesController.cs.md), [`ModerationController`](../Code/src/EchoHub.Server/Controllers/ModerationController.cs.md), [`ServerController`](../Code/src/EchoHub.Server/Controllers/ServerController.cs.md), [`UsersController`](../Code/src/EchoHub.Server/Controllers/UsersController.cs.md).
|
||||
|
||||
**Services** — Application services implement business logic, file handling, background tasks, and utilities used by controllers and hubs. Implemented by [`ChannelService`](../Code/src/EchoHub.Server/Services/ChannelService.cs.md), [`ChatService`](../Code/src/EchoHub.Server/Services/ChatService.cs.md), [`FileStorageService`](../Code/src/EchoHub.Server/Services/FileStorageService.cs.md), [`FileCleanupService`](../Code/src/EchoHub.Server/Services/FileCleanupService.cs.md), and supporting utilities such as [`AsciiBannerService`](../Code/src/EchoHub.Core/Services/AsciiBannerService.cs.md), [`AudioPlaybackService`](../Code/src/EchoHub.Client/Services/AudioPlaybackService.cs.md), [`ClientEncryptionService`](../Code/src/EchoHub.Client/Services/ClientEncryptionService.cs.md), and [`DataMigrationService`](../Code/src/EchoHub.Server/Setup/DataMigrationService.cs.md).
|
||||
**Services** — Core application logic and long-running background tasks, including channel/chat handling, file storage/cleanup, migrations, and utility services used by client and server. Implemented by [`ChannelService`](../Code/src/EchoHub.Server/Services/ChannelService.cs.md), [`ChatService`](../Code/src/EchoHub.Server/Services/ChatService.cs.md), [`FileCleanupService`](../Code/src/EchoHub.Server/Services/FileCleanupService.cs.md), [`FileStorageService`](../Code/src/EchoHub.Server/Services/FileStorageService.cs.md), [`DataMigrationService`](../Code/src/EchoHub.Server/Setup/DataMigrationService.cs.md), [`AsciiBannerService`](../Code/src/EchoHub.Core/Services/AsciiBannerService.cs.md), [`AudioPlaybackService`](../Code/src/EchoHub.Client/Services/AudioPlaybackService.cs.md), [`ClientEncryptionService`](../Code/src/EchoHub.Client/Services/ClientEncryptionService.cs.md).
|
||||
|
||||
**Workers / Hubs** — Real-time messaging and hosted work are provided by SignalR-style hubs and background services; the primary realtime hub is implemented by [`ChatHub`](../Code/src/EchoHub.Server/Hubs/ChatHub.cs.md).
|
||||
**Workers/Hubs** — Real-time messaging and presence channel for live client-server communication. Implemented by [`ChatHub`](../Code/src/EchoHub.Server/Hubs/ChatHub.cs.md).
|
||||
|
||||
**Data Access** — Persistent application state is managed via the Entity Framework DbContext used across services and controllers: [`EchoHubDbContext`](../Code/src/EchoHub.Server/Data/EchoHubDbContext.cs.md).
|
||||
**Repositories / Data Access** — Persistence layer backed by Entity Framework Core; where application state is stored. Implemented by [`EchoHubDbContext`](../Code/src/EchoHub.Server/Data/EchoHubDbContext.cs.md).
|
||||
|
||||
**External Clients** — Client-side communication with the server is encapsulated by an HTTP/real-time client and the client contract. Implemented by [`ApiClient`](../Code/src/EchoHub.Client/Services/ApiClient.cs.md) and the client interface [`IEchoHubClient`](../Code/src/EchoHub.Core/Contracts/IEchoHubClient.cs.md).
|
||||
|
||||
**Configuration** — Server runtime options and feature flags are defined in option classes used by services and integrations. Implemented by [`IrcOptions`](../Code/src/EchoHub.Server.Irc/IrcOptions.cs.md), [`ServerLogsOptions`](../Code/src/EchoHub.Server/Config/ServerLogsOptions.cs.md), [`SpamOptions`](../Code/src/EchoHub.Server/Config/SpamOptions.cs.md), [`StatsOptions`](../Code/src/EchoHub.Server/Config/StatsOptions.cs.md).
|
||||
|
||||
**IRC integration** — IRC-related command handling and service wiring are provided by IRC support classes and extensions. Implemented by [`IrcServiceExtensions`](../Code/src/EchoHub.Server.Irc/IrcServiceExtensions.cs.md) and [`IrcCommandHandler`](../Code/src/EchoHub.Server.Irc/IrcCommandHandler.cs.md).
|
||||
|
||||
**Core Contracts** — Domain and integration interfaces that define service boundaries and encryption abstractions. Implemented by [`IChannelService`](../Code/src/EchoHub.Core/Contracts/IChannelService.cs.md), [`IChatService`](../Code/src/EchoHub.Core/Contracts/IChatService.cs.md), [`IMessageEncryptionService`](../Code/src/EchoHub.Core/Contracts/IMessageEncryptionService.cs.md), and [`IUserService`](../Code/src/EchoHub.Core/Contracts/IUserService.cs.md).
|
||||
**External integrations** — Client and protocol integrations used to communicate with the server or external systems (IRC). Implemented by [`ApiClient`](../Code/src/EchoHub.Client/Services/ApiClient.cs.md), [`IrcServiceExtensions`](../Code/src/EchoHub.Server.Irc/IrcServiceExtensions.cs.md), [`IrcCommandHandler`](../Code/src/EchoHub.Server.Irc/IrcCommandHandler.cs.md), [`IrcOptions`](../Code/src/EchoHub.Server.Irc/IrcOptions.cs.md).
|
||||
|
||||
## Component Map
|
||||
|
||||
*Subsystems below are structural clusters detected from the dependency graph — groups of symbols more densely wired to each other than to the rest of the codebase.*
|
||||
|
||||
- **src/EchoHub.Client/Services · AppOrchestrator** — 22 documented files
|
||||
- **src/EchoHub.Client/UI · MainWindow** — 18 documented files
|
||||
- **src/EchoHub.Client/Services · AppOrchestrator** — 14 documented files
|
||||
- **src/EchoHub.Server · User** — 13 documented files
|
||||
- **src/EchoHub.Server · Program** — 12 documented files
|
||||
- **src/EchoHub.Server · User** — 12 documented files
|
||||
- **src/EchoHub.Core/DTOs · ChatService** — 11 documented files
|
||||
- **src/EchoHub.Core/DTOs · ApiClient** — 10 documented files
|
||||
- **src/EchoHub.Core/DTOs · ChannelService** — 7 documented files
|
||||
- **src/EchoHub.Client/Config** — 5 documented files
|
||||
- **src/EchoHub.Core/Contracts · ChannelDto** — 6 documented files
|
||||
- **src/EchoHub.Core/Models** — 5 documented files
|
||||
- **src/EchoHub.Client/Themes** — 4 documented files
|
||||
- **src/EchoHub.Client/UI · Channel** — 4 documented files
|
||||
- **src/EchoHub.Server · ServerLogsStreamService** — 4 documented files
|
||||
- *…and 11 more subsystem folders*
|
||||
- **src/EchoHub.Client/Services · UpdateBackupService** — 3 documented files
|
||||
- *…and 10 more subsystem folders*
|
||||
|
||||
### Components by Role
|
||||
|
||||
@@ -144,4 +138,4 @@ EchoHub is a client/server chat system that exposes an HTTP API implemented by m
|
||||
- `IUserService` — `src/EchoHub.Core/Contracts/IUserService.cs`
|
||||
|
||||
---
|
||||
*Generated by Aurion on 2026-07-23 05:56:01 UTC*
|
||||
*Generated by AurionDocs on 2026-07-23 09:35:48 UTC*
|
||||
|
||||
@@ -2,28 +2,28 @@
|
||||
|
||||
> *A curated reading path through this codebase for new contributors. Work through the stops in order.*
|
||||
|
||||
This reading path gets a new team member from zero to a place where they can run the app and make a small contribution. Read the short architecture overview first to understand the system's collaboration pattern, then inspect the entry points to see how the pieces are wired; from there follow a single request through the ingress layer into the services and state so you can start making safe, focused changes.
|
||||
This onboarding reading path gets a new contributor from zero to the point where they can make a small, safe change in the EchoHub codebase. Read these stops in order: start with the generated architecture overview to understand the system shape, open the entry points to see how programs and the server host are configured, follow a request through the ingress layer into the business services, and finish by locating the conventional folders where you should add new controllers, services, or hubs.
|
||||
|
||||
## Stop 1: What this project is
|
||||
At this stop skim the auto-generated system description to learn the overall collaboration pattern and where state is owned; the document also highlights the main components and their responsibilities. Start by opening [Architecture](Architecture.md) to pick up the big-picture boundaries and the primary data stores so later code-level reads map to that conceptual model.
|
||||
At this stop you will skim the auto-generated system overview to learn the high-level collaboration pattern, the main components, and where persistent state is kept. Read the [Architecture](Architecture.md) document to pick up the generated dependency map and the summary descriptions the project uses to show which services, APIs, and storage pieces are primary.
|
||||
|
||||
## Stop 2: Where execution starts
|
||||
Read the two Program entry points to see how the client and server are bootstrapped, which early runtime concerns are wired, and what cross-cutting services are registered. Inspect the client [Program.cs](../Code/src/EchoHub.Client/Program.cs.md) to see startup tasks like rollback handling, permission checks, configuration provisioning, logging setup, and PATH preparation; then open the server [Program.cs](../Code/src/EchoHub.Server/Program.cs.md) to see how configuration, logging, data access, authentication, service registrations and the ASP.NET Core pipeline are arranged.
|
||||
This stop shows how the client and server processes are bootstrapped so you can see dependency injection, one-time setup, and host configuration before diving deeper. Open the client [Program.cs](../Code/src/EchoHub.Client/Program.cs.md) to see its CLI handling (the --rollback flag), best-effort Unix execute-permission check, and how it provisions configuration; then inspect the server [Program.cs](../Code/src/EchoHub.Server/Program.cs.md) to see the call to FirstRunSetup.EnsureAppSettings(), the bootstrap logger configuration, and the code path that starts the ASP.NET Core host.
|
||||
|
||||
## Stop 3: Where requests come in
|
||||
Trace a single end-to-end interaction by following the client command entry, the server HTTP controller, and the real-time hub used for chat. Read the client [CommandHandler.cs](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md) to learn how user commands are emitted, then the server [UsersController.cs](../Code/src/EchoHub.Server/Controllers/UsersController.cs.md) to see the API surface that handles user-related requests, and finally the SignalR [ChatHub.cs](../Code/src/EchoHub.Server/Hubs/ChatHub.cs.md) to understand real-time message routing and authorization checks.
|
||||
Trace an incoming action end-to-end by reading the client-side command processor and the server ingress points that handle requests and real-time messages. Examine the client [CommandHandler.cs](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md) to learn how client commands are dispatched, the [UsersController](../Code/src/EchoHub.Server/Controllers/UsersController.cs.md) to see the HTTP API surface exposed by an [ApiController], and the real-time path via the authorized [ChatHub](../Code/src/EchoHub.Server/Hubs/ChatHub.cs.md) to understand how authenticated SignalR messages are handled.
|
||||
|
||||
## Stop 4: Where the business logic lives
|
||||
Drill into the substantive services that perform work for the client: network calls, audio, encryption, and backup orchestration. Read the client [ApiClient.cs](../Code/src/EchoHub.Client/Services/ApiClient.cs.md) that manages HTTP requests and disposal, the [AudioPlaybackService.cs](../Code/src/EchoHub.Client/Services/AudioPlaybackService.cs.md) that handles playback concerns, the [ClientEncryptionService.cs](../Code/src/EchoHub.Client/Services/ClientEncryptionService.cs.md) which implements IMessageEncryptionService for message protection, the [NotificationSoundService.cs](../Code/src/EchoHub.Client/Services/NotificationSoundService.cs.md) for user-facing alerts, and the [UpdateBackupService.cs](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) which is involved in BackupInfo serialization and backup flows.
|
||||
Follow the workhorses invoked by the ingress layer: the HTTP/SignalR handlers call into these services to perform the real operations. Read the client-side [ApiClient](../Code/src/EchoHub.Client/Services/ApiClient.cs.md) (a disposable HTTP client wrapper), [AudioPlaybackService](../Code/src/EchoHub.Client/Services/AudioPlaybackService.cs.md) for playback responsibilities, [ClientEncryptionService](../Code/src/EchoHub.Client/Services/ClientEncryptionService.cs.md) which implements IMessageEncryptionService for message-level encryption, [NotificationSoundService](../Code/src/EchoHub.Client/Services/NotificationSoundService.cs.md) for UI sounds, and [UpdateBackupService](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) which participates in backup serialization (JsonSerializable for BackupInfo).
|
||||
|
||||
## Stop 5: Where state lives
|
||||
Look at the code that owns connection state, persisted backups, and the commands that drive application state changes. Revisit [CommandHandler.cs](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md) to understand the commands that mutate client state, inspect [ConnectionManager.cs](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) for the lifecycle and disposal of live connections, open [UpdateBackupService.cs](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) to see how BackupInfo is serialized for persistence, and check the UI [ConnectDialog.cs](../Code/src/EchoHub.Client/UI/Dialogs/ConnectDialog.cs.md) to learn where connection information is captured and handed off to the connection manager.
|
||||
Identify the concrete types that own runtime and persisted state so you know what to change when you add data or lifecycle concerns. Revisit [CommandHandler.cs](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md) for command-driven client state transitions, inspect the connection lifecycle in the internal sealed [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) (IAsyncDisposable), see how UI-driven folder selection is encapsulated in the static [NativeFolderPicker](../Code/src/EchoHub.Client/Services/NativeFolderPicker.cs.md), and review [UpdateBackupService](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) for how BackupInfo is serialized for persistence.
|
||||
|
||||
## Stop 6: Where to put new code
|
||||
Use the conventional places represented by controllers, server services, and hubs when deciding where to add features or fixes. For HTTP and auth-related endpoints add or update controllers like [AuthController.cs](../Code/src/EchoHub.Server/Controllers/AuthController.cs.md); server-side domain operations belong in services such as [ChannelService.cs](../Code/src/EchoHub.Server/Services/ChannelService.cs.md) (which implements IChannelService); and real-time or cross-connection behavior belongs in the SignalR hub [ChatHub.cs](../Code/src/EchoHub.Server/Hubs/ChatHub.cs.md).
|
||||
Learn the conventional locations to add controllers, services, and hubs by looking at existing examples in the server surface. The server exposes authentication endpoints in [AuthController](../Code/src/EchoHub.Server/Controllers/AuthController.cs.md) (an [ApiController]), long-running or domain behavior belongs in services such as [ChannelService](../Code/src/EchoHub.Server/Services/ChannelService.cs.md) which implements IChannelService, and real-time endpoints belong in hubs like the authorized [ChatHub](../Code/src/EchoHub.Server/Hubs/ChatHub.cs.md).
|
||||
|
||||
## Next steps
|
||||
Run the app locally: read the two [Program.cs](../Code/src/EchoHub.Server/Program.cs.md) and [Program.cs](../Code/src/EchoHub.Client/Program.cs.md) files to learn how to start the server and client, then launch both projects and use the Connect dialog to exercise the [ChatHub](../Code/src/EchoHub.Server/Hubs/ChatHub.cs.md) path.
|
||||
Try this as your first contribution: read the [Architecture](Architecture.md) overview, run the dev server from the server [Program.cs](../Code/src/EchoHub.Server/Program.cs.md) entry point, and make a tiny change (for example, add a log line in [ChatHub](../Code/src/EchoHub.Server/Hubs/ChatHub.cs.md)) to verify your local build and run loop.
|
||||
|
||||
---
|
||||
*Synthesised by Aurion on 2026-07-23 05:54:49 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:34:36 UTC*
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
> *Workflow template auto-derived from 7 existing exemplar(s).*
|
||||
|
||||
This template describes how to add a new HTTP controller to the server: reach for this pattern when you need a new API surface implemented as an [ApiController] class that exposes routes and actions. Use the reference controller below as the concrete shape to copy (attributes, base class, constructor injection, and action patterns), and consult the existing examples to match naming and placement.
|
||||
Adding a new controller in this codebase means adding an ASP.NET Core API controller class under src/EchoHub.Server/Controllers that follows the shape shown in the reference FilesController. A developer would reach for this pattern when they need to expose a new HTTP API surface: controllers are decorated with controller attributes, derive from ControllerBase, and implement actions (HttpGet/HttpPost/etc.) that the framework routes to.
|
||||
|
||||
## Reference implementation
|
||||
|
||||
Real code from src/EchoHub.Server/Controllers/FilesController.cs that you can model a new controller on:
|
||||
|
||||
```csharp
|
||||
[ApiController]
|
||||
[Route("api/files")]
|
||||
@@ -69,11 +71,11 @@ public class FilesController : ControllerBase
|
||||
|
||||
## Where it lives
|
||||
|
||||
Controllers in this codebase are placed under src/EchoHub.Server/Controllers, and exemplar files use names such as AuthController.cs, ChannelsController.cs, FilesController.cs, InvitesController.cs, ModerationController.cs, ServerController.cs, and UsersController.cs with corresponding public classes named AuthController, ChannelsController, FilesController, InvitesController, ModerationController, ServerController, and UsersController. Use that same folder and naming pattern when adding a new controller file.
|
||||
Controllers in this project appear under src/EchoHub.Server/Controllers and use the Controller naming form (for example FilesController, AuthController, ChannelsController, etc.). Each controller is a class that carries the [ApiController] attribute and derives from ControllerBase; routing is provided with [Route("...")] on the class and action attributes like [HttpGet] on methods.
|
||||
|
||||
## Wiring
|
||||
|
||||
A specific registration site for controllers was not detected in the symbol graph provided. Inspect the existing controllers listed below to see how they are referenced in the project and to follow the same runtime usage patterns used by the application.
|
||||
A registration/composition site for controllers was not detected in the provided wiring list. To see how controllers are used and how their action surface looks in practice, inspect the existing controllers listed in "Existing examples" below and model your new controller on those files.
|
||||
|
||||
## Existing examples
|
||||
|
||||
@@ -86,4 +88,4 @@ A specific registration site for controllers was not detected in the symbol grap
|
||||
- [`UsersController`](../../Code/src/EchoHub.Server/Controllers/UsersController.cs.md)
|
||||
|
||||
---
|
||||
*Synthesised by Aurion on 2026-07-23 05:55:15 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:35:00 UTC*
|
||||
|
||||
@@ -2,14 +2,10 @@
|
||||
|
||||
> *Workflow template auto-derived from 8 existing exemplar(s).*
|
||||
|
||||
Adding a new service
|
||||
|
||||
When you need to encapsulate a piece of server functionality—either a long-lived background job or an application service consumed by controllers and other services—you add a new service type in this codebase. Use the existing service types in src/EchoHub.Server/Services as your models: pick a clear name that ends with "Service", place the source alongside the other services, and wire it up where services are registered.
|
||||
When you need to add a new application service or a long-running background task to EchoHub.Server, add a new type alongside the existing services and register it where services are composed. The examples in src/EchoHub.Server/Services show both ordinary services and BackgroundService-based hosted tasks; model a new instance on those concrete types and then wire it into the application startup.
|
||||
|
||||
## Reference implementation
|
||||
|
||||
Real code from `src/EchoHub.Server/Services/MuteExpirationService.cs` that a new instance can be modelled on:
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// Background service that periodically unmutes users whose timed mute has expired.
|
||||
@@ -73,11 +69,11 @@ public sealed class MuteExpirationService : BackgroundService
|
||||
|
||||
## Where it lives
|
||||
|
||||
Service source files are placed in src/EchoHub.Server/Services. Existing service types include names such as ChannelService, ChatService, FileCleanupService, FileStorageService, LinkEmbedService, MessageEncryptionService, MuteExpirationService, and ServerDirectoryService; each service file in that folder defines the corresponding type (for example, public class ChannelService : IChannelService and public sealed class FileCleanupService : BackgroundService). Follow the same placement and name your new type with a Service suffix so it sits alongside these exemplars.
|
||||
Create the new service type under src/EchoHub.Server/Services. The repository contains multiple service types in that folder whose type names end with "Service", for example ChannelService, ChatService, FileCleanupService, FileStorageService, LinkEmbedService, MessageEncryptionService, MuteExpirationService, and ServerDirectoryService.
|
||||
|
||||
## Wiring
|
||||
|
||||
Detected registration/composition site: src/EchoHub.Server/Program.cs. Inspect that file to see how services from src/EchoHub.Server/Services are registered and how hosted/background services are added to the application; new service types should be wired there consistent with the existing registrations.
|
||||
Registration and composition of services was detected in src/EchoHub.Server/Program.cs. Add the new service's registration in that file alongside the existing service registrations; inspect src/EchoHub.Server/Program.cs and the exemplars to follow the same wiring approach used for other services.
|
||||
|
||||
## Existing examples
|
||||
|
||||
@@ -91,4 +87,4 @@ Detected registration/composition site: src/EchoHub.Server/Program.cs. Inspect t
|
||||
- [`ServerDirectoryService`](../../Code/src/EchoHub.Server/Services/ServerDirectoryService.cs.md)
|
||||
|
||||
---
|
||||
*Synthesised by Aurion on 2026-07-23 05:55:34 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:35:20 UTC*
|
||||
|
||||
@@ -1,54 +1,29 @@
|
||||
# API client and authentication
|
||||
# API client authentication
|
||||
|
||||
> How the EchoHub client authenticates with the server, handles tokens, and defines authentication DTOs.
|
||||
> How the client authenticates with the server, including login, token refresh, and token usage across API calls.
|
||||
|
||||
This guide explains how the EchoHub client performs HTTP operations and manages authentication tokens, and it documents the DTOs the client uses when talking to the server. It focuses on the client-side [ApiClient](../Code/src/EchoHub.Client/Services/ApiClient.cs.md) as the central point for login/refresh/logout and common API operations, and the small set of DTOs and client callback interface the ApiClient consumes and produces. Read this when you need to understand which types carry credentials and tokens, how attachments and avatar uploads are represented, and where server-initiated events are delivered on the client.
|
||||
A short, focused orientation to how the client authenticates to the server and then uses those credentials when making API calls. The three files described below show a single HTTP façade that owns token state and many API operations ([ApiClient](../Code/src/EchoHub.Client/Services/ApiClient.cs.md)), plus the small immutable DTOs that carry credentials and message/attachment metadata between the client and server. Read these together to understand the runtime flow: sign in -> store tokens -> refresh when needed -> attach tokens to requests; and how message attachments are represented when uploaded or downloaded.
|
||||
|
||||
## ApiClient.cs
|
||||
Implements token management and API calls to the EchoHub server.
|
||||
Performs login, token refresh, and authenticated API calls.
|
||||
|
||||
The [ApiClient](../Code/src/EchoHub.Client/Services/ApiClient.cs.md) class is a high-level HTTP client that centralizes authentication lifecycle (LoginAsync, LoginWithRefreshTokenAsync, RefreshTokenAsync, LogoutAsync, SetTokens) and exposes token state via properties like Token, RefreshToken, and ExpiresAt. It provides helper methods for authenticated requests (AuthenticatedRequestAsync, AuthenticatedGetAsync, EnsureAuthenticated, GetValidTokenAsync) and common server operations surfaced to callers: channel and message management (CreateChannelAsync, DeleteChannelAsync, SendMessageWithAttachmentsAsync, DeleteMessageAsync, RekeyChannelAsync, NukeChannelAsync), moderation actions (AssignRoleAsync, BanUserAsync, KickUserAsync, MuteUserAsync, UnbanUserAsync, UnmuteUserAsync), profile and upload flows (UploadAvatarAsync, DownloadFileToTempAsync, UpdateProfileAsync, ExportMyDataAsync, DeleteMyAccountAsync), and utilities for handling file content types (GetContentType). The ApiClient implements IDisposable (Dispose) and contains response handling helpers (EnsureSuccessAsync) so callers get a single, managed surface for HTTP/authorization concerns. According to its relationships it depends on the DTO definitions in [AuthDtos](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md), [ChatDtos](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md), [ModerationDtos](../Code/src/EchoHub.Core/DTOs/ModerationDtos.cs.md), and [ProfileDtos](../Code/src/EchoHub.Core/DTOs/ProfileDtos.cs.md); in practice the ApiClient serializes and deserializes instances of those DTOs when calling corresponding endpoints and when returning structured results to its callers.
|
||||
The [ApiClient](../Code/src/EchoHub.Client/Services/ApiClient.cs.md) is a sealed, disposable HTTP façade that centralizes authentication state (access token, refresh token, and expiration) and exposes the concrete operations the UI or other client code calls. The doc lists properties and members such as `BaseUrl`, `Token`, `RefreshToken`, `SetTokens`, and lifecycle helpers like `Dispose`, plus auth-focused methods `LoginAsync`, `LoginWithRefreshTokenAsync`, `RefreshTokenAsync`, and `GetValidTokenAsync` — these are the explicit entry points for establishing and renewing credentials. For making requests it provides `AuthenticatedRequestAsync` and `AuthenticatedGetAsync` (and `EnsureAuthenticated` / `EnsureSuccessAsync`) to attach the current token and validate responses; higher-level API operations are implemented as methods like `SendMessageWithAttachmentsAsync`, `DownloadFileToTempAsync`, `UploadAvatarAsync`, and many channel/user management calls (e.g., `CreateChannelAsync`, `BanUserAsync`, `AssignRoleAsync`). Within this topic the `ApiClient` depends on the DTO types defined in the other files to marshal request and response payloads (see relationships: depends on ChatDtos.cs, AuthDtos.cs) and therefore hands off typed payloads like `LoginRequest`/`LoginResponse` and `AttachmentDto` when calling the server.
|
||||
|
||||
## AuthDtos.cs
|
||||
Defines login request data structure used to authenticate.
|
||||
Defines the login response DTO used by the API client.
|
||||
|
||||
The [AuthDtos](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md) file defines the transport types used by the authentication endpoints: the immutable positional [LoginRequest](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md) record carrying Username and Password, the [LoginResponse](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md) record that bundles Token, RefreshToken, ExpiresAt and basic user identity fields, plus a [RefreshRequest](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md) and [RegisterRequest](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md). These DTOs are pure data containers (no business logic) intended to be serialized over HTTP; the documentation calls out that Password is sensitive and that LoginResponse is what clients consume to establish an authenticated session. The ApiClient uses these DTOs when performing login and token-refresh flows (see relationships: used by ApiClient.cs).
|
||||
|
||||
## AuthDtos.cs (LoginResponse)
|
||||
Represents server response after authentication including tokens.
|
||||
|
||||
The [LoginResponse](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md) record is the structured server reply to a successful authentication, containing the short-lived Token, the RefreshToken, an ExpiresAt timestamp, and identifying fields like Username with optional display personalization. Clients (like the [ApiClient](../Code/src/EchoHub.Client/Services/ApiClient.cs.md)) consume LoginResponse to populate their in-memory token state and to drive expiration/refresh logic; because it contains the expiry moment, consumers can decide when to call RefreshTokenAsync or LoginWithRefreshTokenAsync instead of issuing unauthenticated requests.
|
||||
|
||||
## AuthDtos.cs (RefreshRequest)
|
||||
Represents refresh token request for renewing authentication.
|
||||
|
||||
The [RefreshRequest](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md) is the DTO used to request new authentication tokens from the server using a refresh token. It is the lightweight, immutable payload the ApiClient will serialize when it invokes its refresh endpoint (RefreshTokenAsync / LoginWithRefreshTokenAsync) so the server can validate the refresh token and return a new [LoginResponse](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md).
|
||||
|
||||
## IEchoHubClient.cs
|
||||
Interface for EchoHub client surface used by ApiClient to perform operations.
|
||||
|
||||
The [IEchoHubClient](../Code/src/EchoHub.Core/Contracts/IEchoHubClient.cs.md) interface defines the callback surface that a client implementing the real-time hub must provide: methods such as ReceiveMessage(MessageDto), UserJoined(channelName, username, UserPresenceDto?), UserLeft, ChannelUpdated(ChannelDto), UserStatusChanged, UserKicked, UserBanned, MessageDeleted, ChannelDeleted, ChannelNuked, ForceDisconnect, and Error. The doc shows example minimal implementations that log or handle these events quickly and non-blockingly. While the ApiClient handles HTTP and token management, this interface is the typed contract used by any hub/transport layer to deliver server-initiated events to client code; the relationship shows IEchoHubClient depends on DTO types like those in [ChatDtos](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) and [ProfileDtos](../Code/src/EchoHub.Core/DTOs/ProfileDtos.cs.md), which are delivered through these callbacks.
|
||||
This file contains small immutable records that model the authentication payloads the client sends and receives. Notably, `LoginRequest(string Username, string Password)` packages credentials for `LoginAsync` calls, and `LoginResponse(string Token, string RefreshToken, DateTimeOffset ExpiresAt, string Username, string? DisplayName, string? NicknameColor)` is the typed response carrying the `Token`, `RefreshToken`, and `ExpiresAt` values that the [ApiClient](../Code/src/EchoHub.Client/Services/ApiClient.cs.md) stores and uses to authorize subsequent requests. There are also `RefreshRequest` and `RegisterRequest` records for refresh and registration flows; these DTOs are value objects (records) intended for transport only and are the direct inputs/outputs used by ApiClient methods like `LoginAsync`, `RefreshTokenAsync`, and `LoginWithRefreshTokenAsync` as the source of truth for token state.
|
||||
|
||||
## ChatDtos.cs
|
||||
`AttachmentDto` collaborates directly with `ApiClient` and other members of this topic (10 dependency links).
|
||||
`AttachmentDto` collaborates directly with `ApiClient` and other members of this topic (8 dependency links).
|
||||
|
||||
The [ChatDtos](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) file defines message and channel payloads used across both HTTP API and hub callbacks. In particular, the [AttachmentDto](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) record carries Kind (AttachmentKind), Url, FileName, FileSize, and an optional AsciiPreview; it represents a message attachment's metadata and is the shape ApiClient sends or receives when uploading, downloading, or rendering attachments. Other DTOs in the same file (MessageDto, ChannelDto, ChannelMetaDto, SendMessageRequest, SendUrlRequest, ReplyRefDto, etc.) are the structured inputs and outputs ApiClient uses for channel operations and that appear on the [IEchoHubClient](../Code/src/EchoHub.Core/Contracts/IEchoHubClient.cs.md) callbacks. The docs note an important detail: in end-to-end encrypted channels the content behind the Url (and previews) may be ciphertext opaque to the server, which affects how clients process the Url returned in AttachmentDto.
|
||||
|
||||
## ModerationDtos.cs
|
||||
`AssignRoleRequest` collaborates directly with `ApiClient` and other members of this topic (4 dependency links).
|
||||
|
||||
The [ModerationDtos](../Code/src/EchoHub.Core/DTOs/ModerationDtos.cs.md) file provides small, immutable payloads for moderation actions; the [AssignRoleRequest](../Code/src/EchoHub.Core/DTOs/ModerationDtos.cs.md) record carries a Username and a ServerRole value and is intended to be sent to moderation endpoints to request a role change. The file also contains BanRequest, KickRequest, and MuteRequest records used for banning, kicking, and muting operations. The ApiClient serializes these DTOs when invoking its moderation methods (AssignRoleAsync, BanUserAsync, KickUserAsync, MuteUserAsync), so moderation actions are expressed as data objects across the HTTP boundary.
|
||||
|
||||
## ProfileDtos.cs
|
||||
`AvatarUploadResponse` collaborates directly with `ApiClient` and other members of this topic (4 dependency links).
|
||||
|
||||
The [ProfileDtos](../Code/src/EchoHub.Core/DTOs/ProfileDtos.cs.md) file defines small user-profile payloads used by profile/update and avatar upload endpoints. The [AvatarUploadResponse](../Code/src/EchoHub.Core/DTOs/ProfileDtos.cs.md) record holds AvatarAscii, the ASCII-art representation returned after an avatar upload; ApiClient's UploadAvatarAsync returns or deserializes this DTO so callers can display or store the ASCII preview. UpdateProfileRequest and UpdateStatusRequest are optional-field records used for partial profile updates and are the payloads ApiClient will send via UpdateProfileAsync.
|
||||
`ChatDtos.cs` defines the message- and channel-related transport shapes that the [ApiClient](../Code/src/EchoHub.Client/Services/ApiClient.cs.md) consumes and returns. The `AttachmentDto(AttachmentKind Kind, string Url, string FileName, long FileSize, string? AsciiPreview = null)` record encapsulates an attachment's metadata: a retrieval `Url`, `FileName`, `FileSize`, and optional `AsciiPreview`. The file also contains `SendMessageRequest`, `SendUrlRequest`, `ChannelDto`, `ChannelMetaDto`, `MessageDto`, `UserDto`, and `ChannelCryptoDto` among others; these records are the concrete payloads `ApiClient` methods accept and return for operations such as `SendMessageWithAttachmentsAsync`, `SendUrlAsync`, `GetChannelMetaAsync`, and `DownloadFileToTempAsync`. In practice the `AttachmentDto.Url` is the link the client will follow (via `DownloadFileToTempAsync`) to retrieve an attachment and the structured send requests are the bodies used by the ApiClient when posting messages or creating channels.
|
||||
|
||||
How the pieces fit
|
||||
|
||||
The ApiClient is the HTTP façade: it consumes and produces the DTOs in AuthDtos, ChatDtos, ModerationDtos, and ProfileDtos when calling server endpoints and populating client state. Authentication flows center on the LoginRequest/LoginResponse/RefreshRequest DTOs and ApiClient methods that set and refresh Token/RefreshToken and expose helpers like GetValidTokenAsync and EnsureAuthenticated. Separately, real-time server-to-client events are delivered through the [IEchoHubClient](../Code/src/EchoHub.Core/Contracts/IEchoHubClient.cs.md) callback interface using the same Chat and Profile DTOs, keeping transport and event handling decoupled while the ApiClient handles request/response semantics and token lifecycle.
|
||||
The runtime collaboration is straightforward: the [ApiClient](../Code/src/EchoHub.Client/Services/ApiClient.cs.md) is the orchestrator that holds token state emitted by the auth DTOs (e.g., [LoginResponse](../Code/src/EchoHub.Core/DTOs/AuthDtos.cs.md)). Callers invoke `LoginAsync`/`LoginWithRefreshTokenAsync` to obtain or restore that state, `GetValidTokenAsync`/`RefreshTokenAsync` to keep it current, and the client then uses `AuthenticatedRequestAsync`/`AuthenticatedGetAsync` to attach the access token to calls. For message and file operations the ApiClient sends and receives the chat records from [ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) — for example, `AttachmentDto` conveys the `Url` and metadata that `DownloadFileToTempAsync` and `SendMessageWithAttachmentsAsync` operate on — so DTOs remain passive carriers while ApiClient implements the network and auth behavior that uses them.
|
||||
|
||||
---
|
||||
*Covers 8 of 8 source files identified for this topic.*
|
||||
*Covers 3 of 3 source files identified for this topic.*
|
||||
|
||||
*Synthesised by Aurion on 2026-07-23 05:50:51 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:30:19 UTC*
|
||||
|
||||
@@ -1,41 +1,31 @@
|
||||
# Attachments and file transfers
|
||||
# Attachments transfer
|
||||
|
||||
> Staging and sending attachments in chat messages and coordinating outbound attachments.
|
||||
> Attachment handling for staged files and outgoing attachments in chat messages.
|
||||
|
||||
Outgoing attachments are staged in the UI, packaged as transport objects, and then coordinated through the app orchestrator into the live connection for transmission. This topic shows the small set of types and methods that carry file streams and metadata from the MainWindow staging UI through AppOrchestrator into the connection layer so they can be uploaded (optionally encrypted) and surfaced as attachment DTOs in messages.
|
||||
This guide describes how the client UI stages user-provided files and how the application constructs the immutable attachment objects that travel with outgoing chat messages. It explains the UI surface that users interact with, the small data carrier used to represent a prepared attachment, and the orchestrator that connects the two when a send or clear action occurs. Read this to quickly locate the methods you'll call to stage files, build upload payloads, and clean up temporary paste artifacts.
|
||||
|
||||
## OutgoingAttachment.cs
|
||||
Represents an attachment queued for sending to a channel or user.
|
||||
## MainWindow
|
||||
Stage and manage file attachments in the chat input.
|
||||
|
||||
The [OutgoingAttachment](../Code/src/EchoHub.Client/Services/OutgoingAttachment.cs.md) record is the in-process transport object used to carry a single file stream and its filename through the sending pipeline. It declares four properties: the raw Stream and FileName (required), and two optional strings DeclaredKind and EncryptedPreview which are intended for end-to-end encrypted scenarios. As a record it provides value-based equality for tracking/deduplication but notably does not manage the Stream lifetime — callers open and dispose streams around instances of this type. In this topic it is produced/consumed by the orchestrator layer (see [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md)).
|
||||
The [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md) type is the UI surface for composing messages and managing staged attachments. Its documented members include explicit input- and attachment-focused operations such as SetStagedAttachments and StageFiles (for adding files from disk or paste), ClearAll and HandleCmdClearAttachments-related flows, plus many UI helpers (FocusInput, UpdateInputTitle, UpdateInputReadOnly) that keep the compose area in sync. Per the file relationships, MainWindow is used by [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md); the orchestrator drives MainWindow to display or clear staged attachments and reacts to user commands emitted from the window.
|
||||
|
||||
## MainWindow.cs
|
||||
Provides UI hooks for staging attachments and displaying progress.
|
||||
## OutgoingAttachment
|
||||
Represents attachments prepared for sending with messages.
|
||||
|
||||
The [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md) component exposes the user-facing hooks that allow files to be staged and progress or status to be shown. Among its many members are StageFiles (to accept user-selected files) and SetStagedAttachments (to update the UI with the current list of staged items), plus UI update methods such as UpdateSpinner/UpdateInputTitle to reflect in-progress operations. MainWindow depends on the message/attachment DTO types in [ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) for rendering metadata and is called by [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) when orchestrated work (prepare/send/clear attachments) must update the UI.
|
||||
The [OutgoingAttachment](../Code/src/EchoHub.Client/Services/OutgoingAttachment.cs.md) record is a compact, immutable data carrier containing a Stream and the original FileName plus two optional fields: DeclaredKind and EncryptedPreview. As a record it provides value-based equality so attachments can be compared or deduplicated as they move through the pipeline. The DeclaredKind/EncryptedPreview pair is used to carry presentation/encryption metadata for end-to-end encrypted channels, while normal (non-encrypted) sends typically populate only Stream and FileName. The file is consumed by the orchestrator when preparing payloads for transmit.
|
||||
|
||||
## AppOrchestrator.cs
|
||||
Builds outbound attachments and coordinates sending operations.
|
||||
## AppOrchestrator
|
||||
`AppOrchestrator` collaborates directly with `OutgoingAttachment` and other members of this topic (2 dependency links).
|
||||
|
||||
The [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) owns the high-level send flow: it implements BuildOutgoingAttachmentAsync to assemble outbound attachment payloads (creating [OutgoingAttachment](../Code/src/EchoHub.Client/Services/OutgoingAttachment.cs.md) instances), provides cleanup helpers such as CleanupPastedTempFiles, and contains command handlers like HandleCmdSendFile and HandleCmdClearAttachments that respond to user actions. It depends on the DTO types in [ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) when preparing message payloads and coordinates with the UI by reading staged files from and writing status back to [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md). For transmission the orchestrator delegates connection and delivery responsibilities to the connection layer ([ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md)).
|
||||
|
||||
## ConnectionManager.cs
|
||||
`ConnectionManager` collaborates directly with `AppOrchestrator` and other members of this topic (4 dependency links).
|
||||
|
||||
The [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) encapsulates the live chat connection lifecycle: authentication, optional end-to-end key fetching, and instantiation/wiring of the SignalR hub connection. It exposes a thin event surface so UI code (principally [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md)) can subscribe to SignalR events without dealing with SignalR details, and it implements IAsyncDisposable so the orchestrator can tear down network resources cleanly. ConnectAsync (documented in the file) reports progress via a provided onStatus callback, treats failure to obtain an E2E key as non-fatal, and returns compound results (the internal [ConnectResult](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) record) that include login, channel list, and histories for the orchestrator to use.
|
||||
|
||||
## ChatDtos.cs
|
||||
`AttachmentDto` collaborates directly with `AppOrchestrator` and other members of this topic (4 dependency links).
|
||||
|
||||
The [AttachmentDto](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) is the immutable transport representation of an attachment that travels with messages: it records the attachment Kind, a Url where the resource can be retrieved, FileName, FileSize, and an optional AsciiPreview used for character-art rendering. The DTO is the canonical metadata shape used across UI, API, and connection boundaries; the orchestrator uses these DTO types when composing or processing message payloads, and the MainWindow reads them to render attachments in the UI. In end-to-end encrypted channels the DTO’s Url and AsciiPreview may represent ciphertext that the server cannot interpret.
|
||||
The [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) mediates between UI actions and the attachment/send logic. Notable documented members include BuildOutgoingAttachmentAsync (the builder that produces an [OutgoingAttachment](../Code/src/EchoHub.Client/Services/OutgoingAttachment.cs.md) from a file/clipboard source), CleanupPastedTempFiles (removes temporary files created when pasting), and explicit command handlers such as HandleCmdSendFile and HandleCmdClearAttachments. AppOrchestrator depends on [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md) to reflect staged attachments in the UI and to respond to user-driven events; it constructs the immutable OutgoingAttachment values and manages lifecycle concerns (downloads, ensuring room unlocked for send, and cleanup).
|
||||
|
||||
How the pieces fit
|
||||
|
||||
- UI staging: users pick files via [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md). MainWindow.StageFiles and SetStagedAttachments hold the files and show progress to the user while AppOrchestrator drives the workflow.
|
||||
- Packaging: [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) constructs [OutgoingAttachment](../Code/src/EchoHub.Client/Services/OutgoingAttachment.cs.md) records (via BuildOutgoingAttachmentAsync), cleans up temp files, and maps to the DTO shapes from [ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) when preparing messages.
|
||||
- Delivery: the orchestrator delegates network work to [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md), which manages connection/auth/E2E keys and forwards events so the UI and orchestrator can report progress and completion.
|
||||
- MainWindow is the UI owner of staged files: it exposes StageFiles, SetStagedAttachments, ClearAll and other composition helpers so users can add, view, and remove attachments before sending.
|
||||
- AppOrchestrator listens for UI commands, calls BuildOutgoingAttachmentAsync to turn staged input into an [OutgoingAttachment](../Code/src/EchoHub.Client/Services/OutgoingAttachment.cs.md), and invokes the send/download/cleanup flows (including CleanupPastedTempFiles) as needed.
|
||||
- OutgoingAttachment is the immutable transport object passed from the orchestrator into the send pipeline; optional DeclaredKind and EncryptedPreview carry E2EE-specific metadata when applicable.
|
||||
|
||||
---
|
||||
*Covers 5 of 5 source files identified for this topic.*
|
||||
*Covers 3 of 3 source files identified for this topic.*
|
||||
|
||||
*Synthesised by Aurion on 2026-07-23 05:53:19 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:32:36 UTC*
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
# Clipboard utilities
|
||||
|
||||
> Helpers for clipboard interactions: files and images.
|
||||
> Clipboard helpers for files and images used in the UI.
|
||||
|
||||
This guide describes the clipboard-focused utilities in the client: one helper that exposes file-list clipboard contents, another that normalizes image clipboard data into PNG bytes, and the UI entry points that call those helpers to stage attachments or consume images.
|
||||
This topic covers small, focused helpers that let the UI treat clipboard contents as first-class attachments: one helper extracts file paths from a file-list clipboard, another canonicalizes whatever image bytes are available into a PNG, and the window UI calls them when the user pastes or triggers clipboard-driven actions. The helpers centralize platform differences (Windows, Linux, macOS fallbacks) and intentionally present a simple success/failure API so the UI can degrade gracefully when clipboard content or platform support is missing.
|
||||
|
||||
## ClipboardFiles.cs
|
||||
Clipboard file utilities for handling file lists.
|
||||
Provides clipboard file handling utilities.
|
||||
|
||||
The [ClipboardFiles](../Code/src/EchoHub.Client/Services/ClipboardFiles.cs.md) static class provides a single, platform-aware API (exposed via TryGetFiles) to read file paths when the OS clipboard contains a file-list. It hides OS-specific handling—on Windows it reads CF_HDROP with a short retry loop to tolerate clipboard contention, on Linux it uses text/uri-list through wl-paste or xclip—and it performs existence checks and filters out non-file entries so callers receive only existing paths. TryGetFiles returns true only when at least one valid file path is found, otherwise false, allowing callers to fall back if no usable file-list is present; this class is consumed by the UI layer ([MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md)).
|
||||
The [ClipboardFiles](../Code/src/EchoHub.Client/Services/ClipboardFiles.cs.md) type is a static helper that exposes a single, simple consumption pattern: call TryGetFiles to ask the OS clipboard for a list of file paths. TryGetFiles returns true only when one or more existing file paths are discovered; it filters out non-existent or malformed entries and returns false on platforms that don’t support a file-list clipboard or when no valid paths are present. Internally the helper normalizes platform differences (CF_HDROP on Windows, text/uri-list on Linux using command-line helpers) and logs exceptions rather than throwing, so callers receive a boolean+list result they can act on without having to catch clipboard-specific exceptions. In the app this helper is consumed by the UI layer: the [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md) calls into ClipboardFiles.TryGetFiles to obtain file paths to be staged or attached.
|
||||
|
||||
## ClipboardImage.cs
|
||||
Clipboard image utilities for copying images to the clipboard.
|
||||
Provides clipboard image utilities.
|
||||
|
||||
The [ClipboardImage](../Code/src/EchoHub.Client/Services/ClipboardImage.cs.md) static class exposes TryGetPng to extract whatever image is currently on the OS clipboard and return it as PNG-encoded bytes suitable for saving, embedding, or transmitting. It normalizes multiple clipboard image formats: it prefers a native PNG clipboard format to preserve alpha, and falls back to platform bitmaps (CF_DIB on Windows) by wrapping DIB bytes in a minimal BMP header and decoding/re-encoding to PNG via DibToPng; malformed DIB input yields null and TryGetPng surfaces that as a failure (false). TryGetPng routes to OS-specific helpers, logs errors rather than throwing, and returns false on unsupported platforms or on failure; [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md) depends on this helper to obtain clipboard image bytes.
|
||||
The [ClipboardImage](../Code/src/EchoHub.Client/Services/ClipboardImage.cs.md) static class exposes TryGetPng to produce a canonical PNG byte array from whatever image representation the OS clipboard currently holds. TryGetPng dispatches platform-specific work to methods such as TryGetWindows, TryGetLinux, or TryGetMacOS based on runtime OperatingSystem checks, preserves native PNG clipboard bytes when present (using PngMagic or platform-registered formats), and converts other formats — notably DIB/CF_DIB on Windows — by wrapping the DIB in a minimal BMP and using an image loader to re-encode as PNG via the DibToPng helper. The API favors robustness: all clipboard- and image-decoding exceptions are logged and swallowed so callers get a simple true/false outcome, and the docs call out platform and threading caveats (for example, STA requirements on Windows and header validation for DIB inputs). The [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md) uses ClipboardImage.TryGetPng when it needs a pasteable PNG payload from the clipboard for staging or insertion.
|
||||
|
||||
## MainWindow.cs
|
||||
`MainWindow` collaborates directly with `ClipboardFiles` and other members of this topic (2 dependency links).
|
||||
|
||||
The [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md) UI class defines a large set of interactive behaviors and a handful of members that interact with the clipboard: notably methods named StageFiles, SetStagedAttachments and GuardedClipboardAction appear in its surface. Per the documented relationships, MainWindow delegates platform specifics to the clipboard helpers: it invokes [ClipboardFiles](../Code/src/EchoHub.Client/Services/ClipboardFiles.cs.md).TryGetFiles to obtain file paths copied by the user and then uses its own staging APIs (SetStagedAttachments/StageFiles) to prepare those paths for attachment. Likewise, MainWindow can call [ClipboardImage](../Code/src/EchoHub.Client/Services/ClipboardImage.cs.md).TryGetPng to obtain a normalized PNG byte array when the user has copied an image, allowing the UI to save, embed, or attach that image without per-OS handling. GuardedClipboardAction provides a place to centralize error handling and UI feedback around those clipboard calls so failures from the helpers (they return false rather than throwing) can be handled gracefully.
|
||||
The [MainWindow](../Code/src/EchoHub.Client/UI/MainWindow.cs.md) source defines the interactive UI surface and numerous event handlers and helpers related to input, message lists, and clipboard interactions. Of particular relevance to this topic are methods such as GuardedClipboardAction, StageFiles, SetStagedAttachments, and CopyToClipboard: GuardedClipboardAction is the safe wrapper for performing clipboard operations (honoring the helpers’ failure semantics), StageFiles and SetStagedAttachments are the paths by which file lists or image bytes obtained from the clipboard are moved into the UI’s pending-attachment state, and CopyToClipboard implements copy behavior the UI exposes. When a paste or clipboard-driven accept occurs, MainWindow calls into the clipboard helpers — invoking [ClipboardImage](../Code/src/EchoHub.Client/Services/ClipboardImage.cs.md).TryGetPng to request a PNG payload or [ClipboardFiles](../Code/src/EchoHub.Client/Services/ClipboardFiles.cs.md).TryGetFiles to obtain file paths — and then uses its staging methods to present those attachments to the rest of the UI or to the send/attach pipeline.
|
||||
|
||||
How the pieces fit
|
||||
|
||||
- The two service classes encapsulate platform-specific clipboard concerns: [ClipboardFiles] returns a filtered list of existing file paths or false; [ClipboardImage] returns a PNG byte array or false.
|
||||
- [MainWindow] orchestrates user-facing clipboard flows: it calls those helpers from StageFiles/SetStagedAttachments and related clipboard actions, then integrates the results into the message-composition and attachment UI.
|
||||
- The helpers favor returning a simple success/failure result (and normalized data) so the UI can decide whether to stage attachments, embed image bytes, or fall back to alternative input methods.
|
||||
MainWindow is the orchestrator: on paste or clipboard actions it uses GuardedClipboardAction to safely call the two helpers and translate their boolean+payload results into staged attachments (files or PNG bytes). The clipboard helpers isolate platform differences and error handling so the window code only needs to check success/failure and process the returned paths or bytes. This keeps clipboard I/O contained in small, testable utilities while the window code focuses on user flow and attachment lifecycle.
|
||||
|
||||
---
|
||||
*Covers 3 of 3 source files identified for this topic.*
|
||||
|
||||
*Synthesised by Aurion on 2026-07-23 05:53:51 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:33:02 UTC*
|
||||
|
||||
@@ -1,46 +1,53 @@
|
||||
# Command handling
|
||||
# Slash command handling
|
||||
|
||||
> Slash-command parsing and dispatching command actions from UI and orchestrator.
|
||||
> Parsing and executing user commands entered as slash commands in chat.
|
||||
|
||||
*Figure: How Command handling works.*
|
||||
*Figure: How Slash command handling works.*
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme':'base','themeVariables':{'background':'#faf7ef','primaryColor':'#f0e2c2','primaryTextColor':'#1f2840','primaryBorderColor':'#8a7548','secondaryColor':'#d9efec','secondaryBorderColor':'#1d8a80','secondaryTextColor':'#1f2840','tertiaryColor':'#f2ebd8','tertiaryBorderColor':'#8a7548','tertiaryTextColor':'#1f2840','lineColor':'#1d8a80','titleColor':'#1f2840','fontSize':'14px','edgeLabelBackground':'#faf7ef','clusterBkg':'#f2ebd8','clusterBorder':'#8a7548','actorBkg':'#f0e2c2','actorBorder':'#8a7548','actorTextColor':'#1f2840','actorLineColor':'#8a7548','signalColor':'#1d8a80','signalTextColor':'#1f2840','activationBkgColor':'#d9efec','activationBorderColor':'#1d8a80','noteBkgColor':'#f2ebd8','noteBorderColor':'#8a7548','noteTextColor':'#1f2840','labelBoxBkgColor':'#f0e2c2','labelBoxBorderColor':'#8a7548','labelTextColor':'#1f2840','transitionColor':'#1d8a80','transitionLabelColor':'#1f2840','stateLabelColor':'#1f2840','altBackground':'#f2ebd8'}}}%%
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant ConnectionManager_cs as ConnectionManager.cs
|
||||
participant AppOrchestrator_cs as AppOrchestrator.cs
|
||||
participant CommandHandler_cs as CommandHandler.cs
|
||||
Client->>ConnectionManager_cs: UI sends slash command
|
||||
ConnectionManager_cs->>AppOrchestrator_cs: forward command to orchestrator
|
||||
AppOrchestrator_cs->>CommandHandler_cs: invoke command parsing and dispatch
|
||||
CommandHandler_cs-->>AppOrchestrator_cs: return parsed action/result
|
||||
AppOrchestrator_cs->>ConnectionManager_cs: dispatch action / send response
|
||||
ConnectionManager_cs-->>Client: deliver response to UI
|
||||
participant ConnectionManager
|
||||
participant AppOrchestrator
|
||||
participant CommandHandler
|
||||
|
||||
Client->>ConnectionManager: Send slash command
|
||||
activate ConnectionManager
|
||||
ConnectionManager->>AppOrchestrator: OnSlashCommandReceived
|
||||
activate AppOrchestrator
|
||||
AppOrchestrator->>CommandHandler: ParseAndExecute(command)
|
||||
activate CommandHandler
|
||||
CommandHandler-->>AppOrchestrator: ExecutionResult
|
||||
deactivate CommandHandler
|
||||
AppOrchestrator-->>ConnectionManager: Response(result)
|
||||
deactivate AppOrchestrator
|
||||
ConnectionManager-->>Client: Send response
|
||||
deactivate ConnectionManager
|
||||
```
|
||||
|
||||
This guide explains how user-entered slash commands move from text input into application behavior and network actions. It describes the parsing and event surface (the command-to-event bridge), the central orchestrator that implements command handlers and coordinates UI-side concerns, and the connection manager that owns the live SignalR connection and performs the network work the orchestrator requests.
|
||||
This guide explains how slash-style chat input is parsed and executed across three collaborating components: a parser/dispatcher, an application orchestrator that implements command behavior and UI coordination, and a connection manager that exposes server and SignalR events. Read this to understand which file performs parsing, which one implements the command actions and UI glue, and which one owns the network and lifecycle concerns so you can correctly subscribe handlers and marshal events to the UI thread.
|
||||
|
||||
## CommandHandler.cs
|
||||
Parses and executes chat commands; determines if input is a command.
|
||||
Parses and executes slash commands from the chat input.
|
||||
|
||||
The [CommandHandler](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md) class is the input-to-event bridge: it recognizes whether a text input is a slash command (via IsCommand) and runs a suite of HandleXxx parsing routines (for example HandleSetStatus, HandleSendAction, HandleCreateInvite, HandleExportData and many others listed in the source). It does not perform side effects itself; instead it exposes one event per supported command (OnSetStatus, OnSendAction, OnCreateInvite, OnExportData, etc.) and raises asynchronous events after parsing. The class also contains parsing helpers and semantics notes (status handling, StripQuotes, IsValidHex, ParsePathAndSizeFlag) so subscribers can depend on a consistent interpretation of user input. According to the topic relationships, this component is consumed by the [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md), which subscribes to those events to implement behavior.
|
||||
The [CommandHandler](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md) class is the parser and event-based dispatcher for any string that looks like a slash command. Its primary entry is HandleAsync which analyses the incoming text, maps it to one of many command handlers (the file lists HandleAvatar, HandleBan, HandleSend, HandleSetStatus, HandleJoin, etc.), raises the corresponding asynchronous On... events (consumer-provided Func<..., Task> handlers), and returns a CommandResult describing success, usage, or error. CommandHandler also includes parsing helpers such as IsCommand, IsValidHex, StripQuotes and ParsePathAndSizeFlag and exposes small helpers like StatusUsage and HandleDownloadPath so callers can rely on consistent argument parsing. Relationship: App code (the [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md)) consumes CommandHandler by subscribing to its events so that parsed commands are executed by the orchestrator's handlers rather than by the parser itself.
|
||||
|
||||
## AppOrchestrator.cs
|
||||
Central coordinator handling command-related actions and user commands across the app.
|
||||
Wires command events to UI and coordinates command handling with the app lifecycle.
|
||||
|
||||
The [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) wires the command parsing surface into application behavior: it subscribes to the events emitted by the [CommandHandler](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md) and implements the concrete handlers named in the source (a large set of HandleCmd* methods such as HandleCmdSetStatus, HandleCmdSendFile, HandleCmdJoinChannel, HandleCmdCreateInvite, HandleCmdExportData, HandleCmdKickUser, HandleCmdNukeChannel, etc.). It also owns UI-side responsibilities like BuildOutgoingAttachmentAsync, EnsureRoomUnlockedForSendAsync, CleanupPastedTempFiles, pending reply management, and resource cleanup (Dispose). Per its relationships the orchestrator depends on both [CommandHandler](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md) for parsing and [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) for performing network operations; the source shows it translating parsed commands into calls and requests that drive the connection layer. The file also documents many small, focused flow steps (ApplyAsciiSize, HandleChannelSelected, HandleEditProfile, etc.) that adapt command intent into concrete application actions.
|
||||
The [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) implements the concrete behavior for the commands exposed by the parser: it defines a large set of HandleCmd* methods (for example HandleCmdSetStatus, HandleCmdSendFile, HandleCmdJoinChannel, HandleCmdKickUser, HandleCmdCreateInvite, HandleCmdExportData and many more) plus UI-oriented helpers (MainWindow, BuildOutgoingAttachmentAsync, DownloadAttachmentAsync, ApplyAsciiSize, AsciiSizeLabel, CleanupPastedTempFiles). In practice the orchestrator subscribes the CommandHandler events to these HandleCmd* methods so that when the parser raises an On... event the orchestrator performs the actual action, updates UI state, manages attachments and download paths, and enforces room locking or permission checks (for example EnsureRoomUnlockedForSendAsync). Relationship: AppOrchestrator depends on the parser ([CommandHandler](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md)) to receive parsed commands and on the connection layer to execute server-facing actions; it wires command events into UI flows and uses ConnectionManager to carry out network operations.
|
||||
|
||||
## ConnectionManager.cs
|
||||
`ConnectionManager` collaborates directly with `AppOrchestrator` and other members of this topic (4 dependency links).
|
||||
|
||||
The [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) owns the full lifecycle of a live chat connection: authentication and token handling, attempting to fetch and apply end-to-end encryption keys, instantiating and wiring the EchoHub (SignalR) connection, tracking which channels are joined, and forwarding SignalR callbacks as simple .NET events the UI can subscribe to. It exposes ConnectAsync semantics (reporting progress via an onStatus callback and throwing on authentication failure) and implements IAsyncDisposable so callers can call DisposeAsync to tear down the hub and underlying ApiClient. The file also defines the [ConnectResult](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) record (Login, Channels, Histories) that packages the login response, joined channels list, and message histories returned by ConnectAsync. Notes in the source call out important behaviors: failures to fetch encryption keys are non-fatal, forwarded events may arrive on background threads, and callers (principally the [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md)) must handle marshal-to-UI-thread concerns.
|
||||
The [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) is the single place that manages the server connection lifecycle: it performs authentication (via the API client referenced in the docs), attempts to fetch and apply end-to-end encryption keys, constructs and registers handlers on the hub connection, and tracks channel membership state. It exposes high-level events forwarded from the underlying hub (MessageReceived, UserJoined, ChannelUpdated, ConnectionStatusChanged and similar) so callers like the orchestrator can subscribe without binding SignalR handlers directly. Important operational notes surfaced by the doc: ConnectAsync reports progress through an onStatus callback and will throw on authentication failure, its event callbacks may run on SignalR threads so UI code must marshal to the UI thread, and the manager implements IAsyncDisposable so callers should await disposal to release connection and API resources. Relationship: AppOrchestrator uses ConnectionManager to perform server actions and to observe incoming runtime events; ConnectionManager is therefore the network-facing collaborator the orchestrator relies on.
|
||||
|
||||
How the pieces fit
|
||||
|
||||
User input flows into [CommandHandler](../Code/src/EchoHub.Client/Commands/CommandHandler.cs.md), which parses text and emits a focused event per command. [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) subscribes to those events and implements the HandleCmd* methods that translate parsed intent into application actions and requests; when a command requires network interaction, AppOrchestrator delegates to [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md). ConnectionManager manages the SignalR connection and returns results or raises network events back to the orchestrator, while AppOrchestrator handles UI concerns (attachments, pending replies, local state) and coordinates lifecycle and cleanup.
|
||||
CommandHandler is the stateless parser/dispatcher that turns raw slash input into event invocations. AppOrchestrator subscribes to those events and implements the actual command semantics, UI updates, and attachment/download flows. ConnectionManager centralizes authentication, E2E key application, hub creation and SignalR event forwarding so AppOrchestrator can call into the network layer and react to server-originated events without handling low-level connection details.
|
||||
|
||||
---
|
||||
*Covers 3 of 3 source files identified for this topic.*
|
||||
|
||||
*Synthesised by Aurion on 2026-07-23 05:52:46 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:32:15 UTC*
|
||||
|
||||
@@ -1,79 +1,24 @@
|
||||
# Encryption and room key management
|
||||
# Encryption and room keys
|
||||
|
||||
> End-to-end encryption plumbing and secure handling of per-channel room keys.
|
||||
> Client-side encryption and per-room key protection for secure messaging.
|
||||
|
||||
*Figure: How Encryption and room key management works.*
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme':'base','themeVariables':{'background':'#faf7ef','primaryColor':'#f0e2c2','primaryTextColor':'#1f2840','primaryBorderColor':'#8a7548','secondaryColor':'#d9efec','secondaryBorderColor':'#1d8a80','secondaryTextColor':'#1f2840','tertiaryColor':'#f2ebd8','tertiaryBorderColor':'#8a7548','tertiaryTextColor':'#1f2840','lineColor':'#1d8a80','titleColor':'#1f2840','fontSize':'14px','edgeLabelBackground':'#faf7ef','clusterBkg':'#f2ebd8','clusterBorder':'#8a7548','actorBkg':'#f0e2c2','actorBorder':'#8a7548','actorTextColor':'#1f2840','actorLineColor':'#8a7548','signalColor':'#1d8a80','signalTextColor':'#1f2840','activationBkgColor':'#d9efec','activationBorderColor':'#1d8a80','noteBkgColor':'#f2ebd8','noteBorderColor':'#8a7548','noteTextColor':'#1f2840','labelBoxBkgColor':'#f0e2c2','labelBoxBorderColor':'#8a7548','labelTextColor':'#1f2840','transitionColor':'#1d8a80','transitionLabelColor':'#1f2840','stateLabelColor':'#1f2840','altBackground':'#f2ebd8'}}}%%
|
||||
sequenceDiagram
|
||||
participant ConnectionManager
|
||||
participant ClientConfig
|
||||
participant RoomKeyProtector
|
||||
participant RoomKeyStore
|
||||
participant ClientEncryptionService
|
||||
|
||||
ConnectionManager->>ClientConfig: Load AccountPreset
|
||||
ClientConfig->>RoomKeyProtector: Initialize/Acquire protector
|
||||
RoomKeyProtector-->>ClientConfig: Protector instance
|
||||
|
||||
ConnectionManager->>RoomKeyStore: Initialize RoomKeyStore
|
||||
RoomKeyStore->>ClientConfig: Read AccountPreset/config
|
||||
ClientConfig-->>RoomKeyStore: Config data
|
||||
|
||||
RoomKeyStore->>RoomKeyProtector: Protect/Unprotect room keys
|
||||
RoomKeyProtector-->>RoomKeyStore: Protected/Decrypted key
|
||||
|
||||
ConnectionManager->>ClientEncryptionService: Register IMessageEncryptionService
|
||||
ClientEncryptionService-->>ConnectionManager: Encryption service ready
|
||||
|
||||
ConnectionManager->>RoomKeyStore: Request room key for channel
|
||||
RoomKeyStore->>RoomKeyProtector: Decrypt room key
|
||||
RoomKeyProtector-->>RoomKeyStore: Plain room key
|
||||
RoomKeyStore-->>ConnectionManager: Return room key
|
||||
|
||||
ConnectionManager->>ClientEncryptionService: Encrypt/Decrypt message with room key
|
||||
ClientEncryptionService-->>ConnectionManager: Encrypted/Decrypted payload
|
||||
```
|
||||
|
||||
# Encryption and room key management
|
||||
|
||||
End-to-end encryption in the client is implemented as a few focused components: a runtime encryptor that mirrors the server format, a protector that encrypts per-channel room keys at rest, a store that binds persisted server entries to an in-memory cache, and a connection manager that wires those pieces into the live SignalR connection. This guide explains what each file actually implements, how they call each other, and where responsibilities (in-memory keys, persisted protected keys, and message-level cryptography) are split.
|
||||
Client-side message confidentiality is implemented in two cooperating pieces: a runtime encryptor that performs AES-256-GCM on outgoing and incoming message payloads, and a storage protector that keeps per-room content keys encrypted on disk. The runtime service expects a 32-byte key (provided as base64) and emits self-contained ciphertext that carries nonce and tag; the protector hides those room keys at rest behind platform-specific protections so the config file never stores raw base64 keys.
|
||||
|
||||
## ClientEncryptionService.cs
|
||||
Implements IMessageEncryptionService for encrypting/decrypting messages.
|
||||
Implements client-side encryption for messages and room keys.
|
||||
|
||||
The [ClientEncryptionService](../Code/src/EchoHub.Client/Services/ClientEncryptionService.cs.md) class is the client-side AES-256-GCM encryptor/decryptor that mirrors the server’s encryption format so clients and server exchange the same payload shape. It exposes SetKey to accept a 32-byte, server-provided base64 key, Encrypt to produce a prefixed base64 payload containing nonce and ciphertext+tag, and Decrypt to reverse that encoding; before a key is set Encrypt is intentionally a no-op and returns plaintext, and Decrypt returns a sentinel failure message when decryption fails. Per the documentation, the service isolates cryptography behind a swappable implementation and is used by higher-level connection code to apply message encryption only when a key is loaded; in this topic it is referenced by [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md).
|
||||
The [ClientEncryptionService](../Code/src/EchoHub.Client/Services/ClientEncryptionService.cs.md) is a sealed implementation of the message-encryption contract that performs AES-256-GCM on plaintext before it leaves the client. Its public surface includes SetKey (accepts a base64-encoded key and enforces exactly 32 bytes), Encrypt (generates a fresh 12-byte nonce, produces a 16-byte authentication tag, and returns a string that begins with an EncryptionPrefix and contains base64-encoded nonce and payload), and Decrypt (which returns plaintext unchanged if no key is set or if the input lacks the expected prefix). The class also provides nullable-friendly helpers EncryptNullable and DecryptNullable; decryption failures are handled gracefully by returning a sentinel message rather than throwing. Because it expects a server-provisioned key via SetKey, it does not manage persistent key storage itself and therefore can be paired with a separate on-disk protector to obtain that key material at runtime.
|
||||
|
||||
## RoomKeyProtector.cs
|
||||
Provides protection around room keys for secure storage/usage.
|
||||
Provides protection for per-room encryption keys used in chats.
|
||||
|
||||
The [RoomKeyProtector](../Code/src/EchoHub.Client/Services/RoomKeyProtector.cs.md) class is the single API for protecting and unprotecting per-user room content keys before they are written to or read from client configuration. Its Protect method returns a storage-ready string that is prefixed to indicate the protection method ("dp1:" for Windows DPAPI or "k1:" for an AES-GCM-encrypted master key file on other platforms), and TryUnprotect attempts to recover the raw room key while reporting whether the stored value was a legacy plain-base64 entry and whether unprotection succeeded. The class accepts a directory (to locate the master key file) and caches the master key after guarded loading; callers such as [ClientConfig](../Code/src/EchoHub.Client/Config/ClientConfig.cs.md) and [RoomKeyStore](../Code/src/EchoHub.Client/Services/RoomKeyStore.cs.md) rely on it to convert between in-memory bytes and protected storage strings without having to deal with platform-specific details.
|
||||
|
||||
## RoomKeyStore.cs
|
||||
Stores and retrieves room keys securely for channels.
|
||||
|
||||
[RoomKeyStore](../Code/src/EchoHub.Client/Services/RoomKeyStore.cs.md) binds runtime state (a decrypted, in-memory cache of room keys) to persisted per-server entries so users don't re-enter passphrases every launch. You call LoadForServer(serverUrl) to bind the store to a SavedServer in [ClientConfig](../Code/src/EchoHub.Client/Config/ClientConfig.cs.md); the store will read that SavedServer's ChannelKeys, call into [RoomKeyProtector](../Code/src/EchoHub.Client/Services/RoomKeyProtector.cs.md) to unprotect them, and populate its thread-safe cache. The class exposes methods to TryGetKey, StoreKey, Replace/Remove keys, and TryStoreFromEnvelope (which unwraps a wrapped key with a KEK) and will upgrade legacy plain/base64 entries to the protected format when possible; changes are persisted back to the SavedServer through ClientConfig and unreadable entries are logged rather than failing hard. Connection-side code (notably [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md)) uses RoomKeyStore to determine which channels are encrypted and to retrieve keys for encrypting/decrypting messages at send/receive time.
|
||||
|
||||
## ClientConfig.cs
|
||||
`ClientConfig` collaborates directly with `RoomKeyProtector` and other members of this topic (3 dependency links).
|
||||
|
||||
[ClientConfig](../Code/src/EchoHub.Client/Config/ClientConfig.cs.md) is the central container for a user's persisted preferences and runtime state, and it holds SavedServer entries that include the persisted, protected ChannelKeys consumed by [RoomKeyStore](../Code/src/EchoHub.Client/Services/RoomKeyStore.cs.md). ClientConfig provides the serialized place where RoomKeyProtector-generated strings live (the protector prefixes such as "dp1:" or "k1:" are stored here), and callers such as RoomKeyStore read and write these SavedServer entries to keep the on-disk picture in sync with the in-memory cache. Because RoomKeyProtector derives its key-file location from a directory you pass to its constructor, ClientConfig’s location and usage patterns determine where the master key file will be stored and how RoomKeyStore persists upgrades from legacy entries.
|
||||
|
||||
## ConnectionManager.cs
|
||||
`ConnectionManager` collaborates directly with `ClientEncryptionService` and other members of this topic (2 dependency links).
|
||||
|
||||
[ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) is the high-level lifecycle owner for authentication, establishing the EchoHub SignalR connection, and wiring end-to-end encryption into runtime behavior. During ConnectAsync it performs authentication (throwing on auth failure), attempts to fetch and apply an E2E encryption key (failure to fetch is non-fatal and the manager logs a warning), and then uses the [ClientEncryptionService](../Code/src/EchoHub.Client/Services/ClientEncryptionService.cs.md) to encrypt outbound messages and decrypt inbound ones when a key is present. It relies on [RoomKeyStore](../Code/src/EchoHub.Client/Services/RoomKeyStore.cs.md) to know which channels are encrypted and to obtain per-channel room keys, and it uses [ClientConfig](../Code/src/EchoHub.Client/Config/ClientConfig.cs.md) as the backing persisted configuration for saved servers; ConnectionManager forwards SignalR events as simple .NET events and implements IAsyncDisposable so callers can cleanly tear down network and API resources.
|
||||
The [RoomKeyProtector](../Code/src/EchoHub.Client/Services/RoomKeyProtector.cs.md) encrypts the cached per-room content keys so the client configuration does not hold plain base64 keys. It exposes Protect(byte[] roomKey) to produce a storable string and TryUnprotect(string stored, out byte[] roomKey, out bool wasLegacy) to recover raw key bytes. On Windows it prefers DPAPI in the current-user scope and marks values with the DpapiPrefix (dp1:); on other platforms it encrypts keys with AES-GCM using a per-user master key file stored next to the config (KeyFilePrefix, k1:) with 0600 permissions. Entries with no known prefix are treated as legacy plain-base64 keys: they are loaded once and re-encrypted under the active scheme on save. The class caches the per-user master key, chooses the protection mechanism by platform, and explicitly never stores the room passphrase itself.
|
||||
|
||||
How the pieces fit
|
||||
|
||||
- ConnectionManager is the orchestrator: it authenticates, attempts to fetch the server-provided E2E key, wires SignalR events to the UI, and delegates message-level cryptography to [ClientEncryptionService](../Code/src/EchoHub.Client/Services/ClientEncryptionService.cs.md) when a key is present.
|
||||
- RoomKeyStore sits between persisted state and runtime: it loads and persists ChannelKeys via [ClientConfig](../Code/src/EchoHub.Client/Config/ClientConfig.cs.md) and uses [RoomKeyProtector](../Code/src/EchoHub.Client/Services/RoomKeyProtector.cs.md) to unprotect/protect those keys so the on-disk config never contains raw base64 room keys (legacy unprotected values are upgraded when possible).
|
||||
- RoomKeyProtector implements the platform-specific protection formats (DPAPI or a file-backed AES-GCM master key) and presents a stable Protect/TryUnprotect API so the higher-level store and config code do not need to handle cryptography details.
|
||||
|
||||
Together these components keep plaintext room keys out of persistent storage, keep a decrypted cache for active sessions, and ensure message encryption happens only when a server-supplied key has been loaded and applied by the client encryptor.
|
||||
At runtime the pattern is: RoomKeyProtector is responsible for safe at-rest storage of raw room key bytes; callers call TryUnprotect to obtain the byte[] for a room, base64-encode that raw key and pass it to ClientEncryptionService.SetKey, and then call Encrypt/Decrypt to protect message payloads. Conversely, when a new room key is generated or received from the server, callers call Protect to produce the on-disk representation (with the dp1: or k1: prefix) so future runs can recover the same raw bytes. The direction of dependency is clear: the protector controls persistent formats and prefixes and hands raw key bytes to higher-level encryption (which enforces the 32-byte requirement and performs AES-GCM message operations).
|
||||
|
||||
---
|
||||
*Covers 5 of 5 source files identified for this topic.*
|
||||
*Covers 2 of 2 source files identified for this topic.*
|
||||
|
||||
*Synthesised by Aurion on 2026-07-23 05:52:19 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:34:11 UTC*
|
||||
|
||||
@@ -1,34 +1,29 @@
|
||||
# Real-time connection management
|
||||
# Real-time connection and messaging
|
||||
|
||||
> Managing the SignalR hub connection lifecycle and connection state.
|
||||
> How the client establishes and maintains a real-time connection to the server and handles channel messaging.
|
||||
|
||||
# Real-time connection management
|
||||
|
||||
This guide explains how the client-side pieces manage a SignalR-based chat connection, surface server events to the UI, and carry message and attachment DTOs across those boundaries. Read it to understand which types own the HubConnection lifecycle, which types represent messages and attachments, and how connection orchestration hands events and histories back to the UI layer.
|
||||
A compact overview of the client-side real-time layer: how the connection is created, the runtime surface it exposes to higher layers, and the DTOs used to carry chat and channel data. Read this to understand which types you call to open a SignalR-backed, end-to-end-capable chat connection, what events and exceptions to expect, and which transport records carry message and attachment metadata.
|
||||
|
||||
## EchoHubConnection.cs
|
||||
Implements the SignalR connection lifecycle and messaging.
|
||||
|
||||
Encapsulates the SignalR connection to the server and join history with encryption info.
|
||||
|
||||
The [EchoHubConnection](../Code/src/EchoHub.Client/Services/EchoHubConnection.cs.md) type is a thin, SignalR-backed client wrapper that owns a HubConnection and translates server callbacks into plain .NET events (for example OnMessageReceived, OnUserJoined, OnChannelUpdated). It also integrates client-side encryption and room-key lookup: incoming payloads are decrypted before being raised to subscribers, and join history plus encryption metadata is tracked so callers can present past messages. EchoHubConnection declares focused exception types such as ChannelPasswordRequiredException (thrown when a join fails for password reasons) to enable UI-driven retry flows. According to the file relationships, EchoHubConnection consumes message and channel shapes from [ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) and is instantiated and used by [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md).
|
||||
This file defines a small domain exception and a single, high-level connection wrapper. The `ChannelPasswordRequiredException` is a dedicated exception type that carries a `ChannelName` and signals that a channel join failed due to missing or invalid credentials; the doc recommends UIs catch this specific type to prompt for a password and retry. The `EchoHubConnection` class is an event-driven wrapper around a SignalR `HubConnection`: it registers the server callback handlers defined by the server contract, decrypts incoming content when necessary, exposes simple events for messages, presence and channel updates, surfaces connection-state changes, and centralizes token provision and reconnection wiring. Within this topic `EchoHubConnection` consumes the transport records from [ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) and is constructed/managed by the [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md).
|
||||
|
||||
## ConnectionManager.cs
|
||||
Orchestrates connection state and event wiring for the real-time layer.
|
||||
|
||||
Coordinates connection lifecycle and connection events across the client.
|
||||
|
||||
The [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) is the high-level owner of authentication, E2E key retrieval, HubConnection creation, wiring of SignalR callbacks, and tracking of joined channels. It exposes a small event surface that forwards the EchoHubConnection events to the UI (the doc notes AppOrchestrator subscribes), implements IAsyncDisposable to tear down both the hub wrapper and the underlying client, and reports progress from ConnectAsync via an onStatus callback while throwing on authentication failure. ConnectionManager also defines the [ConnectResult](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) record that packages the login response, a list of channel DTOs, and a dictionary of channel histories (the histories contain [MessageDto] entries defined in ChatDtos). Per the relationships, ConnectionManager depends on [ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) for payload shapes and on [EchoHubConnection](../Code/src/EchoHub.Client/Services/EchoHubConnection.cs.md) to manage the live SignalR interactions.
|
||||
`ConnectionManager` is the composition root for a full client connection: it performs authentication (via the project's HTTP API client), attempts to fetch and apply end-to-end encryption keys, constructs and wires an [EchoHubConnection](../Code/src/EchoHub.Client/Services/EchoHubConnection.cs.md), and maintains channel membership state. It forwards the hub's runtime events (for example message and presence events) as higher-level events such as `MessageReceived`, `UserJoined`, and `ConnectionStatusChanged`, so UI orchestrators can subscribe without touching SignalR internals; these forwarded events may be raised from SignalR threads and callers must marshal to the UI thread if required. `ConnectAsync` reports progress through an `onStatus` callback and returns a `ConnectResult` (also declared in this file) to indicate outcome; the class and the underlying `EchoHubConnection` both implement `IAsyncDisposable`, and the doc emphasizes awaiting disposal so resources (connection, tokens, keys) are cleaned up.
|
||||
|
||||
## ChatDtos.cs
|
||||
|
||||
`AttachmentDto` collaborates directly with `ConnectResult` and other members of this topic (9 dependency links).
|
||||
|
||||
[ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) defines the immutable DTOs used across the connection boundary: records such as AttachmentDto, ChannelDto, ChannelMetaDto, MessageDto, JoinChannelResult, and request shapes like SendMessageRequest. The [AttachmentDto](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) record carries metadata for file attachments (kind, URL, filename, filesize, optional ASCII preview) and is explicitly designed to work with end-to-end encrypted channels where the resource behind Url may be ciphertext the server cannot read. These DTOs are the concrete payload shapes that both [EchoHubConnection](../Code/src/EchoHub.Client/Services/EchoHubConnection.cs.md) and [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) send, receive, and store in histories.
|
||||
This file declares the transport records used across the real-time boundary: types such as `AttachmentDto`, `ChannelCryptoDto`, `ChannelDto`, `ChannelMetaDto`, `CreateChannelRequest`, `EmbedDto`, `JoinChannelResult`, `MessageDto`, `RekeyChannelRequest`, `ReplyRefDto`, `SendMessageRequest`, `SendUrlRequest`, `UpdateTopicRequest`, and `UserDto` model messages, channels, users and channel crypto metadata. Concretely, `AttachmentDto` is a value record holding `Kind`, `Url`, `FileName`, `FileSize`, and an optional `AsciiPreview`; the doc highlights that `Url` and `AsciiPreview` may be ciphertext for end-to-end encrypted channels, and that attachments are carried as metadata so clients can fetch or preview content on demand. `ChannelCryptoDto` is a small record with `IsEncrypted` and an optional `EncryptionSalt` and is used to indicate whether channel payloads are protected. These DTOs are the typed payloads that [EchoHubConnection](../Code/src/EchoHub.Client/Services/EchoHubConnection.cs.md) emits and that [ConnectionManager](../Code/src/EchoHub.Client/Services/ConnectionManager.cs.md) tracks when reporting join results and message events.
|
||||
|
||||
How the pieces fit
|
||||
|
||||
ConnectionManager is the orchestration layer: it authenticates, attempts to acquire E2E keys, builds and wires an [EchoHubConnection](../Code/src/EchoHub.Client/Services/EchoHubConnection.cs.md), and exposes forwarded events to the UI while tracking joined channels and histories. EchoHubConnection is the SignalR-focused implementation that manages the HubConnection lifecycle, maps server callbacks to events, performs decryption of incoming payloads, and throws focused exceptions (for example ChannelPasswordRequiredException) so the UI can prompt and retry joins. The DTOs in [ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) are the shared, immutable shapes (messages, channels, attachments) that flow between the manager, the hub wrapper, and the UI; ConnectResult packages those DTOs back to callers after an initial connect sequence.
|
||||
ConnectionManager is the orchestration layer: it authenticates, applies E2E keys, constructs an [EchoHubConnection](../Code/src/EchoHub.Client/Services/EchoHubConnection.cs.md), and subscribes to its events so UI-level orchestrators can observe high-level events and results without dealing with SignalR. EchoHubConnection implements the low-level SignalR wiring, dispatches strongly-typed events and domain exceptions (for example `ChannelPasswordRequiredException`), and uses the DTOs from [ChatDtos.cs](../Code/src/EchoHub.Core/DTOs/ChatDtos.cs.md) as its message and channel payloads. Together they present a clear separation: DTOs define the wire shape, EchoHubConnection maps wire messages to runtime events and errors, and ConnectionManager composes those primitives into a single lifecycle and event surface for the UI.
|
||||
|
||||
---
|
||||
*Covers 3 of 3 source files identified for this topic.*
|
||||
|
||||
*Synthesised by Aurion on 2026-07-23 05:51:44 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:31:01 UTC*
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
# Theming and UI color management
|
||||
# UI theming and theme management
|
||||
|
||||
> Representing themes, color palettes, and runtime theme application.
|
||||
> Theme data models and the system that loads, stores, and applies themes to the UI.
|
||||
|
||||
Theming and UI color management
|
||||
|
||||
The files in this topic define how the EchoHub client represents color themes, exposes a curated set of built-in and user-provided themes, and wires theme selection into the running application. Read these three artifacts to understand the Theme data model, the static ThemeManager API that discovers/applies/persists themes, and the AppOrchestrator entry point that reacts to user commands and delegates theme work to the manager.
|
||||
|
||||
## Theme.cs
|
||||
Represents a UI theme.
|
||||
|
||||
The [Theme](../Code/src/EchoHub.Client/Themes/Theme.cs.md) class is the data container for a complete UI appearance. It exposes a required Name plus four area-specific palettes—Base, Menu, Dialog, and Status—each typed as a [ThemeColors](../Code/src/EchoHub.Client/Themes/Theme.cs.md) instance, and an optional Border palette that, when set, overrides only frame-border colors while leaving other chrome tied to Base. The writer notes sensible defaults: each palette initializes to a new ThemeColors so a Theme is usable with minimal configuration, and Border accepts hex literals or named colors to let designers tint edges without touching text palettes. This file is the canonical representation of a theme and is consumed by the [ThemeManager](../Code/src/EchoHub.Client/Themes/ThemeManager.cs.md) to build and persist theme choices and by the [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) when the application needs to apply or react to theme changes.
|
||||
This guide explains the client-side theming pieces: the Theme data model, the ThemeManager that provides built-in and user-provided themes and applies them at runtime, and the AppOrchestrator that coordinates UI behavior (including theme usage). Read this when you need to add a new theme, wire theme selection into the UI, or understand how theme persistence and runtime application are handled.
|
||||
|
||||
## ThemeManager.cs
|
||||
Loads, caches, and applies themes across the app.
|
||||
Manages built-in themes, theme lookup, and application.
|
||||
|
||||
[ThemeManager](../Code/src/EchoHub.Client/Themes/ThemeManager.cs.md) is a static API that bridges theme data and runtime application. It exposes discovery and retrieval functions such as GetAvailableThemes and GetTheme, mutation points like SaveTheme, and the runtime switch ApplyTheme; utility functions include ParseColor and BuildColorScheme, the latter ensuring colors for editable/read-only roles and transparency behave correctly so inputs remain legible under transparent themes. ThemeManager maintains a curated set of built-in theme factory methods (DefaultTheme, DraculaTheme, LightTheme, etc.), attempts to load additional themes from a user directory (ThemeDir), and falls back to built-ins if the directory cannot be read; SaveTheme is implemented best-effort and quietly swallows failures. Because it returns and manipulates [Theme](../Code/src/EchoHub.Client/Themes/Theme.cs.md) instances, ThemeManager is the component the [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) calls when the app needs to enumerate, choose, or persist a theme and when it needs the computed color scheme to apply to the UI.
|
||||
[ThemeManager](../Code/src/EchoHub.Client/Themes/ThemeManager.cs.md) is a static helper that centralizes theming for the client UI. The class defines a fixed set of built-in theme instances (named constants such as DefaultTheme, TransparentTheme, DraculaTheme, NordTheme, etc.), exposes a ThemeDir and JsonOptions for disk-backed theme discovery and persistence, and provides methods callers use to enumerate, fetch, apply, and save themes: GetAvailableThemes() merges built-ins with user theme files (skipping duplicates and malformed files and falling back to built-ins if the directory cannot be read), GetTheme(name) retrieves a theme by name, SaveTheme persists a Theme to disk, and ApplyTheme performs the runtime application of a Theme to the UI. The file also contains utility logic used by those flows — ParseColor to turn color strings into runtime values and BuildColorScheme(ThemeColors) which maps a Theme's ThemeColors into the editor/UI surfaces so properties like transparency are preserved. ThemeManager stores and manipulates instances of the [Theme](../Code/src/EchoHub.Client/Themes/Theme.cs.md) model and is the primary integration point other code uses to present, switch, or persist themes.
|
||||
|
||||
## Theme.cs
|
||||
Represents a theme data model used by the theming system.
|
||||
|
||||
[Theme](../Code/src/EchoHub.Client/Themes/Theme.cs.md) is the data descriptor for a visual style. A Theme groups per-surface color sets (Base, Menu, Dialog, Status) and optionally supplies a Border color that overrides the window frame independently of the surface colors; if Border is null, consumers fall back to Base. Each surface is represented by a [ThemeColors](../Code/src/EchoHub.Client/Themes/Theme.cs.md) instance, which bundles Foreground, Background, FocusForeground, and FocusBackground tokens. ThemeColors provides sensible defaults (a high-contrast dark baseline) but is mutable via public setters, so callers can tweak palettes after construction; Theme objects are the units ThemeManager stores, enumerates, and writes to disk.
|
||||
|
||||
## AppOrchestrator.cs
|
||||
`AppOrchestrator` collaborates directly with `Theme` and other members of this topic (2 dependency links).
|
||||
|
||||
[AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) is the application-level coordinator that owns the MainWindow and a large set of command handlers; among its many responsibilities it includes a handler named HandleCmdSetTheme which responds to theme-change requests. In practice the orchestrator calls into [ThemeManager](../Code/src/EchoHub.Client/Themes/ThemeManager.cs.md) to fetch or apply a [Theme](../Code/src/EchoHub.Client/Themes/Theme.cs.md) (for example via GetTheme and ApplyTheme) and then ensures the active UI reflects the manager-provided color scheme. The doc block lists the constructor and MainWindow property plus the command handlers (including HandleCmdSetTheme) so the intended runtime flow is: user or code issues a theme command to AppOrchestrator, AppOrchestrator delegates theme discovery/load/apply to ThemeManager, and the Theme instance shapes the MainWindow styling.
|
||||
[AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) is the application-level coordinator that owns the MainWindow and many UI command handlers and lifecycle operations (the class lists a constructor, MainWindow, and dozens of handler and utility methods). Per its declared relationships it depends on the [Theme](../Code/src/EchoHub.Client/Themes/Theme.cs.md) model and the [ThemeManager](../Code/src/EchoHub.Client/Themes/ThemeManager.cs.md) helper. In practice AppOrchestrator is the place where UI-driven behavior is orchestrated: it presents or responds to user actions and calls into ThemeManager to retrieve available Theme objects, fetch a Theme by name, or request that a Theme be applied or saved so the MainWindow and its child surfaces reflect the current style. Because AppOrchestrator centralizes command handling and window-level concerns, it is the natural integration point to wire theme selection UI into the running application and to persist user choices through ThemeManager.
|
||||
|
||||
How the pieces fit
|
||||
|
||||
Theme is the immutable-ish data model for visual choices; ThemeManager is the static service that discovers, builds, parses, and persists those models and produces a concrete color scheme via BuildColorScheme; AppOrchestrator is the runtime conductor that responds to user commands and uses ThemeManager to fetch and ApplyTheme to the UI. The dependency direction is AppOrchestrator -> ThemeManager -> Theme, with ThemeManager also responsible for supplying built-in Theme instances and reading user themes from disk when available.
|
||||
ThemeManager is the provider and manipulator of Theme instances: it supplies built-in Theme objects, discovers and loads user themes from ThemeDir, parses color text, builds the UI color scheme, and persists themes to disk. The Theme class and its ThemeColors containers are the plain-data contract ThemeManager uses to describe a palette and to hand color sets to UI code. AppOrchestrator acts as the runtime coordinator: it uses ThemeManager to enumerate and fetch Theme objects in response to UI commands and ensures the MainWindow and related surfaces receive the Theme (and thus the color scheme) to render the chosen look. Together they form a simple pipeline: Theme data (Theme/ThemeColors) ↦ ThemeManager I/O and mapping (BuildColorScheme / ParseColor / SaveTheme) ↦ AppOrchestrator-driven application to the live UI.
|
||||
|
||||
---
|
||||
*Covers 3 of 3 source files identified for this topic.*
|
||||
|
||||
*Synthesised by Aurion on 2026-07-23 05:51:21 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:31:32 UTC*
|
||||
|
||||
@@ -1,32 +1,66 @@
|
||||
# Update management
|
||||
|
||||
> Data and update flow: backup prior to updates and update checks.
|
||||
> Checking for updates and backing up state related to updates.
|
||||
|
||||
Update management
|
||||
*Figure: How Update management works.*
|
||||
|
||||
This topic covers the client-side update workflow: detecting available versions from the running Terminal.Gui app, deferring heavy update work until the UI has shut down, and snapshotting the application state so you can roll back if an update goes wrong. The two files coordinate a safe in-place updater by separating user interaction and terminal ownership (in UpdateChecker) from the filesystem snapshot and metadata (in UpdateBackupService).
|
||||
```mermaid
|
||||
%%{init: {'theme':'base','themeVariables':{'background':'#faf7ef','primaryColor':'#f0e2c2','primaryTextColor':'#1f2840','primaryBorderColor':'#8a7548','secondaryColor':'#d9efec','secondaryBorderColor':'#1d8a80','secondaryTextColor':'#1f2840','tertiaryColor':'#f2ebd8','tertiaryBorderColor':'#8a7548','tertiaryTextColor':'#1f2840','lineColor':'#1d8a80','titleColor':'#1f2840','fontSize':'14px','edgeLabelBackground':'#faf7ef','clusterBkg':'#f2ebd8','clusterBorder':'#8a7548','actorBkg':'#f0e2c2','actorBorder':'#8a7548','actorTextColor':'#1f2840','actorLineColor':'#8a7548','signalColor':'#1d8a80','signalTextColor':'#1f2840','activationBkgColor':'#d9efec','activationBorderColor':'#1d8a80','noteBkgColor':'#f2ebd8','noteBorderColor':'#8a7548','noteTextColor':'#1f2840','labelBoxBkgColor':'#f0e2c2','labelBoxBorderColor':'#8a7548','labelTextColor':'#1f2840','transitionColor':'#1d8a80','transitionLabelColor':'#1f2840','stateLabelColor':'#1f2840','altBackground':'#f2ebd8'}}}%%
|
||||
sequenceDiagram
|
||||
participant AppOrchestrator
|
||||
participant UpdateChecker
|
||||
participant UpdateBackupService
|
||||
|
||||
## UpdateBackupService.cs
|
||||
Provides backup of user data before updates.
|
||||
AppOrchestrator->>UpdateChecker: "CheckForUpdates()"
|
||||
activate UpdateChecker
|
||||
UpdateChecker->>UpdateBackupService: "PrepareBackup()"
|
||||
activate UpdateBackupService
|
||||
UpdateBackupService->>UpdateChecker: "RequestBackupValidation()"
|
||||
UpdateChecker-->>UpdateBackupService: "ValidateBackup()"
|
||||
UpdateBackupService-->>UpdateChecker: "BackupPrepared"
|
||||
deactivate UpdateBackupService
|
||||
alt "Update available"
|
||||
UpdateChecker-->>AppOrchestrator: "ReportUpdateAvailable()"
|
||||
AppOrchestrator->>UpdateBackupService: "CreateBackupState()"
|
||||
activate UpdateBackupService
|
||||
UpdateBackupService-->>AppOrchestrator: "BackupInfo (serialized)"
|
||||
deactivate UpdateBackupService
|
||||
else "No update"
|
||||
UpdateChecker-->>AppOrchestrator: "ReportNoUpdate()"
|
||||
end
|
||||
deactivate UpdateChecker
|
||||
|
||||
The file declares three related symbols that implement pre-update snapshotting. [BackupJsonContext](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) is an internal, source-generated JsonSerializerContext that supplies reflection-free JSON metadata for serializing the on-disk metadata type. The public [UpdateBackupService](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) static class performs the actual backup/rollback responsibilities: it creates a ZIP snapshot of the running application under ~/.echohub/update-backup/ (backup.zip) and writes a companion backup-info.json (the [BackupInfo](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) contract) that records the version, application directory, and UTC timestamp. The service exposes operations to CreateBackup before applying an update, to check presence via BackupExists, and to read metadata with GetBackupInfo; it also exposes an IsPostUpdate flag that lets startup logic detect a recent update backup and react accordingly. Because the JSON context is internal and generated, callers within the assembly configure JsonSerializerOptions with BackupJsonContext when they read or write backup-info.json.
|
||||
AppOrchestrator->>UpdateChecker: "Dispose()"
|
||||
AppOrchestrator->>UpdateBackupService: "Dispose()"
|
||||
```
|
||||
|
||||
The file is used by the update coordination logic in [UpdateChecker](../Code/src/EchoHub.Client/Services/UpdateChecker.cs.md): the checker defers the updater work but relies on UpdateBackupService to attempt a pre-update snapshot when the update is actually applied.
|
||||
# Update management
|
||||
|
||||
This topic covers the small set of services and the orchestrator that detect available application updates, snapshot state before an update, and hand off the heavy update work so it happens after the Terminal.Gui main loop has exited. The pieces separate responsibilities: a background checker and confirmation flow, a backup/metadata helper that writes a ZIP and JSON, and the application orchestrator that stores the post-TUI delegate the host must invoke. Together they avoid console deadlocks and provide a predictable rollback surface for the updater.
|
||||
|
||||
## UpdateChecker.cs
|
||||
Checks for updates and coordinates update flow.
|
||||
|
||||
[UpdateChecker](../Code/src/EchoHub.Client/Services/UpdateChecker.cs.md) is a disposable helper that runs background polling and supports manual checks, while keeping all user interaction on the provided Terminal.Gui IApplication main loop. Its responsibilities are: poll for newer versions via an internal Updater, present a TUI confirmation dialog by marshalling callbacks with _app.Invoke, and — crucially — avoid performing download/extract/restart while the TUI still owns the terminal. When the user accepts an update, UpdateChecker sets PendingUpdate to an awaitable delegate (the internal ApplyUpdateAsync) and captures the chosen version, then signals the TUI to stop; the host is expected to call PendingUpdate after the main loop exits so the update can run headless and safely restart the process.
|
||||
Checks for updates and reports availability.
|
||||
|
||||
Concrete behaviors documented in the class include: Start() only activates the periodic poller in RELEASE builds; PendingUpdate is intentionally a Task-returning delegate to be invoked by the host after the console is restored; ApplyUpdateAsync attempts to create a pre-update backup by calling [UpdateBackupService.CreateBackup](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) and logs but does not fail the update flow if backup creation fails; ApplyUpdateAsync also sets Console.OutputEncoding = UTF8 while swallowing exceptions for non-interactive stdout; and CurrentVersion reads the assembly version with a fallback of "0.0.0".
|
||||
The [UpdateChecker](../Code/src/EchoHub.Client/Services/UpdateChecker.cs.md) type is a sealed, disposable service that runs update checks on a background schedule and coordinates a safe, post-TUI update process. It listens for the underlying updater events, shows a confirmation UI (via the confirmation dialog flow described in the docs), and—when the user confirms—sets the public [PendingUpdate](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) delegate and requests the Terminal.Gui UI to stop so the host can perform the download/extract/restart work on a plain console. `Start()` only enables periodic checks in RELEASE builds, `CurrentVersion` exposes the assembly version (falling back to "0.0.0" if unavailable), and the checker attempts to create a pre-update snapshot by calling into [UpdateBackupService](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) before the heavy update work runs. The checker is consumed by the [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) and depends on [UpdateBackupService](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) for backup creation.
|
||||
|
||||
## UpdateBackupService.cs
|
||||
|
||||
Maintains backups for update-related data and state.
|
||||
|
||||
The [UpdateBackupService](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) is a static helper that centralizes pre-update snapshot and rollback metadata management. Its `CreateBackup()` routine snapshots `AppContext.BaseDirectory` into a `backup.zip` (skipping log files to avoid locking and using `CompressionLevel.Fastest`) and writes a `backup-info.json` that records the current version, application directory, and timestamp; it annotates that metadata using the `CurrentVersion` supplied by [UpdateChecker](../Code/src/EchoHub.Client/Services/UpdateChecker.cs.md). `BackupExists()` verifies that both the ZIP and the JSON exist, and `GetBackupInfo()` reads the stored metadata. Serialization for the `BackupInfo` metadata is handled by the source-generated [BackupJsonContext](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) to provide reflection-free `JsonSerializer` metadata. The service stores backups under the user profile at `~/.echohub/update-backup/`, depends on [UpdateChecker](../Code/src/EchoHub.Client/Services/UpdateChecker.cs.md) for the reported version, and is used by both the [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) and [UpdateChecker](../Code/src/EchoHub.Client/Services/UpdateChecker.cs.md).
|
||||
|
||||
## AppOrchestrator.cs
|
||||
|
||||
`AppOrchestrator` collaborates directly with `UpdateBackupService` and other members of this topic (2 dependency links).
|
||||
|
||||
The [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) is the TUI host and coordinator that declares UI components (like `MainWindow`) and the public [PendingUpdate](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) delegate referenced by the update flow. In this topic its role is to be the object that stores the pending, post-TUI update action that [UpdateChecker](../Code/src/EchoHub.Client/Services/UpdateChecker.cs.md) can set when the user accepts an update; the application or host must examine and invoke that [PendingUpdate](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) delegate after the Terminal.Gui main loop exits. `AppOrchestrator` depends on the backup and checker services to implement the safe update flow and is the natural boundary between the interactive UI and the plain-console updater.
|
||||
|
||||
How the pieces fit
|
||||
|
||||
- Update detection and user confirmation happen inside [UpdateChecker](../Code/src/EchoHub.Client/Services/UpdateChecker.cs.md) running on the Terminal.Gui main loop; when the user accepts an update, the checker defers the actual work by setting PendingUpdate and requesting the TUI to stop.
|
||||
- The deferred update work (ApplyUpdateAsync) calls into [UpdateBackupService](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) to snapshot the application: it writes backup.zip and backup-info.json (the serialized [BackupInfo](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) using [BackupJsonContext](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md)). Backup creation failures are logged but do not block the update.
|
||||
- The host is responsible for invoking PendingUpdate only after the TUI main loop has fully exited and the console is restored, at which point the update runs headless (and may restart the process).
|
||||
Update detection and user confirmation are handled by [UpdateChecker](../Code/src/EchoHub.Client/Services/UpdateChecker.cs.md), which runs periodically (in RELEASE builds) and listens for updater events. When an update is accepted the checker asks [UpdateBackupService](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) to create a snapshot, sets the [PendingUpdate](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) delegate on the [AppOrchestrator](../Code/src/EchoHub.Client/AppOrchestrator.cs.md), and requests the TUI to stop. After the Terminal.Gui main loop exits the host (or the orchestrator) must invoke the stored [PendingUpdate](../Code/src/EchoHub.Client/AppOrchestrator.cs.md) delegate to run the download/extract/restart work on a plain console; that work may restart the process and should be considered a non-returning operation. The backup metadata is serialized through the source-generated [BackupJsonContext](../Code/src/EchoHub.Client/Services/UpdateBackupService.cs.md) and stored under `~/.echohub/update-backup/` so the updater has a clear rollback artifact if needed.
|
||||
|
||||
---
|
||||
*Covers 2 of 2 source files identified for this topic.*
|
||||
*Covers 3 of 3 source files identified for this topic.*
|
||||
|
||||
*Synthesised by Aurion on 2026-07-23 05:54:19 UTC*
|
||||
*Synthesised by AurionDocs on 2026-07-23 09:33:37 UTC*
|
||||
|
||||
Reference in New Issue
Block a user