mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-04 07:45:30 +00:00
131 lines
6.0 KiB
Markdown
131 lines
6.0 KiB
Markdown
# Window Capability RPC Architecture
|
|
|
|
This document defines the internal communication contract between the main window and desktop child windows.
|
|
|
|
## 1. Ownership
|
|
|
|
- The main window is the only owner of the Gopeed runtime, Gopeed API connection, and Hive database.
|
|
- Child windows must never initialize `libgopeed`, initialize the Gopeed HTTP client, or open a Hive box.
|
|
- Child windows access application capabilities through `AppCapabilities` only.
|
|
- Immutable window launch input, such as the window type and an initial create-task request, may use `AppWindowPayload`.
|
|
- API addresses, API tokens, appearance state, locale, and persisted data must not be placed in launch payloads.
|
|
|
|
## 2. Layers
|
|
|
|
```text
|
|
Presentation / Riverpod controllers
|
|
|
|
|
AppCapabilities
|
|
/ \
|
|
GopeedService AppStorageService
|
|
\ /
|
|
CapabilityInvoker
|
|
/ \
|
|
LocalCapability WindowCapability
|
|
Invoker Invoker
|
|
| |
|
|
CapabilityRegistry WindowMethodChannel
|
|
| |
|
|
Gopeed HTTP/FFI + Hive in the main window
|
|
```
|
|
|
|
The presentation layer must not branch on whether it is running in a main or child window. The root `ProviderScope` selects the local or remote capability implementation.
|
|
|
|
## 3. RPC Contract
|
|
|
|
Every operation is declared once as a typed `RpcMethod<P, R>`:
|
|
|
|
```dart
|
|
static const resolve = RpcMethod<ResolveTask, ResolveResult>('gopeed.resolve');
|
|
```
|
|
|
|
Rules:
|
|
|
|
- Operation names are stable protocol identifiers and must be declared in a capability method catalog.
|
|
- Do not duplicate operation strings in pages, controllers, host handlers, or clients.
|
|
- Do not create one MethodChannel per operation.
|
|
- Do not expose Gopeed HTTP paths through the internal capability API.
|
|
- Multi-argument operations should use a JSON map or a dedicated request DTO.
|
|
- Prefer a dedicated request DTO when parameters have domain meaning or are likely to evolve.
|
|
|
|
`RpcCodecRegistry` owns serialization. Encoding is generic for JSON primitives, collections, enums, and models with `toJson()`. Each non-primitive response or request model registers its `fromJson` decoder once. Individual operations must not repeat request and response codec closures.
|
|
|
|
The local invoker calls the typed handler directly and does not perform a JSON round trip. Serialization occurs only at a window boundary.
|
|
|
|
## 4. Transport
|
|
|
|
Child-to-main requests use one unidirectional `WindowMethodChannel`:
|
|
|
|
```text
|
|
gopeed.app.capabilities.v1
|
|
```
|
|
|
|
The transport uses one method, `capability.call`, with an operation name and JSON payload. Results use a common success/error envelope. MethodChannel provides request-response correlation, so the protocol does not add request IDs for ordinary calls.
|
|
|
|
The existing HTTP `HostRpcService` is an external browser-extension integration and is not the internal window capability transport. Its `/forward` endpoint must not be reused by child windows.
|
|
|
|
## 5. Events And State Synchronization
|
|
|
|
Main-to-child events use each child's `WindowController` channel. A child registers its method handler before subscribing.
|
|
|
|
Initialization order:
|
|
|
|
1. The child registers its window event handler.
|
|
2. The child requests the current appearance snapshot.
|
|
3. The child applies the snapshot.
|
|
4. The child subscribes with its window ID.
|
|
5. The main window stores the controller and immediately sends the current snapshot again.
|
|
6. Later state changes are broadcast to every subscribed child.
|
|
|
|
Events contain complete state snapshots, not patches. No revision field is required. Event names are declared centrally in `AppWindowRpcProtocol`.
|
|
|
|
Appearance synchronization uses `appearance.changed` and currently contains:
|
|
|
|
- Theme mode
|
|
- Theme color
|
|
- Locale
|
|
|
|
State broadcasting must observe the owning Riverpod state centrally. Do not broadcast directly from a settings button callback, because updates can originate from configuration loading, system changes, or future entry points.
|
|
|
|
## 6. Storage
|
|
|
|
- `Database` remains the low-level Hive implementation and is main-window infrastructure.
|
|
- Product code used by child windows depends on `AppStorageService`.
|
|
- Storage RPC methods expose business capabilities such as create-history operations, not raw `box.get` or `box.put` access.
|
|
- Prefer batch mutations across the window boundary. For example, save all parsed URLs in one `saveCreateHistory(List<String>)` call.
|
|
- New child-window storage requirements must be added to `StorageMethods` and bound in the main registry.
|
|
|
|
## 7. Gopeed Backend Migration
|
|
|
|
All structured task, configuration, extension, and webhook operations are exposed through `GopeedService`. The local registry currently binds them to `lib/api/api.dart`.
|
|
|
|
When the backend moves to FFI:
|
|
|
|
- Replace the main-window local bindings or their underlying implementation.
|
|
- Keep `GopeedMethods`, `GopeedService`, child-window transport, pages, and controllers unchanged.
|
|
- Keep raw HTTP proxy functionality separate unless an explicit capability contract is introduced for it.
|
|
|
|
## 8. Adding A Capability
|
|
|
|
1. Add one typed `RpcMethod` to the appropriate method catalog.
|
|
2. Register a model decoder once if a new non-primitive type crosses the boundary.
|
|
3. Add the strongly typed facade method to the capability service.
|
|
4. Bind the method to the main-window implementation in `LocalAppCapabilities`.
|
|
5. Use the facade from a Riverpod controller or page.
|
|
6. Add tests for local typed dispatch and serialized dispatch.
|
|
7. For events, add one centralized event name and broadcast a complete snapshot.
|
|
|
|
## 9. Prohibited Patterns
|
|
|
|
Child-window code must not:
|
|
|
|
- Import `lib/api/api.dart`.
|
|
- Call `api.init` or access the Gopeed socket/address/token.
|
|
- Import or access `Database.instance`.
|
|
- Open Hive boxes.
|
|
- Receive API configuration or persisted data through `AppWindowPayload`.
|
|
- Add feature-specific MethodChannels.
|
|
- Parse RPC JSON directly inside a page or widget.
|
|
|
|
These constraints keep all backend and persistence ownership in the main window and allow multiple child windows to operate concurrently without database locks or duplicated Gopeed runtimes.
|