RateLimiter.h
1 /* 2 * Copyright (c) 2017 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 #import <Foundation/Foundation.h> 25 26 NS_ASSUME_NONNULL_BEGIN 27 28 @interface RateLimiter : NSObject <NSSecureCoding> 29 30 @property (readonly, nonatomic) NSDictionary* config; 31 @property (readonly, nonatomic) NSUInteger stateSize; 32 @property (readonly, nonatomic, nullable) NSString* assetType; 33 34 typedef NS_ENUM(NSInteger, RateLimiterBadness) { 35 RateLimiterBadnessClear = 0, // everything is fine, process right now 36 RateLimiterBadnessCongested, 37 RateLimiterBadnessSeverelyCongested, 38 RateLimiterBadnessGridlocked, 39 RateLimiterBadnessOverloaded, // everything is on fire, go away 40 }; 41 42 - (instancetype _Nullable)initWithConfig:(NSDictionary*)config; 43 - (instancetype _Nullable)initWithCoder:(NSCoder*)coder; 44 - (instancetype _Nullable)init NS_UNAVAILABLE; 45 46 /*! 47 * @brief Find out whether objects may be processed or must wait. 48 * @param obj The object being judged. 49 * @param time Current time. 50 * @param limitTime Assigned okay-to-process time. Nil when object may be processed immediately. 51 * @return RateLimiterBadness enum value indicating current congestion situation, or to signal 52 * 53 * judge:at: will set the limitTime object to nil in case of 0 badness. For badnesses 1-4 the time object will indicate when it is okay to send the entry. 54 * At badness 5 judge:at: has determined there is too much activity so the caller should hold off altogether. The limitTime object will indicate when 55 * this overloaded state will end. 56 */ 57 - (RateLimiterBadness)judge:(id)obj at:(NSDate*)time limitTime:(NSDate* _Nonnull __autoreleasing* _Nonnull)limitTime; 58 59 - (void)reset; 60 - (NSString*)diagnostics; 61 + (BOOL)supportsSecureCoding; 62 63 // TODO: 64 // implement config loading from MobileAsset 65 66 @end 67 68 NS_ASSUME_NONNULL_END 69 70 /* Annotated example plist 71 72 <?xml version="1.0" encoding="UTF-8"?> 73 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 74 <plist version="1.0"> 75 <dict> 76 <key>general</key> 77 <dict> 78 <!-- Total item limit --> 79 <key>maxStateSize</key> 80 <integer>250</integer> 81 <!-- Throw away items after this many seconds --> 82 <key>maxItemAge</key> 83 <integer>3600</integer> 84 <!-- Ignore everybody for this many seconds --> 85 <key>overloadDuration</key> 86 <integer>1800</integer> 87 <!-- Printable string for logs --> 88 <key>name</key> 89 <string>CKKS</string> 90 <!-- Load config stored in this MobileAsset (ignored if inited with config or plist directly) --> 91 <key>MAType</key> 92 <string></string> 93 </dict> 94 <!-- Each property you want to ratelimit on must have its own group dictionary --> 95 <key>groups</key> 96 <array> 97 <dict> 98 <!-- The first group must be for the global bucket. It behaves identically otherwise --> 99 <key>property</key> 100 <string>global</string> 101 <key>capacity</key> 102 <integer>20</integer> 103 <key>rate</key> 104 <integer>30</integer> 105 <key>badness</key> 106 <integer>1</integer> 107 </dict> 108 <dict> 109 <!-- Your object must respond to this selector that takes no arguments by returning an NSString * --> 110 <key>property</key> 111 <string>UUID</string> 112 <!-- Buckets of this type hold at most this many tokens --> 113 <key>capacity</key> 114 <integer>3</integer> 115 <!-- Tokens replenish at 1 every this many seconds --> 116 <key>rate</key> 117 <integer>600</integer> 118 <!-- Max of all empty bucket badnesses is returned to caller. See RateLimiterBadness enum --> 119 <key>badness</key> 120 <integer>3</integer> 121 </dict> 122 </array> 123 </dict> 124 </plist> 125 126 */