/// <summary> /// Dispatches a notification message produced by a subscription. /// </summary> private void DispatchMessage(Subscription subscription, NotificationMessage notification) { lock (m_messages) { for (LinkedListNode<QueuedRequest> node = m_requests.First; node != null; node = node.Next) { // wake up timed out requests and force them to return a fault. if (node.Value.Timeout < DateTime.UtcNow) { node.Value.Signal.Set(); m_requests.Remove(node); continue; } // check for a request that matches the session. if (Object.ReferenceEquals(subscription.Session, node.Value.Session)) { // pass the message to the request and wake up the request thread. node.Value.SubscriptionId = subscription.Id; node.Value.Message = notification; node.Value.Signal.Set(); m_requests.Remove(node); return; } } // messages only go on the publish queue if no threads are waiting. QueuedMessage message = new QueuedMessage(); message.Session = subscription.Session; message.Subscription = subscription; message.Message = notification; m_messages.AddLast(message); // ensure queue does not grow too large. while (m_messages.Count > 50) { m_messages.RemoveFirst(); } } }
/// <summary> /// Creates a subscription that can be used to recieve data change or event notifications. /// </summary> public CreateSubscriptionResponseMessage CreateSubscription(CreateSubscriptionMessage request) { try { lock (m_lock) { // verify the session. Session session = VerifySession(request.RequestHeader, false); // create a new subscription. Subscription subscription = new Subscription(); uint subscriptionId; double publishingInterval; uint lifetimeCount; uint keepAliveCount; // the subscription validates the parameters and throws exceptions on error. subscription.Create( session, m_nodeManager, request.RequestedPublishingInterval, request.RequestedLifetimeCount, request.RequestedMaxKeepAliveCount, request.MaxNotificationsPerPublish, request.PublishingEnabled, request.Priority, out subscriptionId, out publishingInterval, out lifetimeCount, out keepAliveCount); // save the subscription. m_subscriptions.Add(subscriptionId, subscription); // start the publish thread if it has not already been started. if (m_subscriptions.Count == 1) { ThreadPool.QueueUserWorkItem(PublishSubscriptions); } // return the response. CreateSubscriptionResponseMessage response = new CreateSubscriptionResponseMessage(); response.ResponseHeader = CreateResponseHeader(request.RequestHeader); response.SubscriptionId = subscriptionId; response.RevisedPublishingInterval = publishingInterval; response.RevisedLifetimeCount = lifetimeCount; response.RevisedMaxKeepAliveCount = keepAliveCount; return response; } } catch (Exception e) { throw CreateSoapFault(request.RequestHeader, e); } }