public async Task HandleSaveOpcPublishedConfigurationAsJson_FormatIsRight_ShouldReinitializeNodeConfiguration( string testFilename, string testFileNameWithModifiedKey, int configuredSessions, int configuredSubscriptions, int configuredMonitoredItems, int configuredMonitoredEvents) { OpcNodeOnEndpointModel GetFirstNode() { var endpointId = NodeConfiguration.OpcSessions[0].EndpointId; var nodes = NodeConfiguration.GetPublisherConfigurationFileEntries(endpointId, true, out uint version); return(nodes[0].OpcNodes[0]); } using (new ExecutionContext(testFilename)) { var hubCommunicationBase = new HubCommunicationBase(); AssertPreconditions(configuredSessions, configuredSubscriptions, configuredMonitoredItems, configuredMonitoredEvents); // Get node before saving new file. var opcNodeBeforeSave = GetFirstNode(); // ------- Act ----- // load different file with key change. var modifiedFilePath = CopyFileToTempData(testFileNameWithModifiedKey); // Read the file data as bytes var text = await File.ReadAllTextAsync(modifiedFilePath); var methodRequestModel = new HandleSaveOpcPublishedConfigurationMethodRequestModel(text); var json = JsonConvert.SerializeObject(methodRequestModel); var bytes = Encoding.UTF8.GetBytes(json); var request = new MethodRequest("SaveOpcPublishedConfigurationAsJson", bytes); // Feed the json string to the communication base var success = await hubCommunicationBase.HandleSaveOpcPublishedConfigurationAsJson(request, new object()); // ------- Assert ------ // The preconditions should not change, since only the key of the node is changed. AssertPreconditions(configuredSessions, configuredSubscriptions, configuredMonitoredItems, configuredMonitoredEvents); Assert.True(success.Status == (int)HttpStatusCode.OK); var opcNodeAfterSave = GetFirstNode(); Assert.Equal(opcNodeBeforeSave.Id, opcNodeBeforeSave.Id); Assert.Equal("i=2267", opcNodeBeforeSave.Key); Assert.Equal("i=2267-test", opcNodeAfterSave.Key); } }
/// <summary> /// Handle get message properties method call. /// </summary> public virtual Task <MethodResponse> HandleGetMessagePropertiesMethodAsync(MethodRequest methodRequest, object userContext) { var response = new GetMessagePropertiesReponseModel(); var endpoints = NodeConfiguration.GetPublisherConfigurationFileEntries(Guid.Empty, false, out _) .Select(e => new MessagePropertyValue(e.EndpointName, e.EndpointId.ToString())); var endpointMessageProperty = new MessageProperty("OPC UA endpoint", "endpointId", endpoints); response.Items.Add(endpointMessageProperty); string resultString = JsonConvert.SerializeObject(response); byte[] result = Encoding.UTF8.GetBytes(resultString); return(Task.FromResult(new MethodResponse(result, (int)HttpStatusCode.OK))); }
/// <summary> /// Handle method call to get list of configured nodes on a specific endpoint. /// </summary> public virtual Task <MethodResponse> HandleGetConfiguredEventsOnEndpointMethodAsync(MethodRequest methodRequest, object userContext) { const string logPrefix = "HandleGetConfiguredEventsOnEndpointMethodAsync:"; Guid endpointId = Guid.Empty; string endpointName = null; string endpointUrl = null; GetConfiguredNodesOnEndpointMethodRequestModel getConfiguredEventNodesOnEndpointMethodRequest = null; uint nodeConfigVersion = 0; GetConfiguredEventNodesOnEndpointMethodResponseModel getConfiguredEventNodesOnEndpointMethodResponse = new GetConfiguredEventNodesOnEndpointMethodResponseModel(); uint actualNodeCount = 0; uint availableEventNodeCount = 0; var opcEvents = new List <OpcEventOnEndpointModel>(); uint startIndex = 0; var statusCode = HttpStatusCode.OK; var statusResponse = new List <string>(); string statusMessage; try { Logger.Debug($"{logPrefix} called"); getConfiguredEventNodesOnEndpointMethodRequest = JsonConvert.DeserializeObject <GetConfiguredNodesOnEndpointMethodRequestModel>(methodRequest.DataAsJson); if (getConfiguredEventNodesOnEndpointMethodRequest.EndpointId == null) { statusMessage = $"New endpoint: there are no event nodes configured"; Logger.Information($"{logPrefix} {statusMessage}"); statusResponse.Add(statusMessage); statusCode = HttpStatusCode.NoContent; } else { endpointId = new Guid(getConfiguredEventNodesOnEndpointMethodRequest.EndpointId); } } catch (FormatException e) { statusMessage = $"Exception ({e.Message}) while parsing EndpointId '{getConfiguredEventNodesOnEndpointMethodRequest?.EndpointId}'"; Logger.Error(e, $"{logPrefix} {statusMessage}"); statusResponse.Add(statusMessage); statusCode = HttpStatusCode.InternalServerError; } catch (Exception e) { statusMessage = $"Exception ({e.Message}) while deserializing message payload"; Logger.Error(e, $"{logPrefix} Exception"); statusResponse.Add(statusMessage); statusCode = HttpStatusCode.InternalServerError; } if (statusCode == HttpStatusCode.OK) { // get the list of published nodes for the endpoint List <PublisherConfigurationFileEntryModel> configFileEntries = NodeConfiguration.GetPublisherConfigurationFileEntries(endpointId, false, out nodeConfigVersion); // return if there are no nodes configured for this endpoint if (configFileEntries.Count == 0) { statusMessage = $"There are no event nodes configured for endpoint '{endpointId.ToString()}'"; Logger.Information($"{logPrefix} {statusMessage}"); statusResponse.Add(statusMessage); statusCode = HttpStatusCode.NoContent; } else { endpointName = configFileEntries.First().EndpointName; endpointUrl = configFileEntries.First().EndpointUrl.ToString(); foreach (var configFileEntry in configFileEntries) { if (configFileEntry?.OpcEvents != null) { opcEvents.AddRange(configFileEntry.OpcEvents); } } uint configuredEventNodesOnEndpointCount = (uint)opcEvents.Count(); // validate version startIndex = 0; if (getConfiguredEventNodesOnEndpointMethodRequest?.ContinuationToken != null) { uint requestedNodeConfigVersion = (uint)(getConfiguredEventNodesOnEndpointMethodRequest.ContinuationToken >> 32); if (nodeConfigVersion != requestedNodeConfigVersion) { statusMessage = $"The event node configuration has changed between calls. Requested version: {requestedNodeConfigVersion:X8}, Current version '{nodeConfigVersion:X8}'!"; Logger.Information($"{logPrefix} {statusMessage}"); statusResponse.Add(statusMessage); statusCode = HttpStatusCode.Gone; } startIndex = (uint)(getConfiguredEventNodesOnEndpointMethodRequest.ContinuationToken & 0x0FFFFFFFFL); } if (statusCode == HttpStatusCode.OK) { // set count var requestedEventNodeCount = configuredEventNodesOnEndpointCount - startIndex; availableEventNodeCount = configuredEventNodesOnEndpointCount - startIndex; actualNodeCount = Math.Min(requestedEventNodeCount, availableEventNodeCount); opcEvents.ForEach(x => x.OpcPublisherPublishState = OpcPublisherPublishState.Published); // generate response while (true) { string publishedNodesString = JsonConvert.SerializeObject(opcEvents.GetRange((int)startIndex, (int)actualNodeCount)); var publishedNodesByteArray = Encoding.UTF8.GetBytes(publishedNodesString); if (publishedNodesByteArray.Length > MaxResponsePayloadLength) { actualNodeCount /= 2; continue; } break; } } } } // build response string resultString; if (statusCode == HttpStatusCode.OK) { getConfiguredEventNodesOnEndpointMethodResponse.ContinuationToken = null; if (actualNodeCount < availableEventNodeCount) { getConfiguredEventNodesOnEndpointMethodResponse.ContinuationToken = (ulong)nodeConfigVersion << 32 | actualNodeCount + startIndex; } // Todo: check if EventConfigurationModel mit endpointName = endpointUrl = null ok? getConfiguredEventNodesOnEndpointMethodResponse.EventNodes .AddRange(opcEvents .GetRange((int)startIndex, (int)actualNodeCount) .Select(n => new OpcEventOnEndpointModel( new EventConfigurationModel( endpointId.ToString(), endpointName, endpointUrl, null, OpcAuthenticationMode.Anonymous, null, n.Id, n.DisplayName, n.SelectClauses, n.WhereClause, n.IotCentralEventPublishMode ), OpcPublisherPublishState.Published ) ) ); getConfiguredEventNodesOnEndpointMethodResponse.EndpointId = endpointId.ToString(); resultString = JsonConvert.SerializeObject(getConfiguredEventNodesOnEndpointMethodResponse); Logger.Information($"{logPrefix} Success returning {actualNodeCount} event node(s) of {availableEventNodeCount} (start: {startIndex}) (node config version: {nodeConfigVersion:X8})!"); } else if (statusCode == HttpStatusCode.NoContent) { resultString = JsonConvert.SerializeObject(getConfiguredEventNodesOnEndpointMethodResponse); Logger.Information($"{logPrefix} Success returning 0 event nodes."); } else { resultString = JsonConvert.SerializeObject(statusResponse); } byte[] result = Encoding.UTF8.GetBytes(resultString); if (result.Length > MaxResponsePayloadLength) { Logger.Error($"{logPrefix} Response size is too long"); Array.Resize(ref result, result.Length > MaxResponsePayloadLength ? MaxResponsePayloadLength : result.Length); } MethodResponse methodResponse = new MethodResponse(result, (int)statusCode); Logger.Information($"{logPrefix} completed with result {statusCode.ToString()}"); return(Task.FromResult(methodResponse)); }