Resolve all high-severity architecture review findings
This commit is contained in:
@@ -263,7 +263,7 @@ public class MxGatewayDataConnection
|
||||
public async Task UnsubscribeAsync(string subscriptionId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_subs.TryRemove(subscriptionId, out var s))
|
||||
_tagToSub.TryRemove(s.TagPath, out _);
|
||||
((ICollection<KeyValuePair<string, string>>)_tagToSub).Remove(new(s.TagPath, subscriptionId));
|
||||
await _client!.UnsubscribeAsync(subscriptionId, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ public class MxGatewayDataConnection
|
||||
foreach (var id in subscriptionIds)
|
||||
{
|
||||
if (_subs.TryRemove(id, out var s))
|
||||
_tagToSub.TryRemove(s.TagPath, out _);
|
||||
((ICollection<KeyValuePair<string, string>>)_tagToSub).Remove(new(s.TagPath, id));
|
||||
}
|
||||
|
||||
await _client!.UnsubscribeBulkAsync(subscriptionIds, cancellationToken);
|
||||
|
||||
@@ -216,7 +216,7 @@ public sealed class RealMxGatewayClient : IMxGatewayClient
|
||||
// UnsubscribeBulk unadvises AND removes the item, releasing every advice kind.
|
||||
_supervisoryAdvised.TryRemove(handle, out _);
|
||||
if (_handleToTag.TryRemove(handle, out var tag))
|
||||
_tagToHandle.TryRemove(tag, out _);
|
||||
((ICollection<KeyValuePair<string, int>>)_tagToHandle).Remove(new(tag, handle));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ public sealed class RealMxGatewayClient : IMxGatewayClient
|
||||
// so forget any supervisory-advise state for this handle.
|
||||
_supervisoryAdvised.TryRemove(handle, out _);
|
||||
if (_handleToTag.TryRemove(handle, out var tag))
|
||||
_tagToHandle.TryRemove(tag, out _);
|
||||
((ICollection<KeyValuePair<string, int>>)_tagToHandle).Remove(new(tag, handle));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -68,6 +68,7 @@ public class RealOpcUaClient : IOpcUaClient
|
||||
private readonly ConcurrentDictionary<string, MonitoredItem> _alarmItems = new();
|
||||
// Per-handle "currently inside a ConditionRefresh replay" flag → Snapshot kind.
|
||||
private readonly ConcurrentDictionary<string, bool> _alarmInRefresh = new();
|
||||
private readonly ConcurrentDictionary<string, Guid> _alarmSnapshotIds = new();
|
||||
// Per-handle last (active, acked) by source reference, to derive transition kind.
|
||||
private readonly ConcurrentDictionary<string, Dictionary<string, (bool Active, bool Acked)>> _alarmLastState = new();
|
||||
// Int flag toggled with Interlocked.Exchange so the
|
||||
@@ -543,6 +544,10 @@ public class RealOpcUaClient : IOpcUaClient
|
||||
}
|
||||
_monitoredItems.Clear();
|
||||
_callbacks.Clear();
|
||||
_alarmItems.Clear();
|
||||
_alarmInRefresh.Clear();
|
||||
_alarmSnapshotIds.Clear();
|
||||
_alarmLastState.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -925,6 +930,7 @@ public class RealOpcUaClient : IOpcUaClient
|
||||
}, cancellationToken);
|
||||
}
|
||||
_alarmInRefresh.TryRemove(subscriptionHandle, out _);
|
||||
_alarmSnapshotIds.TryRemove(subscriptionHandle, out _);
|
||||
_alarmLastState.TryRemove(subscriptionHandle, out _);
|
||||
}
|
||||
|
||||
@@ -1160,12 +1166,16 @@ public class RealOpcUaClient : IOpcUaClient
|
||||
if (eventType == ObjectTypeIds.RefreshStartEventType)
|
||||
{
|
||||
_alarmInRefresh[handle] = true;
|
||||
var startEpoch = Guid.NewGuid();
|
||||
_alarmSnapshotIds[handle] = startEpoch;
|
||||
onTransition(SnapshotBoundary(AlarmTransitionKind.SnapshotStart, subscriptionSourceReference, startEpoch));
|
||||
return;
|
||||
}
|
||||
if (eventType == ObjectTypeIds.RefreshEndEventType)
|
||||
{
|
||||
_alarmInRefresh[handle] = false;
|
||||
onTransition(SnapshotComplete());
|
||||
if (_alarmSnapshotIds.TryRemove(handle, out var endEpoch))
|
||||
onTransition(SnapshotBoundary(AlarmTransitionKind.SnapshotComplete, subscriptionSourceReference, endEpoch));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1253,13 +1263,16 @@ public class RealOpcUaClient : IOpcUaClient
|
||||
LimitValue: limitValue,
|
||||
// MES alarm-status API §6.4: true source ack instant (index 18) when supplied,
|
||||
// else the observed event time; null unless the condition is active AND acked.
|
||||
AckTime: OpcUaAlarmMapper.DeriveAckTime(active, acked, sourceAckTime, time)));
|
||||
AckTime: OpcUaAlarmMapper.DeriveAckTime(active, acked, sourceAckTime, time),
|
||||
SnapshotSourceReference: inRefresh ? subscriptionSourceReference ?? string.Empty : null,
|
||||
SnapshotId: inRefresh && _alarmSnapshotIds.TryGetValue(handle, out var epoch) ? epoch : null));
|
||||
}
|
||||
|
||||
private static NativeAlarmTransition SnapshotComplete() => new(
|
||||
"", "", "", AlarmTransitionKind.SnapshotComplete,
|
||||
private static NativeAlarmTransition SnapshotBoundary(AlarmTransitionKind kind, string? source, Guid epoch) => new(
|
||||
"", source ?? string.Empty, "", kind,
|
||||
new Commons.Types.Alarms.AlarmConditionState(false, true, null, AlarmShelveState.Unshelved, false, 0),
|
||||
"", "", "", "", "", null, DateTimeOffset.UtcNow, "", "");
|
||||
"", "", "", "", "", null, DateTimeOffset.UtcNow, "", "",
|
||||
SnapshotSourceReference: source ?? string.Empty, SnapshotId: epoch);
|
||||
|
||||
/// <summary>
|
||||
/// Nodes per OPC UA Read/Write service call. Stays under the
|
||||
|
||||
Reference in New Issue
Block a user