| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- /*
- * Copyright 2020 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h"
- static const NSTimeInterval k24Hours = 24 * 60 * 60;
- static const NSTimeInterval k30Minutes = 30 * 60;
- /** The class represents `FIRInstallationsBackoffController` state required to calculate next
- allowed request time. The properties of the class are intentionally immutable because changing them
- separately leads to an inconsistent state. */
- @interface FIRInstallationsBackoffEventData : NSObject
- @property(nonatomic, readonly) FIRInstallationsBackoffEvent eventType;
- @property(nonatomic, readonly) NSDate *lastEventDate;
- @property(nonatomic, readonly) NSInteger eventCount;
- @property(nonatomic, readonly) NSTimeInterval backoffTimeInterval;
- @end
- @implementation FIRInstallationsBackoffEventData
- - (instancetype)initWithEvent:(FIRInstallationsBackoffEvent)eventType
- lastEventDate:(NSDate *)lastEventDate
- eventCount:(NSInteger)eventCount {
- self = [super init];
- if (self) {
- _eventType = eventType;
- _lastEventDate = lastEventDate;
- _eventCount = eventCount;
- _backoffTimeInterval = [[self class] backoffTimeIntervalWithEvent:eventType
- eventCount:eventCount];
- }
- return self;
- }
- + (NSTimeInterval)backoffTimeIntervalWithEvent:(FIRInstallationsBackoffEvent)eventType
- eventCount:(NSInteger)eventCount {
- switch (eventType) {
- case FIRInstallationsBackoffEventSuccess:
- return 0;
- break;
- case FIRInstallationsBackoffEventRecoverableFailure:
- return [self recoverableErrorBackoffTimeForAttemptNumber:eventCount];
- break;
- case FIRInstallationsBackoffEventUnrecoverableFailure:
- return k24Hours;
- break;
- }
- }
- + (NSTimeInterval)recoverableErrorBackoffTimeForAttemptNumber:(NSInteger)attemptNumber {
- NSTimeInterval exponentialInterval = pow(2, attemptNumber) + [self randomMilliseconds];
- return MIN(exponentialInterval, k30Minutes);
- }
- + (NSTimeInterval)randomMilliseconds {
- int32_t random_millis = ABS(arc4random() % 1000);
- return (double)random_millis * 0.001;
- }
- @end
- @interface FIRInstallationsBackoffController ()
- @property(nonatomic, readonly) FIRCurrentDateProvider currentDateProvider;
- @property(nonatomic, nullable) FIRInstallationsBackoffEventData *lastEventData;
- @end
- @implementation FIRInstallationsBackoffController
- - (instancetype)init {
- return [self initWithCurrentDateProvider:FIRRealCurrentDateProvider()];
- }
- - (instancetype)initWithCurrentDateProvider:(FIRCurrentDateProvider)currentDateProvider {
- self = [super init];
- if (self) {
- _currentDateProvider = [currentDateProvider copy];
- }
- return self;
- }
- - (BOOL)isNextRequestAllowed {
- @synchronized(self) {
- if (self.lastEventData == nil) {
- return YES;
- }
- NSTimeInterval timeSinceLastEvent =
- [self.currentDateProvider() timeIntervalSinceDate:self.lastEventData.lastEventDate];
- return timeSinceLastEvent >= self.lastEventData.backoffTimeInterval;
- }
- }
- - (void)registerEvent:(FIRInstallationsBackoffEvent)event {
- @synchronized(self) {
- // Event of the same type as was registered before.
- if (self.lastEventData && self.lastEventData.eventType == event) {
- self.lastEventData = [[FIRInstallationsBackoffEventData alloc]
- initWithEvent:event
- lastEventDate:self.currentDateProvider()
- eventCount:self.lastEventData.eventCount + 1];
- } else { // A different event.
- self.lastEventData =
- [[FIRInstallationsBackoffEventData alloc] initWithEvent:event
- lastEventDate:self.currentDateProvider()
- eventCount:1];
- }
- }
- }
- @end
|