Skip to content
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
2 changes: 1 addition & 1 deletion Libraries/Opc.Ua.Server/Diagnostics/CustomNodeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3849,7 +3849,7 @@ protected virtual void OnMonitoredItemCreated(
/// <param name="nodeId"></param>
/// <param name="requestedPermission"></param>
/// <returns></returns>
public ServiceResult ValidateRolePermissions(OperationContext operationContext, NodeId nodeId, PermissionType requestedPermission)
public virtual ServiceResult ValidateRolePermissions(OperationContext operationContext, NodeId nodeId, PermissionType requestedPermission)
{
if (requestedPermission == PermissionType.None)
{
Expand Down
58 changes: 56 additions & 2 deletions Libraries/Opc.Ua.Server/Diagnostics/MonitoredNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* ======================================================================*/

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Opc.Ua;
using Opc.Ua.Server;
Expand Down Expand Up @@ -142,6 +143,10 @@ public void Remove(MonitoredItem datachangeItem)
if (Object.ReferenceEquals(DataChangeMonitoredItems[ii], datachangeItem))
{
DataChangeMonitoredItems.RemoveAt(ii);

// Remove the cached context for the monitored item
m_contextCache.TryRemove(datachangeItem.Id, out _);

break;
}
}
Expand Down Expand Up @@ -271,7 +276,7 @@ public void OnReportEvent(ISystemContext context, NodeState node, IFilterTarget

}
}
}
}

/// <summary>
/// Called when the state of a Node changes.
Expand Down Expand Up @@ -331,8 +336,15 @@ public void QueueValue(
value.SourceTimestamp = DateTime.MinValue;
value.StatusCode = StatusCodes.Good;

ISystemContext contextToUse = context;

if (context is ServerSystemContext systemContext)
{
contextToUse = GetOrCreateContext(systemContext, monitoredItem);
}

ServiceResult error = node.ReadAttribute(
context,
contextToUse,
monitoredItem.AttributeId,
monitoredItem.IndexRange,
monitoredItem.DataEncoding,
Expand All @@ -347,11 +359,53 @@ public void QueueValue(
}
#endregion

#region Private Methods
/// <summary>
/// Gets or creates a cached context for the monitored item.
/// </summary>
/// <param name="monitoredItem">The monitored item.</param>
/// <param name="context">The system context.</param>
/// <returns>The cached or newly created context.</returns>
private ServerSystemContext GetOrCreateContext(ServerSystemContext context, MonitoredItem monitoredItem)
{
uint monitoredItemId = monitoredItem.Id;
int currentTicks = HiResClock.TickCount;

// Check if the context already exists in the cache
if (m_contextCache.TryGetValue(monitoredItemId, out var cachedEntry))
{
// Check if the session or user identity has changed or the entry has expired
if (cachedEntry.Context.OperationContext.Session != monitoredItem.Session
|| cachedEntry.Context.OperationContext.UserIdentity != monitoredItem.EffectiveIdentity
|| (currentTicks - cachedEntry.CreatedAtTicks) > m_cacheLifetimeTicks)
{
var updatedContext = context.Copy(new OperationContext(monitoredItem));
m_contextCache[monitoredItemId] = (updatedContext, currentTicks);

return updatedContext;
}
Comment thread
romanett marked this conversation as resolved.
// return cached entry
else
{
return cachedEntry.Context;
}
}

// Create a new context and add it to the cache
var newContext = context.Copy(new OperationContext(monitoredItem));
m_contextCache.TryAdd(monitoredItemId, (newContext, currentTicks));

return newContext;
}
#endregion

#region Private Fields
private CustomNodeManager2 m_nodeManager;
private NodeState m_node;
private List<MonitoredItem> m_dataChangeMonitoredItems;
private List<IEventMonitoredItem> m_eventMonitoredItems;
private readonly ConcurrentDictionary<uint, (ServerSystemContext Context, int CreatedAtTicks)> m_contextCache = new();
private readonly int m_cacheLifetimeTicks = (int)TimeSpan.FromMinutes(5).TotalMilliseconds;
#endregion
}
}
2 changes: 1 addition & 1 deletion Libraries/Opc.Ua.Server/NodeManager/MasterNodeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3431,7 +3431,7 @@ protected internal static ServiceResult ValidateRolePermissions(OperationContext
}
}

var currentRoleIds = context.UserIdentity.GrantedRoleIds;
var currentRoleIds = context?.UserIdentity?.GrantedRoleIds;
if (currentRoleIds == null || currentRoleIds.Count == 0)
{
return ServiceResult.Create(StatusCodes.BadUserAccessDenied, "Current user has no granted role.");
Expand Down