82 lines
3.3 KiB
C#
82 lines
3.3 KiB
C#
namespace WxAgent.Core;
|
|
|
|
public sealed record RemoteAccountIdentity(string AccountId, bool Verified);
|
|
|
|
public sealed record RemoteAccountContextSnapshot(
|
|
string? ActiveAccountId,
|
|
long Revision,
|
|
bool Confirmed);
|
|
|
|
public sealed class RemoteAccountContext
|
|
{
|
|
private readonly object _gate = new();
|
|
private RemoteAccountContextSnapshot _snapshot = new(null, 0, false);
|
|
|
|
public RemoteAccountContextSnapshot Snapshot
|
|
{
|
|
get { lock (_gate) return _snapshot; }
|
|
}
|
|
|
|
public static string? SelectActiveAccountId(
|
|
bool uiSessionAvailable,
|
|
string? preferredAccountId,
|
|
IReadOnlyCollection<RemoteAccountIdentity> identities,
|
|
IReadOnlyCollection<string> liveBoundAccountIds)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(identities);
|
|
ArgumentNullException.ThrowIfNull(liveBoundAccountIds);
|
|
if (!uiSessionAvailable) return null;
|
|
|
|
var liveBoundIds = liveBoundAccountIds.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
var eligible = identities
|
|
.Where(identity => identity.Verified && liveBoundIds.Contains(identity.AccountId))
|
|
.ToArray();
|
|
if (!string.IsNullOrWhiteSpace(preferredAccountId))
|
|
{
|
|
var preferred = eligible.FirstOrDefault(identity =>
|
|
string.Equals(identity.AccountId, preferredAccountId, StringComparison.OrdinalIgnoreCase));
|
|
if (preferred is not null) return preferred.AccountId;
|
|
}
|
|
return eligible.Length == 1 ? eligible[0].AccountId : null;
|
|
}
|
|
|
|
public RemoteAccountContextSnapshot SwitchTo(
|
|
string accountId,
|
|
IReadOnlyCollection<RemoteAccountIdentity> identities,
|
|
bool hasInFlightWrites = false)
|
|
{
|
|
RemoteAgentOptions.ValidateIdentifier(accountId, "accountId", 200);
|
|
ArgumentNullException.ThrowIfNull(identities);
|
|
lock (_gate)
|
|
{
|
|
if (hasInFlightWrites && !string.Equals(_snapshot.ActiveAccountId, accountId, StringComparison.Ordinal))
|
|
throw new WxAgentException(WxAgentErrorCode.InvalidOperationState, "Account switching is blocked while a write operation is in flight.");
|
|
var matches = identities.Where(identity => string.Equals(identity.AccountId, accountId, StringComparison.Ordinal)).ToArray();
|
|
if (matches.Length != 1 || !matches[0].Verified)
|
|
{
|
|
_snapshot = new RemoteAccountContextSnapshot(null, checked(_snapshot.Revision + 1), false);
|
|
throw new WxAgentException(WxAgentErrorCode.AccountContextUnconfirmed, "The requested account identity could not be confirmed.");
|
|
}
|
|
if (_snapshot.Confirmed && string.Equals(_snapshot.ActiveAccountId, accountId, StringComparison.Ordinal))
|
|
return _snapshot;
|
|
_snapshot = new RemoteAccountContextSnapshot(accountId, checked(_snapshot.Revision + 1), true);
|
|
return _snapshot;
|
|
}
|
|
}
|
|
|
|
public void Invalidate()
|
|
{
|
|
lock (_gate)
|
|
{
|
|
if (!_snapshot.Confirmed && _snapshot.ActiveAccountId is null) return;
|
|
_snapshot = new RemoteAccountContextSnapshot(null, checked(_snapshot.Revision + 1), false);
|
|
}
|
|
}
|
|
|
|
public bool IsConfirmedFor(string accountId)
|
|
{
|
|
lock (_gate)
|
|
return _snapshot.Confirmed && string.Equals(_snapshot.ActiveAccountId, accountId, StringComparison.Ordinal);
|
|
}
|
|
}
|