Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2019 Google
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h"
16
 
17
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h"
18
 
19
static const float FIRCLSNetworkMinimumRetryJitter = 0.90f;
20
static const float FIRCLSNetworkMaximumRetryJitter = 1.10f;
21
const NSUInteger FIRCLSNetworkMaximumRetryCount = 10;
22
 
23
@interface FIRCLSFABNetworkClient () <NSURLSessionDelegate, NSURLSessionTaskDelegate>
24
 
25
@property(nonatomic, strong, readonly) NSURLSession *session;
26
 
27
@end
28
 
29
@implementation FIRCLSFABNetworkClient
30
 
31
- (instancetype)init {
32
  return [self initWithQueue:nil];
33
}
34
 
35
- (instancetype)initWithQueue:(nullable NSOperationQueue *)operationQueue {
36
  NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
37
  return [self initWithSessionConfiguration:config queue:operationQueue];
38
}
39
 
40
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)config
41
                                       queue:(nullable NSOperationQueue *)operationQueue {
42
  self = [super init];
43
  if (!self) {
44
    return nil;
45
  }
46
 
47
  _session = [NSURLSession sessionWithConfiguration:config
48
                                           delegate:self
49
                                      delegateQueue:operationQueue];
50
 
51
  if (!_session) {
52
    return nil;
53
  }
54
 
55
  return self;
56
}
57
 
58
- (void)dealloc {
59
  [_session finishTasksAndInvalidate];
60
}
61
 
62
#pragma mark - Delay Handling
63
- (double)randomDoubleWithMin:(double)min max:(double)max {
64
  return min + ((max - min) * drand48());
65
}
66
 
67
- (double)generateRandomJitter {
68
  return [self randomDoubleWithMin:FIRCLSNetworkMinimumRetryJitter
69
                               max:FIRCLSNetworkMaximumRetryJitter];
70
}
71
 
72
- (NSTimeInterval)computeDelayForResponse:(NSURLResponse *)response
73
                           withRetryCount:(NSUInteger)count {
74
  NSTimeInterval initialValue = [FIRCLSNetworkResponseHandler retryValueForResponse:response];
75
 
76
  // make sure count is > 0
77
  count = MAX(count, 1);
78
  // make sure initialValue is >2 for exponential backoff to work reasonably with low count numbers
79
  initialValue = MAX(initialValue, 2.0);
80
 
81
  const double jitter = [self generateRandomJitter];
82
 
83
  return pow(initialValue, count) * jitter;  // exponential backoff
84
}
85
 
86
- (void)runAfterRetryValueFromResponse:(NSURLResponse *)response
87
                              attempts:(NSUInteger)count
88
                               onQueue:(dispatch_queue_t)queue
89
                                 block:(void (^)(void))block {
90
  const NSTimeInterval delay = [self computeDelayForResponse:response withRetryCount:count];
91
 
92
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(delay * NSEC_PER_SEC)), queue, block);
93
}
94
 
95
- (void)runAfterRetryValueFromResponse:(NSURLResponse *)response
96
                              attempts:(NSUInteger)count
97
                                 block:(void (^)(void))block {
98
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
99
 
100
  [self runAfterRetryValueFromResponse:response attempts:count onQueue:queue block:block];
101
}
102
 
103
#pragma mark - Tasks
104
 
105
- (void)startDataTaskWithRequest:(NSURLRequest *)request
106
                      retryLimit:(NSUInteger)retryLimit
107
                           tries:(NSUInteger)tries
108
               completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler {
109
  NSURLSessionTask *task = [self.session
110
      dataTaskWithRequest:request
111
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *taskError) {
112
          [FIRCLSNetworkResponseHandler
113
              handleCompletedResponse:response
114
                   forOriginalRequest:request
115
                                error:taskError
116
                                block:^(BOOL retry, NSError *error) {
117
                                  if (!retry) {
118
                                    completionHandler(data, response, error);
119
                                    return;
120
                                  }
121
 
122
                                  if (tries >= retryLimit) {
123
                                    NSDictionary *userInfo = @{
124
                                      @"retryLimit" : @(retryLimit),
125
                                      NSURLErrorFailingURLStringErrorKey : request.URL
126
                                    };
127
                                    completionHandler(
128
                                        nil, nil,
129
                                        [NSError
130
                                            errorWithDomain:FIRCLSNetworkErrorDomain
131
                                                       code:FIRCLSNetworkErrorMaximumAttemptsReached
132
                                                   userInfo:userInfo]);
133
                                    return;
134
                                  }
135
 
136
                                  [self
137
                                      runAfterRetryValueFromResponse:response
138
                                                            attempts:tries
139
                                                               block:^{
140
                                                                 [self
141
                                                                     startDataTaskWithRequest:
142
                                                                         request
143
                                                                                   retryLimit:
144
                                                                                       retryLimit
145
                                                                                        tries:
146
                                                                                            (tries +
147
                                                                                             1)
148
                                                                            completionHandler:
149
                                                                                completionHandler];
150
                                                               }];
151
                                }];
152
        }];
