-
Notifications
You must be signed in to change notification settings - Fork 117
/
DBTransportDefaultClient.m
317 lines (260 loc) · 14.8 KB
/
DBTransportDefaultClient.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
///
/// Copyright (c) 2016 Dropbox, Inc. All rights reserved.
///
#import "DBTransportDefaultClient.h"
#import "DBDelegate.h"
#import "DBFILESRouteObjects.h"
#import "DBSDKConstants.h"
#import "DBStoneBase.h"
#import "DBTasksImpl.h"
#import "DBTransportBaseClient+Internal.h"
#import "DBTransportBaseHostnameConfig.h"
#import "DBTransportDefaultConfig.h"
@implementation DBTransportDefaultClient {
/// The delegate used to manage execution of all response / error code. By default, this
/// is an instance of `DBDelegate` with the main thread queue as delegate queue.
DBDelegate *_delegate;
}
@synthesize session = _session;
@synthesize secondarySession = _secondarySession;
@synthesize longpollSession = _longpollSession;
#pragma mark - Constructors
- (instancetype)initWithAccessToken:(NSString *)accessToken
tokenUid:(NSString *)tokenUid
transportConfig:(DBTransportDefaultConfig *)transportConfig {
if (self = [super initWithAccessToken:accessToken tokenUid:tokenUid transportConfig:transportConfig]) {
_delegateQueue = transportConfig.delegateQueue ?: [NSOperationQueue new];
_delegateQueue.maxConcurrentOperationCount = 1;
_delegate = [[DBDelegate alloc] initWithQueue:_delegateQueue];
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForRequest = 60.0;
NSOperationQueue *sessionDelegateQueue =
[self urlSessionDelegateQueueWithName:[NSString stringWithFormat:@"%@ NSURLSession delegate queue",
NSStringFromClass(self.class)]];
_session =
[NSURLSession sessionWithConfiguration:sessionConfig delegate:_delegate delegateQueue:sessionDelegateQueue];
_forceForegroundSession = transportConfig.forceForegroundSession ? YES : NO;
if (!_forceForegroundSession) {
NSString *backgroundId = [NSString stringWithFormat:@"%@.%@", kBackgroundSessionId, [NSUUID UUID].UUIDString];
NSURLSessionConfiguration *backgroundSessionConfig =
[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:backgroundId];
if (transportConfig.sharedContainerIdentifier) {
backgroundSessionConfig.sharedContainerIdentifier = transportConfig.sharedContainerIdentifier;
}
NSOperationQueue *secondarySessionDelegateQueue =
[self urlSessionDelegateQueueWithName:[NSString stringWithFormat:@"%@ Secondary NSURLSession delegate queue",
NSStringFromClass(self.class)]];
_secondarySession = [NSURLSession sessionWithConfiguration:backgroundSessionConfig
delegate:_delegate
delegateQueue:secondarySessionDelegateQueue];
} else {
_secondarySession = _session;
}
NSURLSessionConfiguration *longpollSessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
longpollSessionConfig.timeoutIntervalForRequest = 480.0;
NSOperationQueue *longpollSessionDelegateQueue =
[self urlSessionDelegateQueueWithName:[NSString stringWithFormat:@"%@ Longpoll NSURLSession delegate queue",
NSStringFromClass(self.class)]];
_longpollSession = [NSURLSession sessionWithConfiguration:longpollSessionConfig
delegate:_delegate
delegateQueue:longpollSessionDelegateQueue];
}
return self;
}
#pragma mark - Utility methods
- (NSOperationQueue *)urlSessionDelegateQueueWithName:(NSString *)queueName {
NSOperationQueue *sessionDelegateQueue = [[NSOperationQueue alloc] init];
sessionDelegateQueue.maxConcurrentOperationCount = 1; // [Michael Fey, 2017-05-16] From the NSURLSession
// documentation: "The queue should be a serial queue, in order
// to ensure the correct ordering of callbacks."
sessionDelegateQueue.name = queueName;
sessionDelegateQueue.qualityOfService = NSQualityOfServiceUtility;
return sessionDelegateQueue;
}
#pragma mark - RPC-style request
- (DBRpcTaskImpl *)requestRpc:(DBRoute *)route arg:(id<DBSerializable>)arg {
NSURL *requestUrl = [self urlWithRoute:route];
NSString *serializedArg = [[self class] serializeStringWithRoute:route routeArg:arg];
NSDictionary *headers = [self headersWithRouteInfo:route.attrs serializedArg:serializedArg];
// RPC request submits argument in request body
NSData *serializedArgData = [[self class] serializeDataWithRoute:route routeArg:arg];
NSURLRequest *request = [[self class] requestWithHeaders:headers url:requestUrl content:serializedArgData stream:nil];
NSURLSession *sessionToUse = _session;
// longpoll requests have a much longer timeout period than other requests
if (route.host == DBRouteHostNotify) {
sessionToUse = _longpollSession;
}
NSURLSessionDataTask *task = [sessionToUse dataTaskWithRequest:request];
DBRpcTaskImpl *rpcTask = [[DBRpcTaskImpl alloc] initWithTask:task
tokenUid:self.tokenUid
session:sessionToUse
delegate:_delegate
route:route];
[task resume];
return rpcTask;
}
#pragma mark - Upload-style request (NSURL)
- (DBUploadTaskImpl *)requestUpload:(DBRoute *)route arg:(id<DBSerializable>)arg inputUrl:(NSString *)input {
NSURL *inputUrl = [NSURL fileURLWithPath:input];
NSURL *requestUrl = [self urlWithRoute:route];
NSString *serializedArg = [[self class] serializeStringWithRoute:route routeArg:arg];
NSDictionary *headers = [self headersWithRouteInfo:route.attrs serializedArg:serializedArg];
NSURLRequest *request = [[self class] requestWithHeaders:headers url:requestUrl content:nil stream:nil];
NSURLSessionUploadTask *task = [_secondarySession uploadTaskWithRequest:request fromFile:inputUrl];
DBUploadTaskImpl *uploadTask = [[DBUploadTaskImpl alloc] initWithTask:task
tokenUid:self.tokenUid
session:_secondarySession
delegate:_delegate
route:route
inputUrl:inputUrl
inputData:nil];
[task resume];
return uploadTask;
}
#pragma mark - Upload-style request (NSData)
- (DBUploadTaskImpl *)requestUpload:(DBRoute *)route arg:(id<DBSerializable>)arg inputData:(NSData *)input {
NSURL *requestUrl = [self urlWithRoute:route];
NSString *serializedArg = [[self class] serializeStringWithRoute:route routeArg:arg];
NSDictionary *headers = [self headersWithRouteInfo:route.attrs serializedArg:serializedArg];
NSURLRequest *request = [[self class] requestWithHeaders:headers url:requestUrl content:nil stream:nil];
NSURLSessionUploadTask *task = [_session uploadTaskWithRequest:request fromData:input];
DBUploadTaskImpl *uploadTask = [[DBUploadTaskImpl alloc] initWithTask:task
tokenUid:self.tokenUid
session:_session
delegate:_delegate
route:route
inputUrl:nil
inputData:input];
[task resume];
return uploadTask;
}
#pragma mark - Upload-style request (NSInputStream)
- (DBUploadTaskImpl *)requestUpload:(DBRoute *)route arg:(id<DBSerializable>)arg inputStream:(NSInputStream *)input {
NSURL *requestUrl = [self urlWithRoute:route];
NSString *serializedArg = [[self class] serializeStringWithRoute:route routeArg:arg];
NSDictionary *headers = [self headersWithRouteInfo:route.attrs serializedArg:serializedArg];
NSURLRequest *request = [[self class] requestWithHeaders:headers url:requestUrl content:nil stream:input];
NSURLSessionUploadTask *task = [_session uploadTaskWithStreamedRequest:request];
DBUploadTaskImpl *uploadTask = [[DBUploadTaskImpl alloc] initWithTask:task
tokenUid:self.tokenUid
session:_session
delegate:_delegate
route:route
inputUrl:nil
inputData:nil];
[task resume];
return uploadTask;
}
#pragma mark - Download-style request (NSURL)
- (DBDownloadUrlTask *)requestDownload:(DBRoute *)route
arg:(id<DBSerializable>)arg
overwrite:(BOOL)overwrite
destination:(NSURL *)destination {
return [self requestDownload:route
arg:arg
overwrite:overwrite
destination:destination
byteOffsetStart:nil
byteOffsetEnd:nil];
}
- (DBDownloadUrlTask *)requestDownload:(DBRoute *)route
arg:(id<DBSerializable>)arg
overwrite:(BOOL)overwrite
destination:(NSURL *)destination
byteOffsetStart:(NSNumber *)byteOffsetStart
byteOffsetEnd:(NSNumber *)byteOffsetEnd {
NSURL *requestUrl = [self urlWithRoute:route];
NSString *serializedArg = [[self class] serializeStringWithRoute:route routeArg:arg];
NSDictionary *headers = [self headersWithRouteInfo:route.attrs
serializedArg:serializedArg
byteOffsetStart:byteOffsetStart
byteOffsetEnd:byteOffsetEnd];
NSURLRequest *request = [[self class] requestWithHeaders:headers url:requestUrl content:nil stream:nil];
NSURLSessionDownloadTask *task = [_secondarySession downloadTaskWithRequest:request];
DBDownloadUrlTaskImpl *downloadTask = [[DBDownloadUrlTaskImpl alloc] initWithTask:task
tokenUid:self.tokenUid
session:_secondarySession
delegate:_delegate
route:route
overwrite:overwrite
destination:destination];
[task resume];
return downloadTask;
}
#pragma mark - Download-style request (NSData)
- (DBDownloadDataTask *)requestDownload:(DBRoute *)route arg:(id<DBSerializable>)arg {
return [self requestDownload:route arg:arg byteOffsetStart:nil byteOffsetEnd:nil];
}
- (DBDownloadDataTask *)requestDownload:(DBRoute *)route
arg:(id<DBSerializable>)arg
byteOffsetStart:(NSNumber *)byteOffsetStart
byteOffsetEnd:(NSNumber *)byteOffsetEnd {
NSURL *requestUrl = [self urlWithRoute:route];
NSString *serializedArg = [[self class] serializeStringWithRoute:route routeArg:arg];
NSDictionary *headers = [self headersWithRouteInfo:route.attrs
serializedArg:serializedArg
byteOffsetStart:byteOffsetStart
byteOffsetEnd:byteOffsetEnd];
NSURLRequest *request = [[self class] requestWithHeaders:headers url:requestUrl content:nil stream:nil];
NSURLSessionDownloadTask *task = [_secondarySession downloadTaskWithRequest:request];
DBDownloadDataTaskImpl *downloadTask = [[DBDownloadDataTaskImpl alloc] initWithTask:task
tokenUid:self.tokenUid
session:_secondarySession
delegate:_delegate
route:route];
[task resume];
return downloadTask;
}
- (DBTransportDefaultConfig *)duplicateTransportConfigWithAsMemberId:(NSString *)asMemberId {
return [[DBTransportDefaultConfig alloc] initWithAppKey:self.appKey
appSecret:self.appSecret
userAgent:self.userAgent
asMemberId:asMemberId
delegateQueue:_delegateQueue
forceForegroundSession:_forceForegroundSession];
}
- (DBTransportDefaultConfig *)duplicateTransportConfigWithPathRoot:(DBCOMMONPathRoot *)pathRoot {
return [[DBTransportDefaultConfig alloc] initWithAppKey:self.appKey
appSecret:self.appSecret
hostnameConfig:nil
redirectURL:nil
userAgent:self.userAgent
asMemberId:self.asMemberId
pathRoot:pathRoot
additionalHeaders:nil
delegateQueue:_delegateQueue
forceForegroundSession:_forceForegroundSession
sharedContainerIdentifier:nil];
}
#pragma mark - Session accessors and mutators
- (NSURLSession *)session {
@synchronized(self) {
return _session;
}
}
- (void)setSession:(NSURLSession *)session {
@synchronized(self) {
_session = session;
}
}
- (NSURLSession *)secondarySession {
@synchronized(self) {
return _secondarySession;
}
}
- (void)setSecondarySession:(NSURLSession *)secondarySession {
@synchronized(self) {
_secondarySession = secondarySession;
}
}
- (NSURLSession *)longpollSession {
@synchronized(self) {
return _longpollSession;
}
}
- (void)setLongpollSession:(NSURLSession *)longpollSession {
@synchronized(self) {
_longpollSession = longpollSession;
}
}
@end