Skip to content

Commit

Permalink
CR fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
SpertsyanKM committed Sep 18, 2023
1 parent 2fa87cb commit 2a7a77c
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ extern NSString *const kEventEndpoint;
extern NSString *const kAccessDeniedError;
extern NSString *const kInternalServerError;

extern int const kMaxSimilarRequestsPerSecond;
extern NSUInteger const kMaxSimilarRequestsPerSecond;
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@
NSString * const kAccessDeniedError = @"Access denied";
NSString * const kInternalServerError = @"Internal server error";

int const kMaxSimilarRequestsPerSecond = 5;
NSUInteger const kMaxSimilarRequestsPerSecond = 5;
78 changes: 39 additions & 39 deletions Sources/Qonversion/Qonversion/Services/QNAPIClient/QNAPIClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ - (void)sendPushToken:(void (^)(BOOL success))completion {
- (void)launchRequest:(QNAPIClientDictCompletionHandler)completion {
NSDictionary *launchData = [self.requestSerializer launchData];

[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypeInit
params:launchData
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypeInit
params:launchData
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(nil, rateLimitError);
return;
Expand All @@ -152,9 +152,9 @@ - (NSURLRequest *)handlePurchase:(QONStoreKit2PurchaseModel *)purchaseInfo

NSURLRequest *request = [self.requestBuilder makePurchaseRequestWith:resultData];

[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypePurchase
params:body
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypePurchase
params:body
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(nil, rateLimitError);
return;
Expand All @@ -180,9 +180,9 @@ - (NSURLRequest *)purchaseRequestWith:(NSDictionary *)body

NSURLRequest *request = [self.requestBuilder makePurchaseRequestWith:resultData];

[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypePurchase
params:body
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypePurchase
params:body
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(nil, rateLimitError);
return;
Expand All @@ -203,9 +203,9 @@ - (void)checkTrialIntroEligibilityParamsForProducts:(NSArray<QONProduct *> *)pro

- (void)checkTrialIntroEligibilityParamsForData:(NSDictionary *)data
completion:(QNAPIClientDictCompletionHandler)completion {
[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypeEligibilityForProducts
params:data
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypeEligibilityForProducts
params:data
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(nil, rateLimitError);
return;
Expand Down Expand Up @@ -233,9 +233,9 @@ - (void)sendProperties:(NSDictionary *)properties completion:(QNAPIClientDictCom
}

- (void)getProperties:(QNAPIClientArrayCompletionHandler)completion {
[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypeGetProperties
hash:[self.userID hash]
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypeGetProperties
hash:[self.userID hash]
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(nil, rateLimitError);
return;
Expand All @@ -260,9 +260,9 @@ - (void)automationWithID:(NSString *)automationID completion:(QNAPIClientDictCom
}

- (void)userInfoRequestWithID:(NSString *)userID completion:(QNAPIClientDictCompletionHandler)completion {
[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypeUserInfo
hash:[userID hash]
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypeUserInfo
hash:[userID hash]
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(nil, rateLimitError);
return;
Expand All @@ -276,9 +276,9 @@ - (void)userInfoRequestWithID:(NSString *)userID completion:(QNAPIClientDictComp
- (void)createIdentityForUserID:(NSString *)userID anonUserID:(NSString *)anonUserID completion:(QNAPIClientDictCompletionHandler)completion {
NSDictionary *parameters = @{@"anon_id": anonUserID, @"identity_id": userID};

[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypeIdentify
params:parameters
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypeIdentify
params:parameters
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(nil, rateLimitError);
return;
Expand Down Expand Up @@ -307,9 +307,9 @@ - (void)attributionRequest:(QONAttributionProvider)provider
completion:(QNAPIClientDictCompletionHandler)completion {
NSDictionary *body = [self.requestSerializer attributionDataWithDict:data fromProvider:provider];

[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypeAttribution
params:body
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypeAttribution
params:body
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(nil, rateLimitError);
return;
Expand Down Expand Up @@ -369,9 +369,9 @@ - (void)sendCrashReport:(NSDictionary *)data completion:(QNAPIClientEmptyComplet
}

- (void)loadRemoteConfig:(QNAPIClientDictCompletionHandler)completion {
[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypeRemoteConfig
hash:[self.userID hash]
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypeRemoteConfig
hash:[self.userID hash]
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(nil, rateLimitError);
return;
Expand All @@ -384,24 +384,24 @@ - (void)loadRemoteConfig:(QNAPIClientDictCompletionHandler)completion {
}

- (void)attachUserToExperiment:(NSString *)experimentId groupId:(NSString *)groupId completion:(QNAPIClientEmptyCompletionHandler)completion {
[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypeAttachUserToExperiment
hash:[[NSString stringWithFormat:@"%@%@%@", self.userID, experimentId, groupId] hash]
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(rateLimitError);
return;
}
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypeAttachUserToExperiment
hash:[[NSString stringWithFormat:@"%@%@%@", self.userID, experimentId, groupId] hash]
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(rateLimitError);
return;
}

NSURLRequest *request = [self.requestBuilder makeAttachUserToExperimentRequest:experimentId groupId:groupId userID:self.userID];
NSURLRequest *request = [self.requestBuilder makeAttachUserToExperimentRequest:experimentId groupId:groupId userID:self.userID];

[self processRequestWithoutResponse:request completion:completion];
[self processRequestWithoutResponse:request completion:completion];
}];
}

- (void)detachUserFromExperiment:(NSString *)experimentId completion:(QNAPIClientEmptyCompletionHandler)completion {
[self.rateLimiter processWithRateLimit:QONRateLimitedRequestTypeDetachUserFromExperiment
hash:[[NSString stringWithFormat:@"%@%@", self.userID, experimentId] hash]
completion:^(NSError *rateLimitError) {
[self.rateLimiter validateRateLimit:QONRateLimitedRequestTypeDetachUserFromExperiment
hash:[[NSString stringWithFormat:@"%@%@", self.userID, experimentId] hash]
completion:^(NSError *rateLimitError) {
if (rateLimitError != nil) {
completion(rateLimitError);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ typedef NS_ENUM(NSInteger, QONRateLimitedRequestType) {

@interface QONRateLimiter : NSObject

- (instancetype _Nullable)initWithMaxRequestsPerSecond:(int)maxRequestsPerSecond;
- (instancetype _Nullable)initWithMaxRequestsPerSecond:(NSUInteger)maxRequestsPerSecond;

- (void)processWithRateLimit:(QONRateLimitedRequestType)requestType
params:(NSDictionary * _Nonnull)params
completion:(QONRateLimiterCompletionHandler _Nonnull)completion;
- (void)validateRateLimit:(QONRateLimitedRequestType)requestType
params:(NSDictionary * _Nonnull)params
completion:(QONRateLimiterCompletionHandler _Nonnull)completion;

- (void)processWithRateLimit:(QONRateLimitedRequestType)requestType
hash:(NSUInteger)hash
completion:(QONRateLimiterCompletionHandler _Nonnull)completion;
- (void)validateRateLimit:(QONRateLimitedRequestType)requestType
hash:(NSUInteger)hash
completion:(QONRateLimiterCompletionHandler _Nonnull)completion;

- (void)saveRequest:(QONRateLimitedRequestType)requestType hash:(NSUInteger)hash;

Expand Down
42 changes: 22 additions & 20 deletions Sources/Qonversion/Qonversion/Utils/QNRateLimiter/QONRateLimiter.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,17 @@
#import "QONRequest.h"
#import "QONErrors.h"

static NSInteger const msInSec = 1000;

@interface QONRateLimiter()

@property (nonatomic) int maxRequestsPerSecond;
@property (nonatomic, copy) NSMutableDictionary<NSNumber *, NSMutableArray<QONRequest *> *> *requests;
@property (nonatomic, assign) NSUInteger maxRequestsPerSecond;
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, NSMutableArray<QONRequest *> *> *requests;

@end

@implementation QONRateLimiter

- (instancetype)initWithMaxRequestsPerSecond:(int)maxRequestsPerSecond {
self = super.init;
- (instancetype)initWithMaxRequestsPerSecond:(NSUInteger)maxRequestsPerSecond {
self = [super init];
if (self) {
_maxRequestsPerSecond = maxRequestsPerSecond;
_requests = [NSMutableDictionary new];
Expand All @@ -32,16 +30,20 @@ - (instancetype)initWithMaxRequestsPerSecond:(int)maxRequestsPerSecond {
return self;
}

- (void)processWithRateLimit:(QONRateLimitedRequestType)requestType
params:(NSDictionary *)params
completion:(QONRateLimiterCompletionHandler _Nonnull)completion {
- (void)validateRateLimit:(QONRateLimitedRequestType)requestType
params:(NSDictionary *)params
completion:(QONRateLimiterCompletionHandler _Nonnull)completion {
NSUInteger hash = [self calculateHashForDictionary:params];
[self processWithRateLimit:requestType hash:hash completion:completion];
[self validateRateLimit:requestType hash:hash completion:completion];
}

- (void)processWithRateLimit:(QONRateLimitedRequestType)requestType
hash:(NSUInteger)hash
completion:(QONRateLimiterCompletionHandler)completion {
- (void)validateRateLimit:(QONRateLimitedRequestType)requestType
hash:(NSUInteger)hash
completion:(QONRateLimiterCompletionHandler)completion {
if (!completion) {
return;
}

if ([self isRateLimitExceeded:requestType hash:hash]) {
completion([QONErrors errorWithCode:QONAPIErrorRateLimitExceeded]);
} else {
Expand All @@ -51,9 +53,9 @@ - (void)processWithRateLimit:(QONRateLimitedRequestType)requestType
}

- (void)saveRequest:(QONRateLimitedRequestType)requestType hash:(NSUInteger)hash {
NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970] * 1000;
NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970];

if (self.requests[@(requestType)] == nil) {
if (!self.requests[@(requestType)]) {
self.requests[@(requestType)] = [NSMutableArray new];
}

Expand All @@ -65,11 +67,11 @@ - (BOOL)isRateLimitExceeded:(QONRateLimitedRequestType)requestType hash:(NSUInte
[self removeOutdatedRequests:requestType];

NSArray<QONRequest *> *requestsPerType = self.requests[@(requestType)];
if (requestsPerType == nil) {
if (!requestsPerType) {
return false;
}

int matchCount = 0;
NSUInteger matchCount = 0;
for (NSUInteger i = 0; i < requestsPerType.count && matchCount < self.maxRequestsPerSecond; i++) {
QONRequest *request = requestsPerType[i];
if (request.hashValue == hash) {
Expand All @@ -84,13 +86,13 @@ - (BOOL)isRateLimitExceeded:(QONRateLimitedRequestType)requestType hash:(NSUInte

- (void)removeOutdatedRequests:(QONRateLimitedRequestType)requestType {
NSArray<QONRequest *> *requestsPerType = self.requests[@(requestType)];
if (requestsPerType == nil) {
if (!requestsPerType) {
return;
}

NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970] * 1000;
NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970];
NSMutableArray *filteredRequests = [NSMutableArray new];
for (NSInteger i = requestsPerType.count - 1; i >= 0 && timestamp - requestsPerType[i].timestamp < msInSec; --i) {
for (NSInteger i = requestsPerType.count - 1; i >= 0 && timestamp - requestsPerType[i].timestamp < 1 /* sec */; --i) {
[filteredRequests insertObject:requestsPerType[i] atIndex:0];
}

Expand Down

0 comments on commit 2a7a77c

Please sign in to comment.