コード例 #1
0
ファイル: ResponseCache.cs プロジェクト: dragthor/BridgeStack
        /// <summary>
        /// Attempts to push API responses into the cache store.
        /// </summary>
        /// <typeparam name="T">The strong type of the expected API result.</typeparam>
        /// <param name="builder">The object that builds the API route endpoint.</param>
        /// <param name="response">The API response.</param>
        /// <returns>True if the operation was successful, false otherwise.</returns>
        public bool Push <T>(IApiEndpointBuilder builder, IApiResponse <T> response) where T : class
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }
            string endpoint = builder.ToString();

            if (endpoint.NullOrEmpty())
            {
                return(false);
            }
            IResponseCacheItem item;

            if (Cache.TryGetValue(endpoint, out item))
            {
                if (item is IResponseCacheItem <T> )               // avoid raising exceptions when improperly invoked.
                {
                    ((IResponseCacheItem <T>)item).UpdateResponse(response);
                    return(true);
                }
                return(false);
            }
            else
            {
                item = new ResponseCacheItem <T>(response, builder);
                return(Cache.TryAdd(endpoint, item));
            }
        }
コード例 #2
0
ファイル: ResponseCache.cs プロジェクト: dragthor/BridgeStack
        /// <summary>
        /// Attempts to access the internal cache and retrieve a response cache item without querying the API.
        /// <para>If the endpoint is not present in the cache yet, null is returned, but the endpoint is added to the cache.</para>
        /// <para>If the endpoint is present, it means the request is being processed. In this case we will wait on the processing to end before returning a result.</para>
        /// </summary>
        /// <typeparam name="T">The strong type of the expected API result.</typeparam>
        /// <param name="builder">The object that builds the API route endpoint.</param>
        /// <param name="pushEmpty">True to push an empty value into the cache if the endpoint isn't present yet.</param>
        /// <param name="retries">The amount of failed push attempts.</param>
        /// <returns>Returns an API response cache item if successful, null otherwise.</returns>
        private IResponseCacheItem <T> Get <T>(IApiEndpointBuilder builder, bool pushEmpty, int retries) where T : class
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }
            string             endpoint = builder.ToString();
            IResponseCacheItem cacheItem;

            if (Cache.TryGetValue(endpoint, out cacheItem))
            {
                while (cacheItem.IsFresh && cacheItem.State == CacheItemStateEnum.Processing)
                {
                    using (AutoResetEvent signal = new AutoResetEvent(false))
                    {
                        signal.WaitOne(50);
                    }
                }
                if (cacheItem.IsFresh && cacheItem.State == CacheItemStateEnum.Cached)
                {
                    return(cacheItem as IResponseCacheItem <T>);                   // avoid raising exceptions when improperly invoked.
                }
                IResponseCacheItem value;
                Cache.TryRemove(endpoint, out value);
            }
            if (!pushEmpty || Push <T>(builder, null) || retries > 1)            // max retries, sanity.
            {
                return(null);
            }
            else
            {
                return(Get <T>(builder, true, ++retries));               // retry push.
            }
        }
コード例 #3
0
 /// <summary>
 /// When necessary, throttles requests in order to prevent flooding the API endpoints.
 /// </summary>
 /// <typeparam name="T">The strong type of the expected API result against which to deserialize JSON.</typeparam>
 /// <param name="builder">The object that builds the API route endpoint.</param>
 /// <returns>The API response object.</returns>
 public IApiResponse <T> Throttle <T>(IApiEndpointBuilder builder) where T : class
 {
     while (ConcurrentRequests >= MaxConcurrentRequests)
     {
         using (AutoResetEvent signal = new AutoResetEvent(false))
         {
             signal.WaitOne(100);
         }
     }
     if (_requestStartTime.Count >= MaxRequestsInTimeframe)
     {
         DateTime start;
         if (_requestStartTime.TryDequeue(out start))
         {
             TimeSpan delta = DateTime.Now - start;
             TimeSpan delay = SlidingTimeframe - delta;
             if (delay > TimeSpan.Zero)
             {
                 using (AutoResetEvent signal = new AutoResetEvent(false))
                 {
                     signal.WaitOne(delay);
                 }
             }
         }
     }
     _requestStartTime.Enqueue(DateTime.Now);
     return(PerformRequest <T>(builder.ToString()));
 }
コード例 #4
0
 /// <summary>
 /// Creates a cache item out of an API response.
 /// </summary>
 /// <param name="response">The API response object.</param>
 /// <param name="builder">The API endpoint builder that generated the endpoint the response came from.</param>
 public ResponseCacheItem(IApiResponse <T> response, IApiEndpointBuilder builder)
 {
     if (builder == null)
     {
         throw new ArgumentNullException("builder");
     }
     LifeSpan = builder.Client.Cache.GetCacheLifeSpan(builder) ?? DefaultLifeSpan;
     UpdateResponse(response);
 }
コード例 #5
0
ファイル: ResponseCache.cs プロジェクト: dragthor/BridgeStack
        /// <summary>
        /// Gets the life span for cache items based on the provided instance of <see cref="IApiEndpointBuilder"/>.
        /// </summary>
        /// <param name="builder">The object that builds the API route endpoint.</param>
        /// <returns>The life span duration after which a cache item is no longer considered fresh.</returns>
        public TimeSpan?GetCacheLifeSpan(IApiEndpointBuilder builder)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }
            ApiMethodEnum method = builder.ApiMethod;

            return(method.GetCacheLifeSpan(Client));
        }