153
 
154
  [task resume];
155
 
156
  if (!task) {
157
    completionHandler(nil, nil,
158
                      [NSError errorWithDomain:FIRCLSNetworkErrorDomain
159
                                          code:FIRCLSNetworkErrorFailedToStartOperation
160
                                      userInfo:nil]);
161
  }
162
}
163
 
164
- (void)startDataTaskWithRequest:(NSURLRequest *)request
165
                      retryLimit:(NSUInteger)retryLimit
166
               completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler {
167
  [self startDataTaskWithRequest:request
168
                      retryLimit:retryLimit
169
                           tries:0
170
               completionHandler:completionHandler];
171
}
172
 
173
- (void)startDataTaskWithRequest:(NSURLRequest *)request
174
               completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler {
175
  [self startDataTaskWithRequest:request
176
                      retryLimit:FIRCLSNetworkMaximumRetryCount
177
               completionHandler:completionHandler];
178
}
179
 
180
- (void)startDownloadTaskWithRequest:(NSURLRequest *)request
181
                          retryLimit:(NSUInteger)retryLimit
182
                               tries:(NSUInteger)tries
183
                   completionHandler:
184
                       (FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler {
185
  NSURLSessionTask *task = [self.session
186
      downloadTaskWithRequest:request
187
            completionHandler:^(NSURL *location, NSURLResponse *response, NSError *taskError) {
188
              [FIRCLSNetworkResponseHandler
189
                  handleCompletedResponse:response
190
                       forOriginalRequest:request
191
                                    error:taskError
192
                                    block:^(BOOL retry, NSError *error) {
193
                                      if (!retry) {
194
                                        completionHandler(location, response, error);
195
                                        return;
196
                                      }
197
 
198
                                      if (tries >= retryLimit) {
199
                                        NSDictionary *userInfo = @{
200
                                          @"retryLimit" : @(retryLimit),
201
                                          NSURLErrorFailingURLStringErrorKey : request.URL
202
                                        };
203
                                        completionHandler(
204
                                            nil, nil,
205
                                            [NSError
206
                                                errorWithDomain:FIRCLSNetworkErrorDomain
207
                                                           code:
208
                                                               FIRCLSNetworkErrorMaximumAttemptsReached
209
                                                       userInfo:userInfo]);
210
                                        return;
211
                                      }
212
 
213
                                      [self
214
                                          runAfterRetryValueFromResponse:response
215
                                                                attempts:tries
216
                                                                   block:^{
217
                                                                     [self
218
                                                                         startDownloadTaskWithRequest:
219
                                                                             request
220
                                                                                           retryLimit:
221
                                                                                               retryLimit
222
                                                                                                tries:
223
                                                                                                    (tries +
224
                                                                                                     1)
225
                                                                                    completionHandler:
226
                                                                                        completionHandler];
227
                                                                   }];
228
                                    }];
229
            }];
230
 
231
  [task resume];
232
 
233
  if (!task) {
234
    completionHandler(nil, nil,
235
                      [NSError errorWithDomain:FIRCLSNetworkErrorDomain
236
                                          code:FIRCLSNetworkErrorFailedToStartOperation
237
                                      userInfo:nil]);
238
  }
239
}
240
 
241
- (void)startDownloadTaskWithRequest:(NSURLRequest *)request
242
                          retryLimit:(NSUInteger)retryLimit
243
                   completionHandler:
244
                       (FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler {
245
  [self startDownloadTaskWithRequest:request
246
                          retryLimit:retryLimit
247
                               tries:0
248
                   completionHandler:completionHandler];
249
}
250
 
251
- (void)startDownloadTaskWithRequest:(NSURLRequest *)request
252
                   completionHandler:
253
                       (FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler {
254
  [self startDownloadTaskWithRequest:request
255
                          retryLimit:FIRCLSNetworkMaximumRetryCount
256
                   completionHandler:completionHandler];
257
}
258
 
259
- (void)invalidateAndCancel {
260
  [self.session invalidateAndCancel];
261
}
262
 
263
#pragma mark - NSURLSession Delegate
264
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error {
265
}
266
 
267
@end