Exemple #1
0
            /// <summary>
            /// handle subscription change messages
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="sequenceNumber"></param>
            /// <param name="notification"></param>
            private void CallMessageReceiverDelegates(object sender, uint sequenceNumber,
                                                      SubscriptionNotificationModel notification)
            {
                try {
                    var message = new DataSetMessageModel {
                        // TODO: Filter changes on the monitored items contained in the template
                        Notifications         = notification.Notifications.ToList(),
                        ServiceMessageContext = notification.ServiceMessageContext,
                        SubscriptionId        = notification.SubscriptionId,
                        SequenceNumber        = sequenceNumber,
                        ApplicationUri        = notification.ApplicationUri,
                        EndpointUrl           = notification.EndpointUrl,
                        TimeStamp             = DateTime.UtcNow,
                        PublisherId           = _outer._publisherId,
                        Writer      = _dataSetWriter,
                        WriterGroup = _outer._writerGroup
                    };
                    lock (_lock) {
                        if (_outer.NumberOfInvokedMessages >= kNumberOfInvokedMessagesResetThreshold)
                        {
                            _outer._logger.Debug("Message counter has been reset to prevent overflow. " +
                                                 "So far, {NumberOfInvokedMessages} messages has been invoked by message source.",
                                                 _outer.NumberOfInvokedMessages);
                            _outer.NumberOfInvokedMessages = 0;
                        }

                        _outer.NumberOfInvokedMessages += message.Notifications.Count();
                        _outer.OnMessage?.Invoke(sender, message);
                    }
                }
                catch (Exception ex) {
                    _outer._logger.Debug(ex, "Failed to produce message");
                }
            }
            /// <summary>
            /// Handle subscription change messages
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="notification"></param>
            private async void OnSubscriptionChangedAsync(object sender,
                                                          SubscriptionNotificationModel notification)
            {
                var sequenceNumber = (uint)Interlocked.Increment(ref _currentSequenceNumber);

                if (_keyFrameCount.HasValue && _keyFrameCount.Value != 0 &&
                    (sequenceNumber % _keyFrameCount.Value) == 0)
                {
                    var snapshot = await Try.Async(() => Subscription.GetSnapshotAsync()).ConfigureAwait(false);

                    if (snapshot != null)
                    {
                        notification = snapshot;
                    }
                }
                CallMessageReceiverDelegates(sender, sequenceNumber, notification);
            }
            /// <summary>
            /// handle subscription change messages
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="sequenceNumber"></param>
            /// <param name="notification"></param>
            private void CallMessageReceiverDelegates(object sender, uint sequenceNumber,
                                                      SubscriptionNotificationModel notification)
            {
                try {
                    var message = new DataSetMessageModel {
                        // TODO: Filter changes on the monitored items contained in the template
                        Notifications         = notification.Notifications.ToList(),
                        ServiceMessageContext = notification.ServiceMessageContext,
                        SubscriptionId        = notification.SubscriptionId,
                        SequenceNumber        = sequenceNumber,
                        ApplicationUri        = notification.ApplicationUri,
                        EndpointUrl           = notification.EndpointUrl,
                        TimeStamp             = notification.Timestamp,
                        PublisherId           = _outer._publisherId,
                        Writer      = _dataSetWriter,
                        WriterGroup = _outer._writerGroup
                    };
                    lock (_lock) {
                        if (_outer.DataChangesCount >= kNumberOfInvokedMessagesResetThreshold ||
                            _outer.ValueChangesCount >= kNumberOfInvokedMessagesResetThreshold)
                        {
                            // reset both
                            _outer._logger.Information("Notifications counter has been reset to prevent overflow. " +
                                                       "So far, {DataChangesCount} data changes and {ValueChangesCount}" +
                                                       " value changes were invoked by message source.",
                                                       _outer.DataChangesCount, _outer.ValueChangesCount);
                            _outer.DataChangesCount  = 0;
                            _outer.ValueChangesCount = 0;
                            _outer.FireOnCounterResetEvent();
                        }

                        _outer.ValueChangesCount += (ulong)message.Notifications.Count();
                        _outer.DataChangesCount++;
                        _outer.OnMessage?.Invoke(sender, message);
                    }
                }
                catch (Exception ex) {
                    _outer._logger.Debug(ex, "Failed to produce message");
                }
            }
 /// <summary>
 /// Subscription data changed
 /// </summary>
 /// <param name="subscription"></param>
 /// <param name="notification"></param>
 /// <param name="stringTable"></param>
 private void OnSubscriptionDataChanged(Subscription subscription,
                                        DataChangeNotification notification, IList <string> stringTable)
 {
     try {
         if (OnSubscriptionChange == null)
         {
             return;
         }
         var message = new SubscriptionNotificationModel {
             ServiceMessageContext = subscription.Session.MessageContext,
             ApplicationUri        = subscription.Session.Endpoint.Server.ApplicationUri,
             EndpointUrl           = subscription.Session.Endpoint.EndpointUrl,
             SubscriptionId        = Id,
             Notifications         = notification
                                     .ToMonitoredItemNotifications(subscription.MonitoredItems)
                                     .ToList()
         };
         OnSubscriptionChange?.Invoke(this, message);
     }
     catch (Exception ex) {
         _logger.Debug(ex, "Exception processing subscription notification");
     }
 }
            /// <summary>
            /// Monitored item notification handler
            /// </summary>
            /// <param name="monitoredItem"></param>
            /// <param name="e"></param>
            private void OnMonitoredItemChanged(MonitoredItem monitoredItem,
                                                MonitoredItemNotificationEventArgs e)
            {
                try {
                    if (OnMonitoredItemChange == null)
                    {
                        return;
                    }
                    if (e?.NotificationValue == null || monitoredItem?.Subscription?.Session == null)
                    {
                        return;
                    }
                    if (!(e.NotificationValue is MonitoredItemNotification notification))
                    {
                        return;
                    }
                    if (!(notification.Value is DataValue value))
                    {
                        return;
                    }

                    var message = new SubscriptionNotificationModel {
                        ServiceMessageContext = monitoredItem.Subscription.Session.MessageContext,
                        ApplicationUri        = monitoredItem.Subscription.Session.Endpoint.Server.ApplicationUri,
                        EndpointUrl           = monitoredItem.Subscription.Session.Endpoint.EndpointUrl,
                        SubscriptionId        = Id,
                        Notifications         = new List <MonitoredItemNotificationModel> {
                            notification.ToMonitoredItemNotification(monitoredItem)
                        }
                    };
                    OnMonitoredItemChange(this, message);
                }
                catch (Exception ex) {
                    _logger.Debug(ex, "Exception processing monitored item notification");
                }
            }
            /// <summary>
            /// Subscription data changed
            /// </summary>
            /// <param name="subscription"></param>
            /// <param name="notification"></param>
            /// <param name="stringTable"></param>
            private void OnSubscriptionDataChanged(Subscription subscription,
                                                   DataChangeNotification notification, IList <string> stringTable)
            {
                try {
                    if (OnSubscriptionChange == null)
                    {
                        return;
                    }
                    if (notification == null)
                    {
                        _logger.Warning("DataChange for subscription: {Subscription} having empty notification",
                                        subscription.DisplayName);
                        return;
                    }

                    if (_currentlyMonitored == null)
                    {
                        _logger.Information("DataChange for subscription: {Subscription} having no monitored items yet",
                                            subscription.DisplayName);
                        return;
                    }

                    // check if notification is a keep alive
                    var isKeepAlive = notification?.MonitoredItems?.Count == 1 &&
                                      notification?.MonitoredItems?.First().ClientHandle == 0 &&
                                      notification?.MonitoredItems?.First().Message?.NotificationData?.Count == 0;
                    var sequenceNumber = notification?.MonitoredItems?.First().Message?.SequenceNumber;
                    var publishTime    = (notification?.MonitoredItems?.First().Message?.PublishTime).
                                         GetValueOrDefault(DateTime.MinValue);

                    _logger.Debug("DataChange for subscription: {Subscription}, sequence#: " +
                                  "{Sequence} isKeepAlive{KeepAlive}, publishTime: {PublishTime}",
                                  subscription.DisplayName, sequenceNumber, isKeepAlive, publishTime);

                    var message = new SubscriptionNotificationModel {
                        ServiceMessageContext = subscription.Session.MessageContext,
                        ApplicationUri        = subscription.Session.Endpoint.Server.ApplicationUri,
                        EndpointUrl           = subscription.Session.Endpoint.EndpointUrl,
                        SubscriptionId        = Id,
                        Notifications         = (!isKeepAlive)
                            ? notification.ToMonitoredItemNotifications(
                            subscription.MonitoredItems).ToList()
                            : new List <MonitoredItemNotificationModel>()
                    };
                    message.IsKeyMessage = true;

                    // add the heartbeat for monitored items that did not receive a a datachange notification
                    // Try access lock if we cannot continue...
                    List <MonitoredItemWrapper> currentlyMonitored = null;
                    if (_lock.Wait(0))
                    {
                        try {
                            currentlyMonitored = _currentlyMonitored;
                        }
                        finally {
                            _lock.Release();
                        }
                    }
                    if (currentlyMonitored != null)
                    {
                        // add the heartbeat for monitored items that did not receive a
                        // a datachange notification
                        foreach (var item in currentlyMonitored)
                        {
                            if (isKeepAlive ||
                                !notification.MonitoredItems.Exists(m => m.ClientHandle == item.Item.ClientHandle))
                            {
                                if (item.TriggerHeartbeat(publishTime))
                                {
                                    var heartbeatValue = item.Item.LastValue.ToMonitoredItemNotification(item.Item);
                                    if (heartbeatValue != null)
                                    {
                                        heartbeatValue.SequenceNumber = sequenceNumber;
                                        heartbeatValue.IsHeartbeat    = true;
                                        heartbeatValue.PublishTime    = publishTime;
                                        message.Notifications.Add(heartbeatValue);
                                    }
                                }
                                else
                                {
                                    // just reset the heartbeat for the items already processed
                                    item.TriggerHeartbeat(publishTime);
                                }
                            }
                        }
                    }
                    OnSubscriptionChange?.Invoke(this, message);
                }
                catch (Exception ex) {
                    _logger.Debug(ex, "Exception processing subscription notification");
                }
            }