public Task TrackAsync(DateTime date, string key, string?category, Counters counters,
                               CancellationToken ct = default)
        {
            Guard.NotNull(key, nameof(key));

            return(inner.TrackAsync(date, key, category, counters, ct));
        }
        public async Task Should_forward_track_call()
        {
            await sut.TrackAsync(key, "MyCategory", 123, 456);

            A.CallTo(() => inner.TrackAsync(key, "MyCategory", 123, 456))
            .MustHaveHappened();
        }
示例#3
0
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var appFeature = context.HttpContext.Features.Get <IAppFeature>();

            if (appFeature?.App != null && FilterDefinition.Weight > 0)
            {
                var stopWatch = Stopwatch.StartNew();

                try
                {
                    var plan = appPlanProvider.GetPlanForApp(appFeature.App);

                    var usage = await usageTracker.GetMonthlyCalls(appFeature.App.Id.ToString(), DateTime.Today);

                    if (plan.MaxApiCalls >= 0 && (usage * 1.1) > plan.MaxApiCalls)
                    {
                        context.Result = new StatusCodeResult(429);
                        return;
                    }

                    await next();
                }
                finally
                {
                    stopWatch.Stop();

                    await usageTracker.TrackAsync(appFeature.App.Id.ToString(), FilterDefinition.Weight, stopWatch.ElapsedMilliseconds);
                }
            }
            else
            {
                await next();
            }
        }
示例#4
0
        public async Task Should_return_429_status_code_if_max_calls_over_limit()
        {
            sut.FilterDefinition = new ApiCostsAttribute(1);

            SetupApp();

            apiCallsCurrent = 1000;
            apiCallsMax     = 600;

            await sut.OnActionExecutionAsync(actionContext, next);

            Assert.Equal(429, (actionContext.Result as StatusCodeResult)?.StatusCode);
            Assert.False(isNextCalled);

            A.CallTo(() => usageTracker.TrackAsync(A <string> .Ignored, A <string> .Ignored, A <double> .Ignored, A <double> .Ignored))
            .MustNotHaveHappened();
        }
示例#5
0
        public async Task Should_forward_track_call()
        {
            var counters = new Counters();

            await sut.TrackAsync(date, key, "my-category", counters);

            A.CallTo(() => inner.TrackAsync(date, key, "my-category", counters))
            .MustHaveHappened();
        }
示例#6
0
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            context.HttpContext.Features.Set <IApiCostsFeature>(FilterDefinition);

            var app = context.HttpContext.Context().App;

            if (app != null)
            {
                var appId = app.Id.ToString();

                if (FilterDefinition.Weight > 0)
                {
                    using (Profiler.Trace("CheckUsage"))
                    {
                        var plan = appPlansProvider.GetPlanForApp(app);

                        var usage = await usageTracker.GetMonthlyCallsAsync(appId, DateTime.Today);

                        if (plan?.MaxApiCalls >= 0 && usage > plan.MaxApiCalls * 1.1)
                        {
                            context.Result = new StatusCodeResult(429);
                            return;
                        }
                    }
                }

                var watch = ValueStopwatch.StartNew();

                try
                {
                    await next();
                }
                finally
                {
                    var elapsedMs = watch.Stop();

                    await appLogStore.LogAsync(app.Id, clock.GetCurrentInstant(),
                                               context.HttpContext.Request.Method,
                                               context.HttpContext.Request.Path,
                                               context.HttpContext.User.OpenIdSubject(),
                                               context.HttpContext.User.OpenIdClientId(),
                                               elapsedMs,
                                               FilterDefinition.Weight);

                    if (FilterDefinition.Weight > 0)
                    {
                        await usageTracker.TrackAsync(appId, context.HttpContext.User.OpenIdClientId(), FilterDefinition.Weight, elapsedMs);
                    }
                }
            }
            else
            {
                await next();
            }
        }
示例#7
0
        public Task TrackAsync(DateTime date, string key, string?category, double weight, long elapsedMs, long bytes)
        {
            var apiKey = GetKey(key);

            var counters = new Counters
            {
                [CounterTotalCalls]     = weight,
                [CounterTotalElapsedMs] = elapsedMs,
                [CounterTotalBytes]     = bytes
            };

            return(usageTracker.TrackAsync(date, apiKey, category, counters));
        }
示例#8
0
        public async Task Invoke(HttpContext context)
        {
            var stopWatch = Stopwatch.StartNew();

            await next(context);

            var appFeature = context.Features.Get <IAppFeature>();

            if (appFeature?.App != null)
            {
                stopWatch.Stop();

                var weight = context.Features.Get <IAppTrackingWeightFeature>()?.Weight ?? 1;

                await usageTracker.TrackAsync(appFeature.App.Id.ToString(), weight, stopWatch.ElapsedMilliseconds);
            }
        }
示例#9
0
        public async Task Should_track_usage()
        {
            Counters?measuredCounters = null;

            A.CallTo(() => usageTracker.TrackAsync(date, $"{key}_API", null, A <Counters> .Ignored, ct))
            .Invokes(args =>
            {
                measuredCounters = args.GetArgument <Counters>(3) !;
            });

            await sut.TrackAsync(date, key, null, 4, 120, 1024, ct);

            measuredCounters.Should().BeEquivalentTo(new Counters
            {
                [ApiUsageTracker.CounterTotalBytes]     = 1024,
                [ApiUsageTracker.CounterTotalCalls]     = 4,
                [ApiUsageTracker.CounterTotalElapsedMs] = 120
            });
        }
示例#10
0
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var appFeature = context.HttpContext.Features.Get <IAppFeature>();

            if (appFeature?.App != null && FilterDefinition.Weight > 0)
            {
                using (Profiler.Trace("CheckUsage"))
                {
                    var plan = appPlanProvider.GetPlanForApp(appFeature.App);

                    var usage = await usageTracker.GetMonthlyCallsAsync(appFeature.App.Id.ToString(), DateTime.Today);

                    if (plan.MaxApiCalls >= 0 && usage > plan.MaxApiCalls * 1.1)
                    {
                        context.Result = new StatusCodeResult(429);
                        return;
                    }
                }

                var watch = ValueStopwatch.StartNew();

                try
                {
                    await next();
                }
                finally
                {
                    var elapsedMs = watch.Stop();

                    await usageTracker.TrackAsync(appFeature.App.Id.ToString(), context.HttpContext.User.OpenIdClientId(), FilterDefinition.Weight, elapsedMs);
                }
            }
            else
            {
                await next();
            }
        }
 public Task TrackAsync(string key, string category, double weight, double elapsedMs)
 {
     return(inner.TrackAsync(key, category, weight, elapsedMs));
 }
示例#12
0
        public Task TrackAsync(DateTime date, string key, string?category, Counters counters)
        {
            Guard.NotNull(key, nameof(key));

            return(inner.TrackAsync(date, key, category, counters));
        }
示例#13
0
        public Task TrackAsync(string key, string?category, double weight, double elapsedMs)
        {
            Guard.NotNull(key);

            return(inner.TrackAsync(key, category, weight, elapsedMs));
        }