Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce that initial EventIds are deterministic #375

Merged
merged 4 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/AlarmCondition/AlarmConditionNodeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@

using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Threading;
using Opc.Ua;
using Opc.Ua.Server;
using Opc.Ua.Test;

namespace AlarmCondition
{
Expand Down Expand Up @@ -271,7 +273,8 @@ private AreaState CreateAndIndexAreas(AreaState parent, AreaConfiguration config
if (!m_sources.TryGetValue(sourcePath, out SourceState source))
{
NodeId sourceId = ModelUtils.ConstructIdForSource(sourcePath, NamespaceIndex);
m_sources[sourcePath] = source = new SourceState(this, sourceId, sourcePath);
ResetRandomGenerator(ii);
m_sources[sourcePath] = source = new SourceState(this, sourceId, sourcePath, m_generator);
}

// HasEventSource and HasNotifier control the propagation of event notifications so
Expand Down Expand Up @@ -456,13 +459,23 @@ protected override NodeState ValidateNode(
cache?.Add(handle.NodeId, target);
}
}

private void ResetRandomGenerator(int seed, int boundaryValueFrequency = 0)
{
m_randomSource = new RandomSource(seed);
m_generator = new DataGenerator(m_randomSource);
m_generator.BoundaryValueFrequency = boundaryValueFrequency;
}

#endregion

#region Private Fields
private readonly UnderlyingSystem m_system;
private readonly Dictionary<string, AreaState> m_areas;
private readonly Dictionary<string, SourceState> m_sources;
private Timer m_simulationTimer;
private RandomSource m_randomSource;
private DataGenerator m_generator;
#endregion
}
}
22 changes: 19 additions & 3 deletions src/AlarmCondition/Model/SourceState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@
* http://opcfoundation.org/License/MIT/1.00/
* ======================================================================*/

using Microsoft.AspNetCore.Hosting.Server;
using Opc.Ua;
using Opc.Ua.Test;
using System;
using System.Collections.Generic;
using System.Reflection.Emit;

namespace AlarmCondition
{
Expand All @@ -45,7 +48,8 @@ public partial class SourceState : BaseObjectState
public SourceState(
AlarmConditionServerNodeManager nodeManager,
NodeId nodeId,
string sourcePath)
string sourcePath,
DataGenerator generator)
:
base(null)
{
Expand All @@ -68,6 +72,7 @@ public SourceState(
EventNotifier = EventNotifiers.None;

// create a dialog.
m_generator = generator;
m_dialog = CreateDialog("OnlineState");

// create the table of conditions.
Expand Down Expand Up @@ -223,7 +228,7 @@ private DialogConditionState CreateDialog(string dialogName)
AddChild(node);

// initialize event information.
node.EventId.Value = Guid.NewGuid().ToByteArray();
node.EventId.Value = GetNextGuidAsByteArray();
node.EventType.Value = node.TypeDefinitionId;
node.SourceNode.Value = NodeId;
node.SourceName.Value = SymbolicName;
Expand Down Expand Up @@ -256,6 +261,16 @@ private DialogConditionState CreateDialog(string dialogName)
return node;
}

private byte[] GetNextGuidAsByteArray()
{
// Unpack the object to Uuid and then explicitly cast to Guid to access the byte[]
// using a random generator with a known seed to get reproducible results.
return ((Guid)((Uuid)m_generator.GetRandom(
NodeId.Parse($"i={(int)BuiltInType.Guid}"),
ValueRanks.Scalar, new uint[] { 1 },
m_nodeManager.Server.TypeTree))).ToByteArray();
}

/// <summary>
/// The responses used with the dialog condition.
/// </summary>
Expand Down Expand Up @@ -411,7 +426,7 @@ private void UpdateAlarm(AlarmConditionState node, UnderlyingSystemAlarm alarm)
}

// update the basic event information (include generating a unique id for the event).
node.EventId.Value = Guid.NewGuid().ToByteArray();
node.EventId.Value = GetNextGuidAsByteArray();
node.Time.Value = DateTime.UtcNow;
node.ReceiveTime.Value = node.Time.Value;

Expand Down Expand Up @@ -727,6 +742,7 @@ private string GetUserName(ISystemContext context)
private readonly Dictionary<string, AlarmConditionState> m_events;
private readonly Dictionary<NodeId, AlarmConditionState> m_branches;
private readonly DialogConditionState m_dialog;
private DataGenerator m_generator;
#endregion
}
}
Loading