コード例 #6
0
        /// <summary>
        /// Processes a request, attempting to retrieve results from the cache whenever possible, and making API calls otherwise.
        /// </summary>
        /// <typeparam name="T">The strong type of the expected API result against which to deserialize JSON.</typeparam>
        /// <param name="builder">The object that builds the API route endpoint.</param>
        /// <returns>A wrapper object around the result object. It's source is either the API, the internal cache, or raised exceptions.</returns>
        public IBridgeResponseCollection <T> ProcessRequest <T>(IApiEndpointBuilder builder) where T : class
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }
            IApiResponse <T> response            = GetResponse <T>(builder);
            IBridgeResponseCollection <T> result = new BridgeResponseCollection <T>(this, builder, response);

            return(result);
        }
コード例 #7
0
        /// <summary>
        /// Attempts to fetch the response object from the cache instead of directly from the API.
        /// </summary>
        /// <typeparam name="T">The strong type of the expected API result against which to deserialize JSON.</typeparam>
        /// <param name="builder">The object that builds the API route endpoint.</param>
        /// <returns>The API response object.</returns>
        private IApiResponse <T> FetchFromCache <T>(IApiEndpointBuilder builder) where T : class
        {
            IResponseCacheItem <T> cacheItem = Client.Cache.Get <T>(builder, true);

            if (cacheItem != null)
            {
                IApiResponse <T> response = cacheItem.Response;
                response.Source = ResultSourceEnum.Cache;
                return(response);
            }
            return(null);
        }
コード例 #8
0
 /// <summary>
 /// Creates a Bridge response object that contains a collection of result items.
 /// </summary>
 /// <param name="requestHandler">The request handler.</param>
 /// <param name="builder">The API endpoint builder.</param>
 /// <param name="response">The API response object.</param>
 internal BridgeResponseCollection(IRequestHandler requestHandler, IApiEndpointBuilder builder, IApiResponse <T> response)
 {
     if (requestHandler == null)
     {
         throw new ArgumentNullException("requestHandler");
     }
     if (builder == null)
     {
         throw new ArgumentNullException("builder");
     }
     if (response == null)
     {
         throw new ArgumentNullException("response");
     }
     _requestHandler = requestHandler;
     EndpointBuilder = builder;
     Response        = response;
 }
コード例 #9
0
        /// <summary>
        /// Produces the response object based on the API endpoint builder provided.
        /// </summary>
        /// <typeparam name="T">The strong type of the expected API result against which to deserialize JSON.</typeparam>
        /// <param name="builder">The object that builds the API route endpoint.</param>
        /// <returns>The API response object.</returns>
        private IApiResponse <T> GetResponse <T>(IApiEndpointBuilder builder) where T : class
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }
            IApiResponse <T> response = null;

            try
            {
                response = InternalProcessing <T>(builder);                // Source = Api | Cache
            }
            catch (BridgeException api)
            {
                response = new ApiResponse <T>                // Source = BridgeException
                {
                    Exception = api,
                    Source    = ResultSourceEnum.BridgeException
                };
            }
            catch (WebException web)
            {
                response = HandleWebException <T>(web);                // Source = ApiException
            }
            finally
            {
                if (response != null)
                {
                    response.SourceClient = Client;
                    if (response.Source != ResultSourceEnum.Cache)
                    {
                        Client.Cache.Push(builder, response);
                    }
                }
            }
            return(response);
        }
コード例 #10
0
        /// <summary>
        /// Checks the cache and then performs the actual request, if required.
        /// </summary>
        /// <typeparam name="T">The strong type of the expected API result against which to deserialize JSON.</typeparam>
        /// <param name="builder">The object that builds the API route endpoint.</param>
        /// <returns>The API response object.</returns>
        private IApiResponse <T> InternalProcessing <T>(IApiEndpointBuilder builder) where T : class
        {
            IApiResponse <T> response = FetchFromCache <T>(builder);

            return(response ?? FetchFromThrottler <T>(builder));
        }
コード例 #11
0
 /// <summary>
 /// Throttling ensures the API isn't flooded with requests and prevents us from getting cut off from the API.
 /// </summary>
 /// <typeparam name="T">The strong type of the expected API result against which to deserialize JSON.</typeparam>
 /// <param name="builder">The object that builds the API route endpoint.</param>
 /// <returns>The API response object.</returns>
 private IApiResponse <T> FetchFromThrottler <T>(IApiEndpointBuilder builder) where T : class
 {
     return(Client.Throttler.Throttle <T>(builder));
 }
コード例 #12
0
ファイル: ResponseCache.cs プロジェクト: dragthor/BridgeStack
 /// <summary>
 /// Attempts to access the internal cache and retrieve a response cache item without querying the API.
 /// <para>If the endpoint is not present in the cache yet, null is returned, but the endpoint is added to the cache.</para>
 /// <para>If the endpoint is present, it means the request is being processed. In this case we will wait on the processing to end before returning a result.</para>
 /// </summary>
 /// <typeparam name="T">The strong type of the expected API result.</typeparam>
 /// <param name="builder">The object that builds the API route endpoint.</param>
 /// <param name="pushEmpty">True to push an empty value into the cache if the endpoint isn't present yet.</param>
 /// <returns>Returns an API response cache item if successful, null otherwise.</returns>
 public IResponseCacheItem <T> Get <T>(IApiEndpointBuilder builder, bool pushEmpty = false) where T : class
 {
     return(Get <T>(builder, pushEmpty, 0));
 }