/* ======================================================================== * Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Opc.Ua; using Opc.Ua.Server; namespace Quickstarts.Servers { /// /// Helpers to find node managers implemented in this library. /// public static class Utils { /// /// Applies custom settings to quickstart servers for CTT run. /// public static async Task ApplyCTTModeAsync(TextWriter output, IStandardServer server) { var methodsToCall = new List(); int index = server.CurrentInstance.NamespaceUris.GetIndex(Alarms.Namespaces.Alarms); if (index > 0) { try { methodsToCall.Add( // Start the Alarms with infinite runtime new CallMethodRequest { MethodId = new NodeId("Alarms.Start", (ushort)index), ObjectId = new NodeId("Alarms", (ushort)index), InputArguments = [new Variant(uint.MaxValue)] }); var requestHeader = new RequestHeader { Timestamp = DateTime.UtcNow, TimeoutHint = 10000 }; using var context = new OperationContext(requestHeader, null, RequestType.Call, RequestLifetime.None); (ArrayOf results, ArrayOf diagnosticInfos) = await server.CurrentInstance.NodeManager.CallAsync( context, methodsToCall) .ConfigureAwait(false); foreach (CallMethodResult result in results) { if (ServiceResult.IsBad(result.StatusCode)) { ILogger logger = server.CurrentInstance.Telemetry.CreateLogger(); logger.ErrorCallingMethod(result.StatusCode); } } output.WriteLine("The Alarms for CTT mode are active."); return; } catch (Exception ex) { ILogger logger = server.CurrentInstance.Telemetry.CreateLogger(); logger.FailedToStartAlarmsForCtt(ex); } } output.WriteLine( "The alarms could not be enabled for CTT, the namespace does not exist."); } /// /// Add all available node manager factories to the server. /// public static void AddDefaultNodeManagers(IStandardServer server) { foreach (INodeManagerFactory nodeManagerFactory in NodeManagerFactories) { server.AddNodeManager(nodeManagerFactory); } foreach (IAsyncNodeManagerFactory asyncFactory in AsyncNodeManagerFactories) { server.AddNodeManager(asyncFactory); } } /// /// Add all available node manager factories to the server. /// public static void UseSamplingGroupsInReferenceNodeManager( ReferenceServer.ReferenceServer server) { server.UseSamplingGroupsInReferenceNodeManager = true; } /// /// Enable provisioning mode in the ReferenceServer. /// public static void EnableProvisioningMode( ReferenceServer.ReferenceServer server) { server.ProvisioningMode = true; } /// /// The property with available node manager factories. /// public static ArrayOf NodeManagerFactories { get { s_nodeManagerFactories ??= GetNodeManagerFactories(); return s_nodeManagerFactories.ToArrayOf(); } } /// /// The property with available async node manager factories. /// public static ArrayOf AsyncNodeManagerFactories { get { s_asyncNodeManagerFactories ??= GetAsyncNodeManagerFactories(); return s_asyncNodeManagerFactories.ToArrayOf(); } } /// /// Enumerates all node manager factories. /// private static List GetNodeManagerFactories() { List nodeManagerFactories = []; nodeManagerFactories.Add(new MemoryBuffer.MemoryBufferNodeManagerFactory()); nodeManagerFactories.Add(new Boiler.BoilerNodeManagerFactory()); return nodeManagerFactories; } /// /// Enumerates all async node manager factories. /// private static List GetAsyncNodeManagerFactories() { List factories = []; factories.Add(new TestData.TestDataNodeManagerFactory()); factories.Add(new Alarms.AlarmNodeManagerFactory()); return factories; } private static IList? s_nodeManagerFactories; private static IList? s_asyncNodeManagerFactories; } internal static partial class UtilsLog { [LoggerMessage( EventId = QuickstartsServersEventIds.Utils + 0, Level = LogLevel.Error, Message = "Error calling method with status code {StatusCode}.")] public static partial void ErrorCallingMethod(this ILogger logger, StatusCode statusCode); [LoggerMessage( EventId = QuickstartsServersEventIds.Utils + 1, Level = LogLevel.Error, Message = "Failed to start alarms for CTT.")] public static partial void FailedToStartAlarmsForCtt(this ILogger logger, Exception exception); } }