Skip to content

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

objectPluginSession

IDisposable, IAsyncDisposable

object.Equals(object?), object.Equals(object?, object?), object.GetHashCode(), object.GetType(), object.ReferenceEquals(object?, object?), object.ToString()

PluginServerJsonExtensions.InstallJsonAsync(PluginSession, string, SandboxPolicy?, CancellationToken)

The install/stage/promote surface lives in the PluginSession.Install.cs partial.

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

public void Dispose()

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources asynchronously.

public ValueTask DisposeAsync()

ValueTask

A task that represents the asynchronous dispose operation.

InstallAndWireAsync(PluginPackage, Action<InstalledKernel>, Func<PluginPackage, SandboxPolicy>?, Action<PluginPackage>?, CancellationToken)

Section titled “ 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 DotBoxD.Plugins.PluginServer.WireHook(DotBoxD.Plugins.Kernel.InstalledKernel,DotBoxD.Plugins.WireOptions) or DotBoxD.Plugins.PluginServer.WireSubscription(DotBoxD.Plugins.Kernel.InstalledKernel,DotBoxD.Plugins.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 `DotBoxD.Plugins.PluginSession.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)

package PluginPackage

wire Action<InstalledKernel>

policy Func<PluginPackage, SandboxPolicy>?

validate Action<PluginPackage>?

cancellationToken CancellationToken

ValueTask<InstalledKernel>

Opt-in convenience over public primitives: hand-write the equivalent with DotBoxD.Plugins.PluginSession.InstallStagedAsync(DotBoxD.Plugins.PluginPackage,DotBoxD.Kernels.SandboxPolicy,System.Threading.CancellationToken) + your wire action + DotBoxD.Plugins.PluginSession.Promote(DotBoxD.Plugins.Kernel.InstalledKernel) on success / DotBoxD.Plugins.PluginSession.Uninstall(System.String) by the staged kernel’s DotBoxD.Plugins.Kernel.InstalledKernel.InstallId on failure (passing the plugin id instead would target the live incumbent in a hot-replace, not the staged kernel). The validate and policy callbacks run before the session gate is held. The wire callback runs while the session gate is held, so it must only touch server-side routing (e.g. DotBoxD.Plugins.PluginServer.WireHook(DotBoxD.Plugins.Kernel.InstalledKernel,DotBoxD.Plugins.WireOptions) / DotBoxD.Plugins.PluginServer.WireSubscription(DotBoxD.Plugins.Kernel.InstalledKernel,DotBoxD.Plugins.WireOptions)) and must NOT call back into this session (DotBoxD.Plugins.PluginSession.InstallAsync(DotBoxD.Plugins.PluginPackage,DotBoxD.Kernels.SandboxPolicy,System.Threading.CancellationToken) / DotBoxD.Plugins.PluginSession.InstallStagedAsync(DotBoxD.Plugins.PluginPackage,DotBoxD.Kernels.SandboxPolicy,System.Threading.CancellationToken) / DotBoxD.Plugins.PluginSession.Promote(DotBoxD.Plugins.Kernel.InstalledKernel) / DotBoxD.Plugins.PluginSession.Uninstall(System.String) / DotBoxD.Plugins.PluginSession.Owns(System.String) / DotBoxD.Plugins.PluginSession.TryGetOwned(System.String,DotBoxD.Plugins.Kernel.InstalledKernel@) / DotBoxD.Plugins.PluginSession.UpdateSettingsAsync(System.String,System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object},System.Boolean,System.Threading.CancellationToken)), which would deadlock on the non-reentrant gate.

InstallAsync(PluginPackage, SandboxPolicy?, CancellationToken)

Section titled “ InstallAsync(PluginPackage, SandboxPolicy?, CancellationToken)”

Installs a package owned by this session. The install and the ownership bookkeeping are atomic with respect to DotBoxD.Plugins.PluginSession.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)

package PluginPackage

policy SandboxPolicy?

cancellationToken CancellationToken

ValueTask<InstalledKernel>

InstallServerExtensionAsync(PluginPackage, SandboxPolicy?, CancellationToken)

Section titled “ InstallServerExtensionAsync(PluginPackage, SandboxPolicy?, CancellationToken)”

Installs a server extension package owned by this session (see DotBoxD.Plugins.PluginServer.InstallServerExtensionAsync(DotBoxD.Plugins.PluginPackage,DotBoxD.Kernels.SandboxPolicy,System.Threading.CancellationToken)). Same ownership/atomicity guarantees as DotBoxD.Plugins.PluginSession.InstallAsync(DotBoxD.Plugins.PluginPackage,DotBoxD.Kernels.SandboxPolicy,System.Threading.CancellationToken); the kernel is invoked request/response via DotBoxD.Plugins.Kernel.InstalledKernel.InvokeServerExtensionAsync(System.Collections.Generic.IReadOnlyList{DotBoxD.Kernels.Sandbox.SandboxValue},System.Threading.CancellationToken) and revoked when the session is disposed.

public ValueTask<InstalledKernel> InstallServerExtensionAsync(PluginPackage package, SandboxPolicy? policy = null, CancellationToken cancellationToken = default)

package PluginPackage

policy SandboxPolicy?

cancellationToken CancellationToken

ValueTask<InstalledKernel>

InstallStagedAsync(PluginPackage, SandboxPolicy?, CancellationToken)

Section titled “ 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 DotBoxD.Plugins.PluginSession.Promote(DotBoxD.Plugins.Kernel.InstalledKernel) once the returned kernel is wired, or roll it back with DotBoxD.Plugins.PluginSession.Uninstall(System.String) using the returned kernel’s DotBoxD.Plugins.Kernel.InstalledKernel.InstallId (or by disposing the session). This is the public staging primitive behind DotBoxD.Plugins.PluginSession.InstallAndWireAsync(DotBoxD.Plugins.PluginPackage,System.Action{DotBoxD.Plugins.Kernel.InstalledKernel},System.Func{DotBoxD.Plugins.PluginPackage,DotBoxD.Kernels.SandboxPolicy},System.Action{DotBoxD.Plugins.PluginPackage},System.Threading.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)

package PluginPackage

policy SandboxPolicy?

cancellationToken CancellationToken

ValueTask<InstalledKernel>

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

public bool Owns(string pluginId)

pluginId string

bool

Promotes a kernel previously installed via DotBoxD.Plugins.PluginSession.InstallStagedAsync(DotBoxD.Plugins.PluginPackage,DotBoxD.Kernels.SandboxPolicy,System.Threading.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)

kernel 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 DotBoxD.Plugins.PluginSession.Owns(System.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)

pluginId string

kernel InstalledKernel

bool

public bool Uninstall(string pluginId)

pluginId string

bool

UpdateSettingsAsync(string, IReadOnlyDictionary<string, object?>, bool, CancellationToken)

Section titled “ 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)

pluginId string

values IReadOnlyDictionary<string, object?>

atomic bool

cancellationToken CancellationToken

ValueTask