Documentation Index
Fetch the complete documentation index at: https://mintlify.com/FarlandsModdingTeam/TerbinProyect/llms.txt
Use this file to discover all available pages before exploring further.
ExecutableDispatcher is the heart of Terbin’s IPC routing layer. It maintains two ConcurrentDictionary maps — one from ByteArrayKey to a list of TerbinExecutableDelegate handlers, and one from ByteArrayKey to a per-action CancellationTokenSource — ensuring that both registration and dispatch are fully thread-safe. TerbinExecutableManager wraps a private singleton instance of ExecutableDispatcher and exposes the same API as a set of static methods so service code never has to manage the dispatcher’s lifetime directly.
ByteArrayKey
Before examining the dispatcher, it helps to understand the key type it uses.
ByteArrayKey wraps a cloned byte[] and overrides GetHashCode / Equals so that two arrays with the same byte sequence are considered equal. This makes it suitable as a ConcurrentDictionary key where a plain byte[] reference comparison would fail.
ExecutableDispatcher
Internal State
| Field | Type | Purpose |
|---|---|---|
_handlers | ConcurrentDictionary<IEquatable<IEnumerable<byte>>, List<TerbinExecutableDelegate>> | Maps each action key to its ordered list of handlers. Multiple handlers per key are supported. |
_activeExecutionsByAction | ConcurrentDictionary<IEquatable<IEnumerable<byte>>, CancellationTokenSource> | One CancellationTokenSource per registered action key. Cancellation is scoped to the action, not the entire dispatcher. |
Per-Action CancellationTokenSource
When a new action key is registered for the first time, ExecutableDispatcher creates a fresh CancellationTokenSource for it and stores it in _activeExecutionsByAction. Every call to DispatchAsync retrieves this CTS and passes its .Token into TerbinExecutableHelper.ExecutionList. This means:
- Cancelling action
[20, 30]does not affect the execution of any other action key. - The same CTS is reused for all subsequent dispatches on that key until it is cancelled (via
CodeStatus.CancelByAction) and removed.
Methods
Register
pHandler under the byte key defined by pAction.Action. If the key already exists, the handler is appended to the existing list. If it is a new key, a new list and a new CancellationTokenSource are created atomically.
The attribute instance that carries the
byte[] action key. Throws ArgumentException if pAction.Action is empty.The handler delegate. Throws
ArgumentNullException if null.Unregister
pActions. Returns true if the key existed and was removed; false otherwise. Note: the associated CancellationTokenSource is not removed by Unregister — only by a CancelByAction dispatch.
The action key to remove. Pass a
ByteArrayKey or any IEquatable<IEnumerable<byte>> that equals the registered key.DispatchAsync
pActions, interprets pHead.Status, and invokes the appropriate logic.
Packet header. The
Status field drives which code path executes (see branch table below).Raw payload bytes forwarded to the handler(s).
The action key to look up. Typically
pCapsule.ActionMethod as supplied by the communicator.CodeStatus branch table:
CodeStatus.Execute (default)
CodeStatus.Execute (default)
The normal execution path. Retrieves the per-action CTS and calls
TerbinExecutableHelper.ExecutionList, which runs all handlers concurrently and returns the first non-null InfoResponse.This branch is the implicit default — the dispatcher deliberately avoids an explicit check for Execute so it is never compared in the hot path.CodeStatus.CheckExecution
CodeStatus.CheckExecution
Does not invoke any handler. Returns
InfoResponse.CreateSucces(pHead.IdRequest) immediately if at least one handler is registered for the key. Useful for clients that want to probe whether a service endpoint exists before sending real data.CodeStatus.CancelByAction
CodeStatus.CancelByAction
Attempts to remove and cancel the
CancellationTokenSource for the given action key. Returns InfoResponse.CreateSucces on success, or InfoResponse.Create(..., CodeStatus.ActionNotInitiated) if no CTS was found.CodeStatus.CancelByRequest
CodeStatus.CancelByRequest
Not yet implemented. Currently returns
null.| Condition | Returned CodeStatus |
|---|---|
No handler registered for pActions | CodeStatus.ActionNotFound |
| Handler throws an unhandled exception | CodeStatus.ExecutionException (payload contains serialized ExceptionDTO) |
pActions equals the Response key but no handler is found | Throws NotImplementedException |
TryGetEntity (static)
The full payload received by the handler.
The first byte of the payload, interpreted as an entity identifier.
The payload bytes after the entity byte. Empty array if payload was only one byte long.
false if pPayload is null or empty; true otherwise.RegisterFromAssembly
TerbinExecutableHelper.RegisterFromAssembly<TerbinExecutableAttribute, ExecutableDispatcher>(pAssembly, this). Scans all types and static methods in pAssembly, validates their signatures, and calls Register for each valid decorated method.
TerbinExecutableManager (static façade)
TerbinExecutableManager owns a private ExecutableDispatcher _dispatcher = new() and exposes the full IExecutableDispatcher surface as static methods. All service code should use TerbinExecutableManager rather than instantiating ExecutableDispatcher directly.
Dispatch inside the Worker
The communicator’sOnRecive event passes every received packet directly to TerbinExecutableManager.DispatchAsync:
ExecutableDispatcherSimple (obsolete)
ExecutableDispatcherSimple and its static façade TerbinExecutableManagerSimple are marked [Obsolete]. Both use a ConcurrentDictionary<byte, …> keyed only on a single byte and most of their methods throw NotImplementedException. Do not use them in new code.See Also
[TerbinExecutable]Attribute — how to annotate methods and configure action keys.- TerbinExecutor — the assembly scanner that feeds
TerbinExecutableManagerat startup.