File: Plugins\InboundRequestProcessingHandler.cs
Web Access
Project: src\src\nuget-client\src\NuGet.Core\NuGet.Protocol\NuGet.Protocol.csproj (NuGet.Protocol)
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace NuGet.Protocol.Plugins
{
    internal class InboundRequestProcessingHandler : IDisposable
    {
        private readonly ISet<MessageMethod> _fastProccessingMethods;
        private readonly Lazy<DedicatedAsynchronousProcessingThread> _processingThread;
        private bool _isDisposed;

        public InboundRequestProcessingHandler()
            : this(Enumerable.Empty<MessageMethod>())
        {
        }

        /// <summary>
        /// Requests from the processing methods provided in this set are handled on a dedicated thread.
        /// </summary>
        /// <param name="fastProcessingMethods"></param>
        public InboundRequestProcessingHandler(IEnumerable<MessageMethod> fastProcessingMethods)
        {
            if (fastProcessingMethods == null)
            {
                throw new ArgumentNullException(nameof(fastProcessingMethods));
            }
            _fastProccessingMethods = new HashSet<MessageMethod>(fastProcessingMethods);
            // Lazily initialize the processing thread. It is not needed if there are no time critical methods.
            _processingThread = new Lazy<DedicatedAsynchronousProcessingThread>(() =>
            {
                var thread = new DedicatedAsynchronousProcessingThread(TimeSpan.FromMilliseconds(50));
                thread.Start();
                return thread;
            });

        }

        /// <summary>
        /// Methods that are in the fast processing method list will be handled on a separate thread. Everything else will be queued on the threadpool.
        /// </summary>
        /// <param name="messageMethod"></param>
        /// <param name="task"></param>
        /// <param name="cancellationToken"></param>
        internal void Handle(MessageMethod messageMethod, Func<Task> task, CancellationToken cancellationToken)
        {
            ThrowIfDisposed();
            if (_fastProccessingMethods.Contains(messageMethod))
            {
                _processingThread.Value.Enqueue(task);
            }
            else
            {
                Task.Run(task, cancellationToken);
            }
        }

        public void Dispose()
        {
            if (_isDisposed)
            {
                return;
            }
            if (_processingThread.IsValueCreated)
            {
                _processingThread.Value.Dispose();
            }
            GC.SuppressFinalize(this);

            _isDisposed = true;
        }

        private void ThrowIfDisposed()
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
        }
    }
}