mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
Add external public IPC host/client and plugin SDK
Introduce a new LanMountainDesktop.Shared.IPC project implementing a public IPC host and client (LanMountainDesktopIpcClient, PublicIpcHostService), IPC constants and routed notify IDs, DTOs and DI helpers for registering public services. Update Plugin SDK to allow plugins to contribute public IPC services and registrations, add related descriptors/records and extension helpers. Migrate Launcher/App to use the new public IPC for startup/loading notifications and wiring (including TryConnect helper), switch LoadingStateReporter to use the external notification publisher, and add host-side public services (app info, shell control, plugin catalog). Include integration tests and spec/checklist/docs for the external IPC public API.
This commit is contained in:
@@ -218,6 +218,16 @@ Two new supporting packages define the isolation boundary:
|
||||
|
||||
For the detailed design, migration path, UI strategy, and residual risks, see `docs/PLUGIN_PROCESS_ISOLATION_ARCHITECTURE.md`.
|
||||
|
||||
## External IPC Public API
|
||||
|
||||
- The current IPC mainline is external integration, not plugin process isolation.
|
||||
- `LanMountainDesktop.Shared.IPC` is the unified IPC base for Host public services, Launcher/OOBE startup notifications, and plugin-contributed public services.
|
||||
- Strongly typed command/query access uses `[IpcPublic]` contracts plus `dotnetCampus.Ipc` generated proxy/joint support.
|
||||
- One-way events use `JsonIpcDirectRoutedProvider.NotifyAsync` with fixed top-level notify IDs.
|
||||
- Host remains the single external IPC entry point even when a capability is contributed by a plugin.
|
||||
|
||||
See `docs/EXTERNAL_IPC_ARCHITECTURE.md` for the detailed contract and migration model.
|
||||
|
||||
## Launcher OOBE / Elevation Contract
|
||||
|
||||
- Launcher OOBE state is owned by a per-user JSON file under `%LOCALAPPDATA%\LanMountainDesktop\.launcher\state\oobe-state.json`.
|
||||
|
||||
125
docs/EXTERNAL_IPC_ARCHITECTURE.md
Normal file
125
docs/EXTERNAL_IPC_ARCHITECTURE.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# External IPC Architecture
|
||||
|
||||
## Scope
|
||||
|
||||
This document defines the current external integration IPC baseline for LanMountainDesktop.
|
||||
|
||||
- The delivery focus is external application integration, not plugin process isolation.
|
||||
- `dotnetCampus.Ipc` is the single IPC foundation for Host public APIs, Launcher/OOBE startup notifications, and plugin-contributed external services.
|
||||
- Process isolation remains a future track and stays documented in `docs/PLUGIN_PROCESS_ISOLATION_ARCHITECTURE.md`.
|
||||
|
||||
## Design Summary
|
||||
|
||||
The public IPC stack is split into two complementary layers:
|
||||
|
||||
1. Strongly typed public services
|
||||
- Contracts are marked with `[IpcPublic]`.
|
||||
- Host exposes service instances through `CreateIpcJoint<TContract>(instance)`.
|
||||
- .NET clients connect once and obtain strong typed proxies through `CreateIpcProxy<TContract>(peer)`.
|
||||
2. Routed notifications
|
||||
- `JsonIpcDirectRoutedProvider.NotifyAsync` is used for one-way event delivery.
|
||||
- Startup progress, loading-state updates, catalog changed events, and plugin live events all use routed notify IDs.
|
||||
|
||||
This keeps command/query calls explicit and strongly typed while still giving plugins and Launcher a lightweight event channel.
|
||||
|
||||
## Projects
|
||||
|
||||
- `LanMountainDesktop.Shared.IPC`
|
||||
- Public IPC constants, routed notify IDs, DTOs, strong-typed public service contracts, host/client helpers, and DI registration helpers.
|
||||
- `LanMountainDesktop`
|
||||
- Runs `PublicIpcHostService`, exposes built-in public services, and folds plugin-contributed services into one external catalog.
|
||||
- `LanMountainDesktop.Launcher`
|
||||
- Connects to the Host public pipe and listens for startup and loading-state notifications instead of running a custom length-prefixed IPC server.
|
||||
- `LanMountainDesktop.PluginSdk`
|
||||
- Adds `IPluginPublicIpcContributor`, `IPluginPublicIpcBuilder`, and `AddPluginPublicIpc(...)`.
|
||||
|
||||
## Built-in Public Services
|
||||
|
||||
Current built-in `[IpcPublic]` contracts:
|
||||
|
||||
- `IPublicAppInfoService`
|
||||
- Returns application metadata such as version, codename, process id, pipe name, and startup time.
|
||||
- `IPublicShellControlService`
|
||||
- Allows external .NET clients to activate the shell, open settings, request restart, and request exit.
|
||||
- `IPublicPluginCatalogService`
|
||||
- Returns the merged public IPC catalog snapshot exposed by Host.
|
||||
|
||||
## Routed Notify IDs
|
||||
|
||||
Current fixed routed notify IDs:
|
||||
|
||||
- `lanmountain.catalog.changed`
|
||||
- `lanmountain.launcher.startup-progress`
|
||||
- `lanmountain.launcher.loading-state`
|
||||
|
||||
The fixed routed surface is intentionally small. Runtime variation happens in the service catalog and in plugin-contributed service instances, not in ad-hoc top-level route registration after startup.
|
||||
|
||||
## Host Lifecycle
|
||||
|
||||
`PublicIpcHostService` is started during Host application startup and remains the single external IPC entry point.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- Start a named `dotnetCampus.Ipc` provider.
|
||||
- Register fixed request routes before `StartServer()`.
|
||||
- Expose built-in strong-typed public services.
|
||||
- Maintain the merged service catalog.
|
||||
- Publish startup and loading-state notifications to connected clients.
|
||||
- Accept plugin-contributed public services after plugin load.
|
||||
|
||||
## Launcher / OOBE Migration
|
||||
|
||||
Launcher no longer depends on the previous custom named-pipe length-prefixed protocol as the primary path.
|
||||
|
||||
- Host publishes `StartupProgressMessage` through `lanmountain.launcher.startup-progress`.
|
||||
- Host publishes `LoadingStateMessage` through `lanmountain.launcher.loading-state`.
|
||||
- Launcher connects as a normal public IPC client and subscribes to those routed notifications.
|
||||
|
||||
This means Splash/OOBE is now just another IPC consumer on the same base transport used by external integrators.
|
||||
|
||||
## Plugin Public IPC Contribution Model
|
||||
|
||||
Plugins can contribute new external IPC services in two ways:
|
||||
|
||||
1. Declarative registration
|
||||
- `services.AddPluginPublicIpc<TContract, TImplementation>(...)`
|
||||
2. Advanced contributor
|
||||
- Register `IPluginPublicIpcContributor`
|
||||
- Use `IPluginPublicIpcBuilder` to contribute services from plugin DI
|
||||
|
||||
At plugin load time the Host runtime:
|
||||
|
||||
- discovers `PluginPublicIpcServiceRegistration`
|
||||
- executes `IPluginPublicIpcContributor`
|
||||
- validates that contributed contracts are `[IpcPublic]` interfaces
|
||||
- registers the resolved instances into `PublicIpcHostService`
|
||||
- emits `lanmountain.catalog.changed`
|
||||
|
||||
Plugins can also inject `IExternalIpcNotificationPublisher` and translate internal DI/message-bus events into routed notifications such as:
|
||||
|
||||
- `lanmountain.plugin.{pluginId}.attendance.updated`
|
||||
- `lanmountain.plugin.{pluginId}.status.changed`
|
||||
|
||||
## Service Catalog
|
||||
|
||||
The public catalog is represented by `PublicIpcCatalogSnapshot` and includes:
|
||||
|
||||
- built-in and plugin-provided public services
|
||||
- contract type metadata
|
||||
- optional object id
|
||||
- owning `pluginId` for plugin services
|
||||
- declared notify IDs
|
||||
- current loaded/enabled plugin list
|
||||
|
||||
This catalog is available through:
|
||||
|
||||
- strong-typed public service `IPublicPluginCatalogService`
|
||||
- fixed request route `lanmountain.catalog.get`
|
||||
- routed notify `lanmountain.catalog.changed`
|
||||
|
||||
## Current Limitations
|
||||
|
||||
- Strong-typed proxy/joint support is .NET-first.
|
||||
- Plugin service removal is still restart-bound. New services can be added at runtime, but service removal is not yet modeled as a live unload contract.
|
||||
- Cross-language clients still need a .NET bridge or sidecar if they want to consume `[IpcPublic]` contracts directly.
|
||||
- Plugin process isolation is not part of this delivery. That remains future work.
|
||||
@@ -559,3 +559,13 @@ var updateCheckService = new UpdateCheckService(
|
||||
- `apply-update`, `plugin-install`, and `debug-preview` must not auto-enter OOBE.
|
||||
- Allowed elevation paths are limited to the installer itself, full installer update application, and user-confirmed legacy uninstall.
|
||||
- Default plugin installation targets the current user's LocalAppData scope and must not request elevation by default.
|
||||
|
||||
## Public IPC Baseline
|
||||
|
||||
Launcher now consumes Host startup telemetry from the unified public IPC stack:
|
||||
|
||||
- Host publishes `StartupProgressMessage` via `lanmountain.launcher.startup-progress`
|
||||
- Host publishes `LoadingStateMessage` via `lanmountain.launcher.loading-state`
|
||||
- Launcher connects through `LanMountainDesktopIpcClient`
|
||||
|
||||
The previous custom length-prefixed named-pipe transport is no longer the primary startup communication path.
|
||||
|
||||
@@ -684,3 +684,34 @@ if (!url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
- [组件开发指南](COMPONENT_DEVELOPMENT.md)
|
||||
- [API 参考](API_REFERENCE.md)
|
||||
- [架构文档](ARCHITECTURE.md)
|
||||
## Public IPC Extension
|
||||
|
||||
Plugins can now contribute external IPC capabilities through the Host public IPC entry point.
|
||||
|
||||
Recommended registration styles:
|
||||
|
||||
```csharp
|
||||
services.AddPluginPublicIpc<IMyPluginPublicService, MyPluginPublicService>(
|
||||
objectId: "default",
|
||||
notifyIds: ["lanmountain.plugin.my-plugin.status.changed"]);
|
||||
```
|
||||
|
||||
Or use the advanced contributor model:
|
||||
|
||||
```csharp
|
||||
public sealed class MyPluginPublicIpcContributor : IPluginPublicIpcContributor
|
||||
{
|
||||
public void ConfigurePublicIpc(IPluginPublicIpcBuilder builder)
|
||||
{
|
||||
builder.AddService<IMyPluginPublicService>(
|
||||
objectId: "default",
|
||||
notifyIds: ["lanmountain.plugin.my-plugin.status.changed"]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Additional notes:
|
||||
|
||||
- Public IPC contracts must be interfaces marked with `[IpcPublic]`.
|
||||
- External .NET clients can reference the plugin contract assembly and create strong-typed proxies through the Host public pipe.
|
||||
- Plugins can inject `IExternalIpcNotificationPublisher` to push live events outward through routed notifications.
|
||||
|
||||
Reference in New Issue
Block a user