Opc.Ua.Server.Subscription.InnerPublish C# (CSharp) Method

InnerPublish() private method

Returns all available notifications.
private InnerPublish ( OperationContext context, UInt32Collection &availableSequenceNumbers, bool &moreNotifications ) : NotificationMessage
context OperationContext
availableSequenceNumbers UInt32Collection
moreNotifications bool
return NotificationMessage
        private NotificationMessage InnerPublish(
            OperationContext      context, 
            out UInt32Collection  availableSequenceNumbers, 
            out bool              moreNotifications)
        {   
            // check session.
            VerifySession(context);

            // TraceState("PUBLISH");

            // check if a keep alive should be sent if there is no data.
            bool keepAliveIfNoData = (m_keepAliveCounter >= m_maxKeepAliveCount);

            availableSequenceNumbers = new UInt32Collection();

            moreNotifications = false;

            if (m_lastSentMessage < m_sentMessages.Count)
            {
                // return the available sequence numbers.
                for (int ii = 0; ii <= m_lastSentMessage && ii < m_sentMessages.Count; ii++)
                {
                    availableSequenceNumbers.Add(m_sentMessages[ii].SequenceNumber);
                }
                
                moreNotifications = m_waitingForPublish = m_lastSentMessage < m_sentMessages.Count-1;

                // TraceState("PUBLISH QUEUED MESSAGE");
                return m_sentMessages[m_lastSentMessage++];
            }
            
            List<NotificationMessage> messages = new List<NotificationMessage>();

            if (m_publishingEnabled)
            {                
                DateTime start1 = DateTime.UtcNow;

                // collect notifications to publish.
                Queue<EventFieldList> events = new Queue<EventFieldList>();
                Queue<MonitoredItemNotification> datachanges = new Queue<MonitoredItemNotification>();
                Queue<DiagnosticInfo> datachangeDiagnostics = new Queue<DiagnosticInfo>();
                
                // check for monitored items that are ready to publish.
                LinkedListNode<IMonitoredItem> current = m_itemsToPublish.First;
                
                while (current != null)
                {
                    LinkedListNode<IMonitoredItem> next = current.Next;
                    IMonitoredItem monitoredItem = current.Value;

                    if ((monitoredItem.MonitoredItemType & MonitoredItemTypeMask.DataChange) != 0)
                    {
                        ((IDataChangeMonitoredItem)monitoredItem).Publish(context, datachanges, datachangeDiagnostics);
                    }
                    else
                    {
                        ((IEventMonitoredItem)monitoredItem).Publish(context, events);                        
                    }

                    // add back to list to check.
                    m_itemsToPublish.Remove(current);
                    m_itemsToCheck.AddLast(current);
                                    
                    // check there are enough notifications for a message.
                    if (m_maxNotificationsPerPublish > 0 && events.Count + datachanges.Count > m_maxNotificationsPerPublish)
                    {
                        // construct message.
                        int notificationCount;
                        int eventCount = events.Count;
                        int dataChangeCount = datachanges.Count;
                                           
                        NotificationMessage message = ConstructMessage(
                             events, 
                             datachanges, 
                             datachangeDiagnostics, 
                             out notificationCount);

                        // add to list of messages to send.
                        messages.Add(message);

                        lock (m_diagnostics)
                        {
                            m_diagnostics.DataChangeNotificationsCount += (uint)(dataChangeCount - datachanges.Count);
                            m_diagnostics.EventNotificationsCount += (uint)(eventCount - events.Count);
                            m_diagnostics.NotificationsCount += (uint)notificationCount;
                        }
                    }
                                        
                    current = next;
                }
                    
                // pubish the remaining notifications.
                while (events.Count + datachanges.Count > 0)
                {
                    // construct message.
                    int notificationCount;
                    int eventCount = events.Count;
                    int dataChangeCount = datachanges.Count;   
                                       
                     NotificationMessage message = ConstructMessage(
                         events, 
                         datachanges, 
                         datachangeDiagnostics, 
                         out notificationCount);

                    // add to list of messages to send.
                    messages.Add(message);

                    lock (m_diagnostics)
                    {
                        m_diagnostics.DataChangeNotificationsCount += (uint)(dataChangeCount - datachanges.Count);
                        m_diagnostics.EventNotificationsCount += (uint)(eventCount - events.Count);
                        m_diagnostics.NotificationsCount += (uint)notificationCount;
                    }
                }

                // check for missing notifications.
                if (!keepAliveIfNoData && messages.Count == 0)
                {
                    Utils.Trace(
                        (int)Utils.TraceMasks.Error,
                        "Oops! MonitoredItems queued but no notifications availabled.");
               
                    m_waitingForPublish = false;

                    return null;
                }
                
                DateTime end1 = DateTime.UtcNow;
                
                double delta1 = ((double)(end1.Ticks-start1.Ticks))/TimeSpan.TicksPerMillisecond;

                if (delta1 > 200)
                {
                    TraceState(Utils.Format("PUBLISHING DELAY ({0}ms)", delta1));
                }
            }

            if (messages.Count == 0)
            {
                // create a keep alive message.
                NotificationMessage message = new NotificationMessage();

                // use the sequence number for the next message.                    
                message.SequenceNumber = (uint)m_sequenceNumber; 
                message.PublishTime    = DateTime.UtcNow;

                // return the available sequence numbers.
                for (int ii = 0; ii <= m_lastSentMessage && ii < m_sentMessages.Count; ii++)
                {
                    availableSequenceNumbers.Add(m_sentMessages[ii].SequenceNumber);
                }

                // TraceState("PUBLISH KEEPALIVE");
                return message;
            }

            // have to drop unsent messages if out of queue space.
            if (messages.Count > m_maxMessageCount)
            {
                Utils.Trace(
                    "WARNING: QUEUE OVERFLOW. Dropping {2} Messages. Increase MaxMessageQueueSize. SubId={0}, MaxMessageQueueSize={1}", 
                    m_id,
                    m_maxMessageCount,
                    messages.Count - (int)m_maxMessageCount);

                messages.RemoveRange(0, messages.Count - (int)m_maxMessageCount);
            }

            // remove old messages if queue is full.
            if (m_sentMessages.Count > m_maxMessageCount - messages.Count)
            {
                lock (m_diagnostics)
                {
                    m_diagnostics.UnacknowledgedMessageCount += (uint)messages.Count;
                }

                if (m_maxMessageCount <= messages.Count)
                {
                    m_sentMessages.Clear();
                }
                else
                {
                    m_sentMessages.RemoveRange(0, messages.Count);
                }
            }

            // save new message
            m_lastSentMessage = m_sentMessages.Count;
            m_sentMessages.AddRange(messages);
            
            // check if there are more notifications to send.
            moreNotifications = m_waitingForPublish = messages.Count > 1;

            // return the available sequence numbers.
            for (int ii = 0; ii <= m_lastSentMessage && ii < m_sentMessages.Count; ii++)
            {
                availableSequenceNumbers.Add(m_sentMessages[ii].SequenceNumber);
            }

            // TraceState("PUBLISH NEW MESSAGE");
            return m_sentMessages[m_lastSentMessage++];
        }