Table of Contents

Class PluginSession

Namespace
DotBoxD.Plugins
Assembly
DotBoxD.Plugins.dll

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

package PluginPackage
wire Action<InstalledKernel>
policy Func<PluginPackage, SandboxPolicy>
validate Action<PluginPackage>
cancellationToken CancellationToken

Returns

ValueTask<InstalledKernel>

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

package PluginPackage
policy SandboxPolicy
cancellationToken CancellationToken

Returns

ValueTask<InstalledKernel>

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

package PluginPackage
policy SandboxPolicy
cancellationToken CancellationToken

Returns

ValueTask<InstalledKernel>

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

package PluginPackage
policy SandboxPolicy
cancellationToken CancellationToken

Returns

ValueTask<InstalledKernel>

Owns(string)

Whether this (non-disposed) session currently owns pluginId.

public bool Owns(string pluginId)

Parameters

pluginId string

Returns

bool

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

kernel InstalledKernel

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

pluginId string
kernel InstalledKernel

Returns

bool

Uninstall(string)

public bool Uninstall(string pluginId)

Parameters

pluginId string

Returns

bool

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

pluginId string
values IReadOnlyDictionary<string, object>
atomic bool
cancellationToken CancellationToken

Returns

ValueTask