Added hammock project to debug streaming issues
[pithos-ms-client] / trunk / hammock / src / net35 / Hammock / Tasks / RateLimitingRule.cs
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 }