Statistics
| Branch: | Revision:

root / trunk / hammock / src / net35 / Hammock / Tasks / RateLimitingRule.cs @ 0eea575a

History | View | Annotate | Download (2.9 kB)

1
using System;
2

    
3
namespace Hammock.Tasks
4
{
5
#if !SILVERLIGHT
6
    [Serializable]
7
#endif
8
    public class RateLimitingRule<T> : IRateLimitingRule<T>
9
    {
10
        private readonly RateLimitType _rateLimitType;
11

    
12
        public RateLimitingRule(Predicate<T> rateLimitIf)
13
        {
14
            _rateLimitType = RateLimitType.ByPredicate;
15
            RateLimitIf = rateLimitIf;
16
        }
17

    
18
        public RateLimitingRule(double percentOfTotal)
19
        {
20
            _rateLimitType = RateLimitType.ByPercent;
21
            LimitToPercentOfTotal = percentOfTotal;
22
        }
23

    
24
        public RateLimitingRule(Func<T> getRateLimitStatus, Predicate<T> rateLimitIf)
25
        {
26
            _rateLimitType = RateLimitType.ByPredicate;
27
            GetRateLimitStatus = getRateLimitStatus;
28
            RateLimitIf = rateLimitIf;
29
        }
30

    
31
        public RateLimitingRule(Func<T> getRateLimitStatus, double percentOfTotal)
32
        {
33
            _rateLimitType = RateLimitType.ByPercent;
34
            GetRateLimitStatus = getRateLimitStatus;
35
            LimitToPercentOfTotal = percentOfTotal;
36
        }
37

    
38
        #region IRateLimitingRule Members
39

    
40
        public virtual double? LimitToPercentOfTotal { get; private set; }
41
        public virtual RateLimitType RateLimitType
42
        {
43
            get { return _rateLimitType; }
44
        }
45

    
46
        public Func<T> GetRateLimitStatus { get; set; }
47
        public Predicate<T> RateLimitIf { get; private set; }
48

    
49
        #endregion
50

    
51
        public bool ShouldSkipForRateLimiting()
52
        {
53
            // [JD]: Only pre-skip via predicate; percentage based adjusts rate after the call
54
            if (RateLimitType != RateLimitType.ByPredicate)
55
            {
56
                return false;
57
            }
58

    
59
            if (RateLimitIf == null)
60
            {
61
                throw new InvalidOperationException("Rule is set to use predicate, but no predicate is defined.");
62
            }
63

    
64
            var status = default(T);
65
            if (GetRateLimitStatus != null)
66
            {
67
                status = GetRateLimitStatus();
68
            }
69
            return !RateLimitIf(status);
70
        }
71

    
72
        public TimeSpan? CalculateNewInterval()
73
        {
74
            if (RateLimitType != RateLimitType.ByPercent)
75
            {
76
                return null;
77
            }
78

    
79
            if (!LimitToPercentOfTotal.HasValue)
80
            {
81
                return null;
82
            }
83
            var currentRateLimit = (IRateLimitStatus)GetRateLimitStatus();
84
            if (currentRateLimit.RemainingUses == 0)
85
            {
86
                return currentRateLimit.NextReset - DateTime.Now;
87
            }
88
            var secondsUntilNextReset = (currentRateLimit.NextReset - DateTime.Now).TotalSeconds;
89
            var desiredRetriesBeforeReset = currentRateLimit.RemainingUses * LimitToPercentOfTotal.Value;
90
            var desiredInterval = (int)Math.Floor(secondsUntilNextReset / desiredRetriesBeforeReset);
91
            return new TimeSpan(0, 0, 0, desiredInterval);
92
        }
93
    }
94
}