/// <summary> /// Publishes a value. /// </summary> private void Publish( OperationContext context, DataValue value, ServiceResult error, Queue <MonitoredItemNotification> notifications, Queue <DiagnosticInfo> diagnostics) { // set semantics changed bit. if (m_semanticsChanged) { if (value != null) { value.StatusCode = value.StatusCode.SetSemanticsChanged(true); } if (error != null) { error = new ServiceResult( error.StatusCode.SetSemanticsChanged(true), error.SymbolicId, error.NamespaceUri, error.LocalizedText, error.AdditionalInfo, error.InnerResult); } m_semanticsChanged = false; } // set structure changed bit. if (m_structureChanged) { if (value != null) { value.StatusCode = value.StatusCode.SetStructureChanged(true); } if (error != null) { error = new ServiceResult( error.StatusCode.SetStructureChanged(true), error.SymbolicId, error.NamespaceUri, error.LocalizedText, error.AdditionalInfo, error.InnerResult); } m_structureChanged = false; } // copy data value. MonitoredItemNotification item = new MonitoredItemNotification(); item.ClientHandle = m_clientHandle; item.Value = value; // apply timestamp filter. if (m_timestampsToReturn != TimestampsToReturn.Server && m_timestampsToReturn != TimestampsToReturn.Both) { item.Value.ServerTimestamp = DateTime.MinValue; } if (m_timestampsToReturn != TimestampsToReturn.Source && m_timestampsToReturn != TimestampsToReturn.Both) { item.Value.SourceTimestamp = DateTime.MinValue; } notifications.Enqueue(item); // update diagnostic info. DiagnosticInfo diagnosticInfo = null; if (m_lastError != null) { if ((m_diagnosticsMasks & DiagnosticsMasks.OperationAll) != 0) { diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_source.Server, context, m_lastError); } } diagnostics.Enqueue(diagnosticInfo); }
/// <summary> /// Adds the value to the queue. Discards values if the queue is full. /// </summary> /// <param name="value">The value to add.</param> /// <param name="error">The error to add.</param> private void Enqueue(DataValue value, ServiceResult error) { // check for empty queue. if (m_start < 0) { m_start = 0; m_end = 1; m_overflow = -1; // Utils.Trace("ENQUEUE VALUE: Value={0}", value.WrappedValue); m_values[m_start] = value; if (m_errors != null) { m_errors[m_start] = error; } return; } int next = m_end; // check if the latest value has initial dummy data if (m_values[m_end - 1].StatusCode != StatusCodes.BadWaitingForInitialData) { // check for wrap around. if (next >= m_values.Length) { next = 0; } // check if queue is full. if (m_start == next) { if (!m_discardOldest) { m_overflow = m_end - 1; ServerUtils.ReportDiscardedValue(null, m_monitoredItemId, value); // overwrite last value m_values[m_overflow] = value; if (m_errors != null) { m_errors[m_overflow] = error; } return; } // remove oldest value. m_start++; if (m_start >= m_values.Length) { m_start = 0; } // set overflow bit. m_overflow = m_start; ServerUtils.ReportDiscardedValue(null, m_monitoredItemId, m_values[m_overflow]); } else { // Utils.Trace("ENQUEUE VALUE: Value={0}", value.WrappedValue); } } else { // overwrite the last value next = m_end - 1; } // add value. m_values[next] = value; if (m_errors != null) { m_errors[next] = error; } m_end = next + 1; }
/// <summary> /// Processes acknowledgements for previously published messages. /// </summary> public void Acknowledge( OperationContext context, SubscriptionAcknowledgementCollection subscriptionAcknowledgements, out StatusCodeCollection acknowledgeResults, out DiagnosticInfoCollection acknowledgeDiagnosticInfos) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (subscriptionAcknowledgements == null) { throw new ArgumentNullException(nameof(subscriptionAcknowledgements)); } lock (m_lock) { bool diagnosticsExist = false; acknowledgeResults = new StatusCodeCollection(subscriptionAcknowledgements.Count); acknowledgeDiagnosticInfos = new DiagnosticInfoCollection(subscriptionAcknowledgements.Count); for (int ii = 0; ii < subscriptionAcknowledgements.Count; ii++) { SubscriptionAcknowledgement acknowledgement = subscriptionAcknowledgements[ii]; bool found = false; for (int jj = 0; jj < m_queuedSubscriptions.Count; jj++) { QueuedSubscription subscription = m_queuedSubscriptions[jj]; if (subscription.Subscription.Id == acknowledgement.SubscriptionId) { ServiceResult result = subscription.Subscription.Acknowledge(context, acknowledgement.SequenceNumber); if (ServiceResult.IsGood(result)) { acknowledgeResults.Add(StatusCodes.Good); if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { acknowledgeDiagnosticInfos.Add(null); } } else { acknowledgeResults.Add(result.Code); if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, result); acknowledgeDiagnosticInfos.Add(diagnosticInfo); diagnosticsExist = true; } } found = true; break; } } if (!found) { ServiceResult result = new ServiceResult(StatusCodes.BadSubscriptionIdInvalid); acknowledgeResults.Add(result.Code); if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, result); acknowledgeDiagnosticInfos.Add(diagnosticInfo); diagnosticsExist = true; } } } if (!diagnosticsExist) { acknowledgeDiagnosticInfos.Clear(); } } }