Class PluginSession
Server-side owner of the kernels installed over one connection. Each kernel it installs is tagged with this session as its owner, so another session cannot replace or mutate it. Disposing the session — e.g. from a transport disconnect handler — revokes and unregisters every kernel it owns.
public sealed class PluginSession : IDisposable, IAsyncDisposable
- Inheritance
-
PluginSession
- Implements
- Inherited Members
- Extension Methods
Remarks
The install/stage/promote surface lives in the PluginSession.Install.cs partial.
Methods
Dispose()
Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
public void Dispose()
DisposeAsync()
Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources asynchronously.
public ValueTask DisposeAsync()
Returns
- ValueTask
A task that represents the asynchronous dispose operation.
InstallAndWireAsync(PluginPackage, Action<InstalledKernel>, Func<PluginPackage, SandboxPolicy>?, Action<PluginPackage>?, CancellationToken)
Installs an event-kernel package owned by this session and wires it in one step,
rolling the install back if validation or wiring fails — the install ceremony every host used to
hand-write. validate runs before install for host route checks;
policy overrides the default install policy; wire is the host's
routing choice (typically WireHook(InstalledKernel, WireOptions?) or
WireSubscription(InstalledKernel, WireOptions?) with host wire options).
The kernel is installed as a non-current instance, wired, and only then promoted to current — all under the session gate. So: a same-id incumbent is not revoked until wiring succeeds (a wiring failure rolls the new instance back by its exact install id with the incumbent still live and current), and a concurrent Dispose() cannot tear the kernel down mid-wire and leave a dangling handler. On any failure the original exception is rethrown.
Note: during a same-id hot-replace there is a brief window — between wiring the new kernel and promoting it (which revokes the incumbent) — in which both the outgoing and incoming kernels are wired, since pipeline handlers are keyed per kernel instance. A concurrent publish of the same event in that window may be observed by both kernels until promotion completes. (The first install of a given id has no incumbent and so no such window.)
Local-terminal packages use their callback route as replay identity: retrying the same owned package reuses the existing kernel, while reusing the callback route for a different package is rejected.
public ValueTask<InstalledKernel> InstallAndWireAsync(PluginPackage package, Action<InstalledKernel> wire, Func<PluginPackage, SandboxPolicy>? policy = null, Action<PluginPackage>? validate = null, CancellationToken cancellationToken = default)
Parameters
packagePluginPackagewireAction<InstalledKernel>policyFunc<PluginPackage, SandboxPolicy>validateAction<PluginPackage>cancellationTokenCancellationToken
Returns
Remarks
Opt-in convenience over public primitives: hand-write the equivalent with
InstallStagedAsync(PluginPackage, SandboxPolicy?, CancellationToken) + your wire action + Promote(InstalledKernel) on success /
Uninstall(string) by the staged kernel's InstallId on failure (passing
the plugin id instead would target the live incumbent in a hot-replace, not the staged kernel). The
wire callback runs while the session gate is held, so it must only touch server-side
routing (e.g. WireHook(InstalledKernel, WireOptions?) / WireSubscription(InstalledKernel, WireOptions?)) and must
NOT call back into this session (InstallAsync(PluginPackage, SandboxPolicy?, CancellationToken) / InstallStagedAsync(PluginPackage, SandboxPolicy?, CancellationToken) /
Promote(InstalledKernel) / Uninstall(string) / Owns(string) / TryGetOwned(string, out InstalledKernel) /
UpdateSettingsAsync(string, IReadOnlyDictionary<string, object?>, bool, CancellationToken)), which would deadlock on the non-reentrant gate.
InstallAsync(PluginPackage, SandboxPolicy?, CancellationToken)
Installs a package owned by this session. The install and the ownership bookkeeping are atomic with respect to Dispose(), so a kernel can never be installed-then-orphaned by a concurrent disconnect.
public ValueTask<InstalledKernel> InstallAsync(PluginPackage package, SandboxPolicy? policy = null, CancellationToken cancellationToken = default)
Parameters
packagePluginPackagepolicySandboxPolicycancellationTokenCancellationToken
Returns
InstallServerExtensionAsync(PluginPackage, SandboxPolicy?, CancellationToken)
Installs a server extension package owned by this session (see InstallServerExtensionAsync(PluginPackage, SandboxPolicy?, CancellationToken)). Same ownership/atomicity guarantees as InstallAsync(PluginPackage, SandboxPolicy?, CancellationToken); the kernel is invoked request/response via InvokeServerExtensionAsync(IReadOnlyList<SandboxValue>, CancellationToken) and revoked when the session is disposed.
public ValueTask<InstalledKernel> InstallServerExtensionAsync(PluginPackage package, SandboxPolicy? policy = null, CancellationToken cancellationToken = default)
Parameters
packagePluginPackagepolicySandboxPolicycancellationTokenCancellationToken
Returns
InstallStagedAsync(PluginPackage, SandboxPolicy?, CancellationToken)
Installs package owned by this session as a non-current instance: a same-id
incumbent (if any) stays current and un-revoked. Pair with Promote(InstalledKernel) once the returned kernel
is wired, or roll it back with Uninstall(string) using the returned kernel's
InstallId (or by disposing the session). This is the public staging primitive
behind InstallAndWireAsync(PluginPackage, Action<InstalledKernel>, Func<PluginPackage, SandboxPolicy>?, Action<PluginPackage>?, CancellationToken) — it lets a host wire a kernel before it displaces the
incumbent, so the helper's behavior is reproducible by hand with public API.
public ValueTask<InstalledKernel> InstallStagedAsync(PluginPackage package, SandboxPolicy? policy = null, CancellationToken cancellationToken = default)
Parameters
packagePluginPackagepolicySandboxPolicycancellationTokenCancellationToken
Returns
Owns(string)
Whether this (non-disposed) session currently owns pluginId.
public bool Owns(string pluginId)
Parameters
pluginIdstring
Returns
Promote(InstalledKernel)
Promotes a kernel previously installed via InstallStagedAsync(PluginPackage, SandboxPolicy?, CancellationToken) to be the current kernel for its plugin id, revoking and detaching any prior same-id incumbent only now (so a pre-promotion failure leaves the incumbent live). Rejects a kernel this session does not own. A local-terminal kernel has no current-kernel semantics, so promotion is a no-op for it.
public void Promote(InstalledKernel kernel)
Parameters
kernelInstalledKernel
TryGetOwned(string, out InstalledKernel)
Atomically fetches the kernel currently registered under pluginId AND verifies this
session owns it, returning that exact instance. Use this instead of a separate Owns(string) + registry
lookup so authorization binds to the kernel actually returned — there is no window in which a same-id
hot-replace could swap a different kernel in between the check and the fetch.
public bool TryGetOwned(string pluginId, out InstalledKernel kernel)
Parameters
pluginIdstringkernelInstalledKernel
Returns
Uninstall(string)
public bool Uninstall(string pluginId)
Parameters
pluginIdstring
Returns
UpdateSettingsAsync(string, IReadOnlyDictionary<string, object?>, bool, CancellationToken)
Updates live settings for a kernel this session owns. Rejects ids the session does not own so one plugin cannot tune another plugin's kernel.
public ValueTask UpdateSettingsAsync(string pluginId, IReadOnlyDictionary<string, object?> values, bool atomic = false, CancellationToken cancellationToken = default)
Parameters
pluginIdstringvaluesIReadOnlyDictionary<string, object>atomicboolcancellationTokenCancellationToken