private void HandleRequest(QueuedRequest queuedRequest) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(queuedRequest.Url); if (Client.Configuration.ContainsKey("username") && Client.Configuration.ContainsKey("password")) { request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String( Encoding.ASCII.GetBytes(String.Format("{0}:{1}", Client.Configuration["username"], Client.Configuration["password"])))); } Directory.CreateDirectory(Path.GetDirectoryName(queuedRequest.Filename)); using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) using (Stream responseStream = response.GetResponseStream()) using (Stream outputStream = File.Open(queuedRequest.Filename, FileMode.OpenOrCreate, FileAccess.Write)) { byte[] buf = new byte[4096]; int readlen; while ((readlen = responseStream.Read(buf, 0, 4096)) > 0) { outputStream.Write(buf, 0, readlen); } outputStream.Close(); responseStream.Close(); response.Close(); } }
/// <summary> /// Removes a subscription from the publish queue. /// </summary> public void Remove(Subscription subscription) { if (subscription == null) { throw new ArgumentNullException("subscription"); } lock (m_lock) { // remove the subscription from the queue. for (int ii = 0; ii < m_queuedSubscriptions.Count; ii++) { if (Object.ReferenceEquals(m_queuedSubscriptions[ii].Subscription, subscription)) { m_queuedSubscriptions.RemoveAt(ii); break; } } // remove any outstanding publishes. if (m_queuedSubscriptions.Count == 0) { while (m_queuedRequests.Count > 0) { QueuedRequest request = m_queuedRequests.First.Value; request.Error = StatusCodes.BadNoSubscription; request.Set(); m_queuedRequests.RemoveFirst(); } } // TraceState("SUBSCRIPTION REMOVED"); } }
/// <summary> /// Clears the queues because the session is closing. /// </summary> /// <returns>The list of subscriptions in the queue.</returns> public IList <Subscription> Close() { lock (m_lock) { // TraceState("SESSION CLOSED"); // wake up any waiting publish requests. m_publishEvent.Set(); while (m_queuedRequests.Count > 0) { QueuedRequest request = m_queuedRequests.First.Value; m_queuedRequests.RemoveFirst(); request.Error = StatusCodes.BadSessionClosed; request.Set(); } // tell the subscriptions that the session is closed. Subscription[] subscriptions = new Subscription[m_queuedSubscriptions.Count]; for (int ii = 0; ii < m_queuedSubscriptions.Count; ii++) { subscriptions[ii] = m_queuedSubscriptions[ii].Subscription; subscriptions[ii].SessionClosed(); } // clear the queue. m_queuedSubscriptions.Clear(); return(subscriptions); } }
private void EnqueueRequest(QueuedRequest request) { if (_workItemsCount < _maxWorkItemsCount) { // schedule new work item to handle request Interlocked.Increment(ref _workItemsCount); ThreadPool.QueueUserWorkItem(_workItemCallback, request); } else { lock (this) { if (_requestQueueSize > _maxRequestQueueSize) { // wait for the place in the queue if (!Monitor.Wait(this, _queueTimeout)) { // so, we can't handle requests now... :( ProcessErrorAndClose(request.Connection, new RemotingException("Server was over-burdened")); return; } } // request will wait for the next available work item _requests.Enqueue(request); ++_requestQueueSize; } } }
/// <summary> /// An overrideable version of the Dispose. /// </summary> protected virtual void Dispose(bool disposing) { if (disposing) { lock (m_lock) { m_publishEvent.Set(); while (m_queuedRequests.Count > 0) { QueuedRequest request = m_queuedRequests.First.Value; m_queuedRequests.RemoveFirst(); try { request.Error = StatusCodes.BadServerHalted; request.Dispose(); } catch (Exception) { // ignore errors. } } m_queuedSubscriptions.Clear(); m_publishEvent.Close(); } } }
private void ExecuteRequest(HttpWebRequest webRequest, HttpRequestQueueCallback callback, object state) { if (this.queue.Count > this.MaxQueuedRequests) { callback(HttpRequestQueueResultCode.QueueFull, null, state); return; } var request = new QueuedRequest { Request = webRequest, Callback = callback, PostData = null, State = state, }; switch (this.QueueState) { case HttpRequestQueueState.Connecting: this.ExecuteRequestConnecting(request); break; case HttpRequestQueueState.Reconnecting: this.ExecuteRequestReconnecting(request); break; case HttpRequestQueueState.Running: this.ExecuteRequestOnline(request); break; case HttpRequestQueueState.Offline: this.ExecuteRequestOffline(request); break; } }
private void Enqueue(QueuedRequest request) { lock (requestQueue) { requestQueue.Add(request); } }
/// <summary> /// Checks the state of the subscriptions. /// </summary> private void AssignSubscriptionToRequest(QueuedSubscription subscription) { // find a request. for (LinkedListNode <QueuedRequest> node = m_queuedRequests.First; node != null; node = node.Next) { QueuedRequest request = node.Value; StatusCode error = StatusCodes.Good; // check if expired. if (request.Deadline < DateTime.MaxValue && request.Deadline.AddMilliseconds(500) < DateTime.UtcNow) { error = StatusCodes.BadTimeout; } // check secure channel. else if (!m_session.IsSecureChannelValid(request.SecureChannelId)) { error = StatusCodes.BadSecureChannelIdInvalid; Utils.Trace("Publish abandoned because the secure channel changed."); } if (StatusCode.IsBad(error)) { // remove request. LinkedListNode <QueuedRequest> next = node.Next; m_queuedRequests.Remove(node); node = next; // wake up thread with error. request.Error = error; request.Set(); if (node == null) { break; } continue; } // remove request. m_queuedRequests.Remove(node); // Utils.Trace("PUBLISH: #000 Assigned To Subscription({0}).", subscription.Subscription.Id); request.Error = StatusCodes.Good; request.Subscription = subscription; request.Subscription.Publishing = true; request.Set(); return; } // mark it as available. subscription.ReadyToPublish = true; subscription.Timestamp = DateTime.UtcNow; }
private void ExecuteRequestOnline(QueuedRequest request) { if (RunningRequestsCount >= MaxConcurrentRequests) { queue.AddLast(request); return; } ExecuteHttpRequest(request); }
private void ExecuteRequestConnecting(QueuedRequest request) { if (RunningRequestsCount < MaxConcurrentRequests) { ExecuteHttpRequest(request); return; } queue.AddLast(request); }
private void ExecuteRequestReconnecting(QueuedRequest request) { if (this.RunningRequestsCount < 1) { this.ExecuteHttpRequest(request); return; } request.Callback(HttpRequestQueueResultCode.Offline, null, request.State); }
private void ExecuteRequestConnecting(QueuedRequest request) { if (this.RunningRequestsCount < this.MaxConcurrentRequests) { this.ExecuteHttpRequest(request); return; } this.queue.AddLast(request); }
private void ExecuteRequestOffline(QueuedRequest request) { if (DateTime.UtcNow >= this.nextReconnectTime) { this.QueueState = HttpRequestQueueState.Reconnecting; this.ExecuteHttpRequest(request); return; } request.Callback(HttpRequestQueueResultCode.Offline, null, request.State); }
private void OnDataAvailable(Exception ex, object state) { QueuedRequest request = (QueuedRequest)state; if (ex == null) { // process request on this thread ProcessRequest(request); } else { // process error message ProcessErrorAndClose(request.Connection, ex); } }
private QueuedRequest DequeueRequest() { QueuedRequest request = null; lock (this) { if (_requestQueueSize > 0) { request = (QueuedRequest)_requests.Dequeue(); --_requestQueueSize; } } return(request); }
private QueuedRequest Dequeue() { QueuedRequest request = null; lock (requestQueue) { if (requestQueue.Count > 0) { request = requestQueue[0]; requestQueue.RemoveAt(0); } } return(request); }
private void OnNewWorkItem(object state) { QueuedRequest request = (QueuedRequest)state; while (request != null) { // process request on this thread ProcessRequest(request); // get next request request = DequeueRequest(); } Interlocked.Decrement(ref _workItemsCount); }
/// <summary> /// Completes the publish. /// </summary> /// <param name="requeue">if set to <c>true</c> the request must be requeued.</param> /// <param name="operation">The asynchronous operation.</param> /// <param name="calldata">The calldata.</param> /// <returns></returns> public Subscription CompletePublish( bool requeue, AsyncPublishOperation operation, object calldata) { // Utils.Trace("PUBLISH: #{0} Completing", operation.RequestHandle, requeue); QueuedRequest request = (QueuedRequest)calldata; // check if need to requeue. lock (m_lock) { if (requeue) { request.Subscription = null; request.Error = StatusCodes.Good; m_queuedRequests.AddFirst(request); return(null); } } // must reassign subscription on error. if (ServiceResult.IsBad(request.Error)) { // Utils.Trace("PUBLISH: #{0} Reassigned ERROR({1})", operation.RequestHandle, request.Error); if (request.Subscription != null) { lock (m_lock) { request.Subscription.Publishing = false; AssignSubscriptionToRequest(request.Subscription); } } // TraceState("REQUEST #{0} PUBLISH ERROR ({1})", clientHandle, error.StatusCode); throw new ServiceResultException(request.Error); } // must be shuting down if this is null but no error. if (request.Subscription == null) { throw new ServiceResultException(StatusCodes.BadNoSubscription); } // return whatever was assigned. return(request.Subscription.Subscription); }
private void ProcessRequest(QueuedRequest request) { try { // process request request.RequestHandler(request.Connection); // wait for the next request on this connection BeginWaitForRequest(request); } catch (Exception ex) { // process error message ProcessErrorAndClose(request.Connection, ex); } }
private void BeginWaitForRequest(QueuedRequest request) { int workerThreads, ioThreads; ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads); int freeThreads = (ioThreads > workerThreads) ? workerThreads : ioThreads; if (freeThreads > _minFreeThreads) { // schedule new thread to wait for the request request.Connection.BeginReceive(_requestAvailableCallback, request); } else { // use request queue... EnqueueRequest(request); } }
private void ExecuteHttpRequest(QueuedRequest request) { try { this.RunningRequestsCount++; var asyncHttpRequest = new AsyncHttpRequest(request.Request, this.WebRequestCallback, request); if (request.PostData == null) { asyncHttpRequest.GetAsync(); } else { asyncHttpRequest.PostAsync(request.PostData); } } catch (Exception ex) { log.Error(ex); } }
/// <summary> /// Returns a subscription that is ready to publish. /// </summary> public Subscription Publish(uint clientHandle, DateTime deadline, bool requeue, AsyncPublishOperation operation) { QueuedRequest request = null; // DateTime queueTime = DateTime.UtcNow; // DateTime dequeueTime = DateTime.UtcNow; lock (m_lock) { if (m_queuedSubscriptions.Count == 0) { // TraceState("PUBLISH ERROR (BadNoSubscription)"); throw new ServiceResultException(StatusCodes.BadNoSubscription); } // find the waiting subscription with the highest priority. List<QueuedSubscription> subscriptions = new List<QueuedSubscription>(); for (int ii = 0; ii < m_queuedSubscriptions.Count; ii++) { QueuedSubscription subscription = m_queuedSubscriptions[ii]; if (subscription.ReadyToPublish && !subscription.Publishing) { subscriptions.Add(subscription); } } // find waiting the subscription that has been waiting the longest. if (subscriptions.Count > 0) { byte maxPriority = 0; DateTime earliestTimestamp = DateTime.MaxValue; QueuedSubscription subscriptionToPublish = null; for (int ii = 0; ii < subscriptions.Count; ii++) { QueuedSubscription subscription = subscriptions[ii]; if (subscription.Priority > maxPriority) { maxPriority = subscription.Priority; earliestTimestamp = DateTime.MaxValue; } if (subscription.Priority >= maxPriority && earliestTimestamp > subscription.Timestamp) { earliestTimestamp = subscription.Timestamp; subscriptionToPublish = subscription; } } // reset subscriptions flag. m_subscriptionsWaiting = false; for (int jj = 0; jj < m_queuedSubscriptions.Count; jj++) { if (m_queuedSubscriptions[jj].ReadyToPublish) { m_subscriptionsWaiting = true; break; } } // TraceState("REQUEST #{0} ASSIGNED TO WAITING SUBSCRIPTION", clientHandle); subscriptionToPublish.Publishing = true; return subscriptionToPublish.Subscription; } // queue request because there is nothing waiting. if (subscriptions.Count == 0) { LinkedListNode<QueuedRequest> node = m_queuedRequests.First; while (node != null) { LinkedListNode<QueuedRequest> next = node.Next; QueuedRequest queuedRequest = node.Value; StatusCode requestStatus = StatusCodes.Good; // check if expired. if (queuedRequest.Deadline < DateTime.MaxValue && queuedRequest.Deadline.AddMilliseconds(500) < DateTime.UtcNow) { requestStatus = StatusCodes.BadTimeout; } // check secure channel. else if (!m_session.IsSecureChannelValid(queuedRequest.SecureChannelId)) { requestStatus = StatusCodes.BadSecureChannelIdInvalid; } // remove bad requests. if (StatusCode.IsBad(requestStatus)) { queuedRequest.Error = requestStatus; queuedRequest.Set(); m_queuedRequests.Remove(node); } node = next; } // clear excess requests - keep the newest ones. while (m_maxPublishRequests > 0 && m_queuedRequests.Count >= m_maxPublishRequests) { request = m_queuedRequests.First.Value; request.Error = StatusCodes.BadTooManyPublishRequests; request.Set(); m_queuedRequests.RemoveFirst(); } request = new QueuedRequest(); request.SecureChannelId = SecureChannelContext.Current.SecureChannelId; request.Deadline = deadline; request.Subscription = null; request.Error = StatusCodes.Good; if (operation == null) { request.Event = new ManualResetEvent(false); } else { request.Operation = operation; } if (requeue) { m_queuedRequests.AddFirst(request); // TraceState("REQUEST #{0} RE-QUEUED", clientHandle); } else { m_queuedRequests.AddLast(request); // TraceState("REQUEST #{0} QUEUED", clientHandle); } } } // check for non-blocking operation. if (operation != null) { // TraceState("PUBLISH: #{0} Async Request Queued.", clientHandle); return null; } // wait for subscription. ServiceResult error = request.Wait(Timeout.Infinite); // check for error. if (ServiceResult.IsGood(error)) { if (StatusCode.IsBad(request.Error)) { error = request.Error; } } // must reassign subscription on error. if (ServiceResult.IsBad(request.Error)) { if (request.Subscription != null) { lock (m_lock) { request.Subscription.Publishing = false; AssignSubscriptionToRequest(request.Subscription); } } // TraceState("REQUEST #{0} PUBLISH ERROR ({1})", clientHandle, error.StatusCode); throw new ServiceResultException(request.Error); } // must be shuting down if this is null but no error. if (request.Subscription == null) { throw new ServiceResultException(StatusCodes.BadNoSubscription); } // TraceState("REQUEST #{0} ASSIGNED", clientHandle); // return whatever was assigned. return request.Subscription.Subscription; }
/// <summary> /// Tells the server that the client is ready to receive notifications from the server. /// </summary> public PublishResponseMessage Publish(PublishMessage request) { try { // validate the sesion Session session = VerifySession(request.RequestHeader, false); uint subscriptionId = 0; NotificationMessage message = null; QueuedRequest queuedRequest = new QueuedRequest(); lock (m_messages) { // first check if there are any messages waiting to be published. for (LinkedListNode<QueuedMessage> node = m_messages.First; node != null; node = node.Next) { // ensure the message belongs to the current session if (Object.ReferenceEquals(session, node.Value.Session)) { // pull the message off the queue and return. subscriptionId = node.Value.Subscription.Id; message = node.Value.Message; m_messages.Remove(node); break; } } // must process requests in the order that they arrive. if (message == null) { queuedRequest.Session = session; queuedRequest.Timeout = DateTime.UtcNow.AddMilliseconds(request.RequestHeader.TimeoutHint); queuedRequest.Signal = new ManualResetEvent(false); m_requests.AddLast(queuedRequest); } } // wait for a notification. if (message == null) { try { queuedRequest.Signal.WaitOne(); if (queuedRequest.Message == null) { throw new StatusCodeException(StatusCodes.BadTimeout, "Timed out waiting for notifications."); } subscriptionId = queuedRequest.SubscriptionId; message = queuedRequest.Message; } finally { queuedRequest.Signal.Close(); } } // sent response. PublishResponseMessage response = new PublishResponseMessage(); response.ResponseHeader = CreateResponseHeader(request.RequestHeader); response.SubscriptionId = subscriptionId; response.NotificationMessage = message; response.MoreNotifications = false; response.Results = new ListOfStatusCode(); response.DiagnosticInfos = new ListOfDiagnosticInfo(); response.AvailableSequenceNumbers = new ListOfUInt32(); return response; } catch (Exception e) { throw CreateSoapFault(request.RequestHeader, e); } }
/// <summary> /// Returns a subscription that is ready to publish. /// </summary> public Subscription Publish(uint clientHandle, DateTime deadline, bool requeue, AsyncPublishOperation operation) { QueuedRequest request = null; // DateTime queueTime = DateTime.UtcNow; // DateTime dequeueTime = DateTime.UtcNow; lock (m_lock) { if (m_queuedSubscriptions.Count == 0) { // TraceState("PUBLISH ERROR (BadNoSubscription)"); throw new ServiceResultException(StatusCodes.BadNoSubscription); } // find the waiting subscription with the highest priority. List <QueuedSubscription> subscriptions = new List <QueuedSubscription>(); for (int ii = 0; ii < m_queuedSubscriptions.Count; ii++) { QueuedSubscription subscription = m_queuedSubscriptions[ii]; if (subscription.ReadyToPublish && !subscription.Publishing) { subscriptions.Add(subscription); } } // find waiting the subscription that has been waiting the longest. if (subscriptions.Count > 0) { byte maxPriority = 0; DateTime earliestTimestamp = DateTime.MaxValue; QueuedSubscription subscriptionToPublish = null; for (int ii = 0; ii < subscriptions.Count; ii++) { QueuedSubscription subscription = subscriptions[ii]; if (subscription.Priority > maxPriority) { maxPriority = subscription.Priority; earliestTimestamp = DateTime.MaxValue; } if (subscription.Priority >= maxPriority && earliestTimestamp > subscription.Timestamp) { earliestTimestamp = subscription.Timestamp; subscriptionToPublish = subscription; } } // reset subscriptions flag. m_subscriptionsWaiting = false; for (int jj = 0; jj < m_queuedSubscriptions.Count; jj++) { if (m_queuedSubscriptions[jj].ReadyToPublish) { m_subscriptionsWaiting = true; break; } } // TraceState("REQUEST #{0} ASSIGNED TO WAITING SUBSCRIPTION", clientHandle); subscriptionToPublish.Publishing = true; return(subscriptionToPublish.Subscription); } // queue request because there is nothing waiting. if (subscriptions.Count == 0) { LinkedListNode <QueuedRequest> node = m_queuedRequests.First; while (node != null) { LinkedListNode <QueuedRequest> next = node.Next; QueuedRequest queuedRequest = node.Value; StatusCode requestStatus = StatusCodes.Good; // check if expired. if (queuedRequest.Deadline < DateTime.MaxValue && queuedRequest.Deadline.AddMilliseconds(500) < DateTime.UtcNow) { requestStatus = StatusCodes.BadTimeout; } // check secure channel. else if (!m_session.IsSecureChannelValid(queuedRequest.SecureChannelId)) { requestStatus = StatusCodes.BadSecureChannelIdInvalid; } // remove bad requests. if (StatusCode.IsBad(requestStatus)) { queuedRequest.Error = requestStatus; queuedRequest.Set(); m_queuedRequests.Remove(node); } node = next; } // clear excess requests - keep the newest ones. while (m_maxPublishRequests > 0 && m_queuedRequests.Count >= m_maxPublishRequests) { request = m_queuedRequests.First.Value; request.Error = StatusCodes.BadTooManyPublishRequests; request.Set(); m_queuedRequests.RemoveFirst(); } request = new QueuedRequest(); request.SecureChannelId = SecureChannelContext.Current.SecureChannelId; request.Deadline = deadline; request.Subscription = null; request.Error = StatusCodes.Good; if (operation == null) { request.Event = new ManualResetEvent(false); } else { request.Operation = operation; } if (requeue) { m_queuedRequests.AddFirst(request); // TraceState("REQUEST #{0} RE-QUEUED", clientHandle); } else { m_queuedRequests.AddLast(request); // TraceState("REQUEST #{0} QUEUED", clientHandle); } } } // check for non-blocking operation. if (operation != null) { // TraceState("PUBLISH: #{0} Async Request Queued.", clientHandle); return(null); } // wait for subscription. ServiceResult error = request.Wait(Timeout.Infinite); // check for error. if (ServiceResult.IsGood(error)) { if (StatusCode.IsBad(request.Error)) { error = request.Error; } } // must reassign subscription on error. if (ServiceResult.IsBad(request.Error)) { if (request.Subscription != null) { lock (m_lock) { request.Subscription.Publishing = false; AssignSubscriptionToRequest(request.Subscription); } } // TraceState("REQUEST #{0} PUBLISH ERROR ({1})", clientHandle, error.StatusCode); throw new ServiceResultException(request.Error); } // must be shuting down if this is null but no error. if (request.Subscription == null) { throw new ServiceResultException(StatusCodes.BadNoSubscription); } // TraceState("REQUEST #{0} ASSIGNED", clientHandle); // return whatever was assigned. return(request.Subscription.Subscription); }
/// <summary> /// Tells the server that the client is ready to receive notifications from the server. /// </summary> public PublishResponseMessage Publish(PublishMessage request) { try { // validate the sesion Session session = VerifySession(request.RequestHeader, false); uint subscriptionId = 0; NotificationMessage message = null; QueuedRequest queuedRequest = new QueuedRequest(); lock (m_messages) { // first check if there are any messages waiting to be published. for (LinkedListNode <QueuedMessage> node = m_messages.First; node != null; node = node.Next) { // ensure the message belongs to the current session if (Object.ReferenceEquals(session, node.Value.Session)) { // pull the message off the queue and return. subscriptionId = node.Value.Subscription.Id; message = node.Value.Message; m_messages.Remove(node); break; } } // must process requests in the order that they arrive. if (message == null) { queuedRequest.Session = session; queuedRequest.Timeout = DateTime.UtcNow.AddMilliseconds(request.RequestHeader.TimeoutHint); queuedRequest.Signal = new ManualResetEvent(false); m_requests.AddLast(queuedRequest); } } // wait for a notification. if (message == null) { try { queuedRequest.Signal.WaitOne(); if (queuedRequest.Message == null) { throw new StatusCodeException(StatusCodes.BadTimeout, "Timed out waiting for notifications."); } subscriptionId = queuedRequest.SubscriptionId; message = queuedRequest.Message; } finally { queuedRequest.Signal.Close(); } } // sent response. PublishResponseMessage response = new PublishResponseMessage(); response.ResponseHeader = CreateResponseHeader(request.RequestHeader); response.SubscriptionId = subscriptionId; response.NotificationMessage = message; response.MoreNotifications = false; response.Results = new ListOfStatusCode(); response.DiagnosticInfos = new ListOfDiagnosticInfo(); response.AvailableSequenceNumbers = new ListOfUInt32(); return(response); } catch (Exception e) { throw CreateSoapFault(request.RequestHeader, e); } }