Merge branch 'fix/archreview-p2' into main (P2 tier: completeness & polish)
# Conflicts: # archreview/remediation/00-tracking.md # clients/dotnet/ZB.MOM.WW.MxGateway.Client.Cli/MxGatewayCliSecretRedactor.cs # clients/dotnet/ZB.MOM.WW.MxGateway.Client.Cli/MxGatewayClientCli.cs # src/ZB.MOM.WW.MxGateway.Worker.Tests/Ipc/WorkerFrameProtocolTests.cs
This commit is contained in:
@@ -848,6 +848,525 @@ public sealed class MxGatewaySession : IAsyncDisposable
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters a previously registered client from the MXAccess session
|
||||
/// (MXAccess <c>Unregister</c>), releasing its ServerHandle.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
public async Task UnregisterAsync(
|
||||
int serverHandle,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await UnregisterRawAsync(serverHandle, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters a previously registered client without error checking.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> UnregisterRawAsync(
|
||||
int serverHandle,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.Unregister,
|
||||
Unregister = new UnregisterCommand { ServerHandle = serverHandle },
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to supervisory events for an item (MXAccess <c>AdviseSupervisory</c>).
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
public async Task AdviseSupervisoryAsync(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await AdviseSupervisoryRawAsync(serverHandle, itemHandle, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to supervisory events for an item without error checking.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> AdviseSupervisoryRawAsync(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.AdviseSupervisory,
|
||||
AdviseSupervisory = new AdviseSupervisoryCommand
|
||||
{
|
||||
ServerHandle = serverHandle,
|
||||
ItemHandle = itemHandle,
|
||||
},
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a buffered item to the MXAccess session (MXAccess <c>AddBufferedItem</c>),
|
||||
/// returning an ItemHandle.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemDefinition">The item tag address.</param>
|
||||
/// <param name="itemContext">Additional context for the item.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The item handle assigned to the new buffered item.</returns>
|
||||
public async Task<int> AddBufferedItemAsync(
|
||||
int serverHandle,
|
||||
string itemDefinition,
|
||||
string itemContext,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await AddBufferedItemRawAsync(
|
||||
serverHandle,
|
||||
itemDefinition,
|
||||
itemContext,
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
return reply.AddBufferedItem?.ItemHandle ?? reply.ReturnValue.Int32Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a buffered item to the MXAccess session without error checking.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemDefinition">The item tag address.</param>
|
||||
/// <param name="itemContext">Additional context for the item.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> AddBufferedItemRawAsync(
|
||||
int serverHandle,
|
||||
string itemDefinition,
|
||||
string itemContext,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(itemDefinition);
|
||||
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.AddBufferedItem,
|
||||
AddBufferedItem = new AddBufferedItemCommand
|
||||
{
|
||||
ServerHandle = serverHandle,
|
||||
ItemDefinition = itemDefinition,
|
||||
ItemContext = itemContext ?? string.Empty,
|
||||
},
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the buffered-item update interval on the MXAccess session
|
||||
/// (MXAccess <c>SetBufferedUpdateInterval</c>).
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="updateIntervalMilliseconds">The buffered update interval, in milliseconds.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
public async Task SetBufferedUpdateIntervalAsync(
|
||||
int serverHandle,
|
||||
int updateIntervalMilliseconds,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await SetBufferedUpdateIntervalRawAsync(
|
||||
serverHandle,
|
||||
updateIntervalMilliseconds,
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the buffered-item update interval without error checking.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="updateIntervalMilliseconds">The buffered update interval, in milliseconds.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> SetBufferedUpdateIntervalRawAsync(
|
||||
int serverHandle,
|
||||
int updateIntervalMilliseconds,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.SetBufferedUpdateInterval,
|
||||
SetBufferedUpdateInterval = new SetBufferedUpdateIntervalCommand
|
||||
{
|
||||
ServerHandle = serverHandle,
|
||||
UpdateIntervalMilliseconds = updateIntervalMilliseconds,
|
||||
},
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suspends updates for an item (MXAccess <c>Suspend</c>).
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The item's MXSTATUS_PROXY as reported by the worker, or <c>null</c> if the reply omitted it.</returns>
|
||||
public async Task<MxStatusProxy?> SuspendAsync(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await SuspendRawAsync(serverHandle, itemHandle, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
return reply.Suspend?.Status;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suspends updates for an item without error checking.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> SuspendRawAsync(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.Suspend,
|
||||
Suspend = new SuspendCommand
|
||||
{
|
||||
ServerHandle = serverHandle,
|
||||
ItemHandle = itemHandle,
|
||||
},
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resumes updates for a suspended item (MXAccess <c>Activate</c>).
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The item's MXSTATUS_PROXY as reported by the worker, or <c>null</c> if the reply omitted it.</returns>
|
||||
public async Task<MxStatusProxy?> ActivateAsync(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await ActivateRawAsync(serverHandle, itemHandle, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
return reply.Activate?.Status;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resumes updates for a suspended item without error checking.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> ActivateRawAsync(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.Activate,
|
||||
Activate = new ActivateCommand
|
||||
{
|
||||
ServerHandle = serverHandle,
|
||||
ItemHandle = itemHandle,
|
||||
},
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a secured value to an item on the MXAccess server (MXAccess <c>WriteSecured</c>).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// MXAccess parity: <c>WriteSecured</c> fails when it is issued before a value-bearing
|
||||
/// NMX body or before a prior <c>AuthenticateUser</c> + <c>AdviseSupervisory</c>. That
|
||||
/// native failure is surfaced unchanged — the client does not pre-validate or reorder it.
|
||||
/// The <paramref name="value"/> is credential-sensitive and must never reach logs; the
|
||||
/// client mirrors the single-item WriteSecured redaction contract.
|
||||
/// </remarks>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="value">The secured value to write.</param>
|
||||
/// <param name="currentUserId">The current operator user id.</param>
|
||||
/// <param name="verifierUserId">The verifier (secondary approver) user id.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
public async Task WriteSecuredAsync(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
MxValue value,
|
||||
int currentUserId,
|
||||
int verifierUserId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await WriteSecuredRawAsync(
|
||||
serverHandle,
|
||||
itemHandle,
|
||||
value,
|
||||
currentUserId,
|
||||
verifierUserId,
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a secured value to an item without error checking. See
|
||||
/// <see cref="WriteSecuredAsync"/> for the parity and redaction contract.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="value">The secured value to write.</param>
|
||||
/// <param name="currentUserId">The current operator user id.</param>
|
||||
/// <param name="verifierUserId">The verifier (secondary approver) user id.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> WriteSecuredRawAsync(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
MxValue value,
|
||||
int currentUserId,
|
||||
int verifierUserId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.WriteSecured,
|
||||
WriteSecured = new WriteSecuredCommand
|
||||
{
|
||||
ServerHandle = serverHandle,
|
||||
ItemHandle = itemHandle,
|
||||
CurrentUserId = currentUserId,
|
||||
VerifierUserId = verifierUserId,
|
||||
Value = value,
|
||||
},
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a secured value and timestamp to an item (MXAccess <c>WriteSecured2</c>).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same parity and redaction contract as <see cref="WriteSecuredAsync"/>: the native
|
||||
/// failure that occurs before a value-bearing NMX body or a prior authenticate is
|
||||
/// surfaced unchanged, and the credential-sensitive <paramref name="value"/> must never
|
||||
/// reach logs.
|
||||
/// </remarks>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="value">The secured value to write.</param>
|
||||
/// <param name="timestampValue">The timestamp to write with the value.</param>
|
||||
/// <param name="currentUserId">The current operator user id.</param>
|
||||
/// <param name="verifierUserId">The verifier (secondary approver) user id.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
public async Task WriteSecured2Async(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
MxValue value,
|
||||
MxValue timestampValue,
|
||||
int currentUserId,
|
||||
int verifierUserId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await WriteSecured2RawAsync(
|
||||
serverHandle,
|
||||
itemHandle,
|
||||
value,
|
||||
timestampValue,
|
||||
currentUserId,
|
||||
verifierUserId,
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a secured value and timestamp to an item without error checking. See
|
||||
/// <see cref="WriteSecured2Async"/> for the parity and redaction contract.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="itemHandle">The ItemHandle from add-item.</param>
|
||||
/// <param name="value">The secured value to write.</param>
|
||||
/// <param name="timestampValue">The timestamp to write with the value.</param>
|
||||
/// <param name="currentUserId">The current operator user id.</param>
|
||||
/// <param name="verifierUserId">The verifier (secondary approver) user id.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> WriteSecured2RawAsync(
|
||||
int serverHandle,
|
||||
int itemHandle,
|
||||
MxValue value,
|
||||
MxValue timestampValue,
|
||||
int currentUserId,
|
||||
int verifierUserId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
ArgumentNullException.ThrowIfNull(timestampValue);
|
||||
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.WriteSecured2,
|
||||
WriteSecured2 = new WriteSecured2Command
|
||||
{
|
||||
ServerHandle = serverHandle,
|
||||
ItemHandle = itemHandle,
|
||||
CurrentUserId = currentUserId,
|
||||
VerifierUserId = verifierUserId,
|
||||
Value = value,
|
||||
TimestampValue = timestampValue,
|
||||
},
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authenticates an MXAccess verify-user (MXAccess <c>AuthenticateUser</c>), returning
|
||||
/// the resolved user id used by <c>WriteSecured</c> / <c>WriteSecured2</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <paramref name="verifyUserPassword"/> is a raw MXAccess credential. It is never
|
||||
/// logged and never placed on the exception path: gateway/MXAccess failures surface only
|
||||
/// reply-derived diagnostics (kind, HRESULT, MXSTATUS_PROXY), never the request payload.
|
||||
/// </remarks>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="verifyUser">The user to verify.</param>
|
||||
/// <param name="verifyUserPassword">The verify-user credential. Never logged.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The authenticated user id.</returns>
|
||||
public async Task<int> AuthenticateUserAsync(
|
||||
int serverHandle,
|
||||
string verifyUser,
|
||||
string verifyUserPassword,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await AuthenticateUserRawAsync(
|
||||
serverHandle,
|
||||
verifyUser,
|
||||
verifyUserPassword,
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
return reply.AuthenticateUser?.UserId ?? reply.ReturnValue.Int32Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authenticates an MXAccess verify-user without error checking. See
|
||||
/// <see cref="AuthenticateUserAsync"/> for the credential-handling contract.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="verifyUser">The user to verify.</param>
|
||||
/// <param name="verifyUserPassword">The verify-user credential. Never logged.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> AuthenticateUserRawAsync(
|
||||
int serverHandle,
|
||||
string verifyUser,
|
||||
string verifyUserPassword,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(verifyUser);
|
||||
ArgumentNullException.ThrowIfNull(verifyUserPassword);
|
||||
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.AuthenticateUser,
|
||||
AuthenticateUser = new AuthenticateUserCommand
|
||||
{
|
||||
ServerHandle = serverHandle,
|
||||
VerifyUser = verifyUser,
|
||||
VerifyUserPassword = verifyUserPassword,
|
||||
},
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves an ArchestrA user GUID to its MXAccess user id
|
||||
/// (MXAccess <c>ArchestrAUserToId</c>).
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="userIdGuid">The ArchestrA user GUID to resolve.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The resolved MXAccess user id.</returns>
|
||||
public async Task<int> ArchestraUserToIdAsync(
|
||||
int serverHandle,
|
||||
string userIdGuid,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
MxCommandReply reply = await ArchestraUserToIdRawAsync(serverHandle, userIdGuid, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
reply.EnsureProtocolSuccess().EnsureMxAccessSuccess();
|
||||
return reply.ArchestraUserToId?.UserId ?? reply.ReturnValue.Int32Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves an ArchestrA user GUID to its MXAccess user id without error checking.
|
||||
/// </summary>
|
||||
/// <param name="serverHandle">The ServerHandle from register.</param>
|
||||
/// <param name="userIdGuid">The ArchestrA user GUID to resolve.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The raw server reply.</returns>
|
||||
public Task<MxCommandReply> ArchestraUserToIdRawAsync(
|
||||
int serverHandle,
|
||||
string userIdGuid,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(userIdGuid);
|
||||
|
||||
return InvokeCommandAsync(
|
||||
new MxCommand
|
||||
{
|
||||
Kind = MxCommandKind.ArchestraUserToId,
|
||||
ArchestraUserToId = new ArchestrAUserToIdCommand
|
||||
{
|
||||
ServerHandle = serverHandle,
|
||||
UserIdGuid = userIdGuid,
|
||||
},
|
||||
},
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes an MXAccess command on this session.
|
||||
/// </summary>
|
||||
@@ -881,6 +1400,34 @@ public sealed class MxGatewaySession : IAsyncDisposable
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Streams events as typed <see cref="MxEventStreamItem"/> values, surfacing
|
||||
/// the gateway's reconnect-replay gap sentinel as an observable, typed signal.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When resuming with a stale <paramref name="afterWorkerSequence"/> (older than
|
||||
/// the oldest event still retained in the session replay ring), the gateway emits
|
||||
/// a single gap sentinel at the head of the stream. It arrives here as an item
|
||||
/// with <see cref="MxEventStreamItem.IsReplayGap"/> true and
|
||||
/// <see cref="MxEventStreamItem.ReplayGap"/> populated, meaning the consumer
|
||||
/// missed events and MUST discard local state and re-snapshot. To resume without
|
||||
/// incurring another gap, reconnect with
|
||||
/// <c>afterWorkerSequence = item.ReplayGap.OldestAvailableSequence - 1</c>.
|
||||
/// All other events pass through with <see cref="MxEventStreamItem.IsReplayGap"/>
|
||||
/// false. Use <see cref="StreamEventsAsync"/> when raw generated
|
||||
/// <see cref="MxEvent"/> messages are needed instead.
|
||||
/// </remarks>
|
||||
/// <param name="afterWorkerSequence">The sequence number to stream from. Defaults to 0.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>An async enumerable of typed event items.</returns>
|
||||
public IAsyncEnumerable<MxEventStreamItem> StreamEventItemsAsync(
|
||||
ulong afterWorkerSequence = 0,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return StreamEventsAsync(afterWorkerSequence, cancellationToken)
|
||||
.AsStreamItemsAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the session and releases resources.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user