Skip to content

Commit 4b536ce

Browse files
authored
New files that will take over the Request class' responsiblities
1 parent 37e9152 commit 4b536ce

File tree

6 files changed

+1010
-0
lines changed

6 files changed

+1010
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// LPFileUploadManager.h
3+
// Leanplum
4+
//
5+
// Created by Mayank Sanganeria on 6/30/18.
6+
// Copyright (c) 2018 Leanplum, Inc. All rights reserved.
7+
//
8+
// Licensed to the Apache Software Foundation (ASF) under one
9+
// or more contributor license agreements. See the NOTICE file
10+
// distributed with this work for additional information
11+
// regarding copyright ownership. The ASF licenses this file
12+
// to you under the Apache License, Version 2.0 (the "License");
13+
// you may not use this file except in compliance with the License.
14+
// You may obtain a copy of the License at
15+
//
16+
// http://www.apache.org/licenses/LICENSE-2.0
17+
//
18+
// Unless required by applicable law or agreed to in writing,
19+
// software distributed under the License is distributed on an
20+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21+
// KIND, either express or implied. See the License for the
22+
// specific language governing permissions and limitations
23+
// under the License.
24+
25+
#import <Foundation/Foundation.h>
26+
#import "Leanplum.h"
27+
#import "LPNetworkFactory.h"
28+
29+
@interface LPFileUploadDownloadManager : NSObject
30+
31+
@property (nonatomic, strong) NSString *uploadUrl;
32+
@property (nonatomic, readonly) int numPendingDownloads;
33+
34+
+ (instancetype)sharedManager;
35+
- (void)sendFilesNow:(NSArray *)filenames fileData:(NSArray *)fileData;
36+
37+
- (void)downloadFile:(NSString *)path onResponse:(LPNetworkResponseBlock)responseBlock onError:(LPNetworkErrorBlock)errorBlock;
38+
- (void)onNoPendingDownloads:(LeanplumVariablesChangedBlock)noPendingDownloadsBlock;
39+
40+
@end
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
//
2+
// LPFileUploadManager.m
3+
// Leanplum
4+
//
5+
// Created by Mayank Sanganeria on 6/30/18.
6+
// Copyright (c) 2018 Leanplum, Inc. All rights reserved.
7+
//
8+
// Licensed to the Apache Software Foundation (ASF) under one
9+
// or more contributor license agreements. See the NOTICE file
10+
// distributed with this work for additional information
11+
// regarding copyright ownership. The ASF licenses this file
12+
// to you under the Apache License, Version 2.0 (the "License");
13+
// you may not use this file except in compliance with the License.
14+
// You may obtain a copy of the License at
15+
//
16+
// http://www.apache.org/licenses/LICENSE-2.0
17+
//
18+
// Unless required by applicable law or agreed to in writing,
19+
// software distributed under the License is distributed on an
20+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21+
// KIND, either express or implied. See the License for the
22+
// specific language governing permissions and limitations
23+
// under the License.
24+
25+
#import "LPFileUploadDownloadManager.h"
26+
#import "LeanplumInternal.h"
27+
#import "LPRequest.h"
28+
#import "LPRequestManager.h"
29+
#import "LPResponse.h"
30+
#import "LPFileManager.h"
31+
32+
@interface LPFileUploadDownloadManager()
33+
34+
@property (nonatomic, strong) NSMutableDictionary *fileTransferStatus;
35+
36+
@property (nonatomic, strong) NSMutableDictionary *fileUploadSize;
37+
@property (nonatomic, strong) NSMutableDictionary *fileUploadProgress;
38+
@property (nonatomic, strong) NSString *fileUploadProgressString;
39+
@property (nonatomic, strong) NSMutableDictionary *pendingUploads;
40+
@property (nonatomic, strong) NSDictionary *requestHeaders;
41+
42+
@property (nonatomic, assign) int pendingDownloads;
43+
@property (nonatomic, strong) LeanplumVariablesChangedBlock noPendingDownloadsBlock;
44+
45+
@property (nonatomic, strong) id<LPNetworkEngineProtocol> engine;
46+
47+
@end
48+
49+
50+
@implementation LPFileUploadDownloadManager
51+
52+
+ (instancetype)sharedManager {
53+
static LPFileUploadDownloadManager *sharedManager = nil;
54+
static dispatch_once_t onceToken;
55+
dispatch_once(&onceToken, ^{
56+
sharedManager = [[self alloc] init];
57+
});
58+
return sharedManager;
59+
}
60+
61+
- (id)init
62+
{
63+
self = [super init];
64+
if (self) {
65+
_fileTransferStatus = [[NSMutableDictionary alloc] init];
66+
_fileUploadSize = [NSMutableDictionary dictionary];
67+
_fileUploadProgress = [NSMutableDictionary dictionary];
68+
_pendingUploads = [NSMutableDictionary dictionary];
69+
70+
if (_engine == nil) {
71+
if (!_requestHeaders) {
72+
_requestHeaders = [[LPRequestManager sharedManager] createHeaders];
73+
}
74+
_engine = [LPNetworkFactory engineWithHostName:[LPConstantsState sharedState].apiHostName
75+
customHeaderFields:_requestHeaders];
76+
}
77+
78+
}
79+
return self;
80+
}
81+
82+
- (void)sendFilesNow:(NSArray *)filenames fileData:(NSArray *)fileData
83+
{
84+
RETURN_IF_TEST_MODE;
85+
NSMutableArray *filesToUpload = [NSMutableArray array];
86+
for (NSString *filename in filenames) {
87+
// Set state.
88+
if ([self.fileTransferStatus[filename] boolValue]) {
89+
[filesToUpload addObject:@""];
90+
} else {
91+
[filesToUpload addObject:filename];
92+
self.fileTransferStatus[filename] = @(YES);
93+
NSNumber *size = [[[NSFileManager defaultManager] attributesOfItemAtPath:filename error:nil] objectForKey:NSFileSize];
94+
self.fileUploadSize[filename] = size;
95+
self.fileUploadProgress[filename] = @0.0;
96+
}
97+
}
98+
if (filesToUpload.count == 0) {
99+
return;
100+
}
101+
102+
LPRequest *request = [LPRequest post:LP_METHOD_UPLOAD_FILE
103+
params:@{LP_PARAM_DATA: [LPJSON stringFromJSON:fileData]}];
104+
NSMutableDictionary *dict = [[LPRequestManager sharedManager] createArgsDictionaryForRequest:request];
105+
dict[LP_PARAM_COUNT] = @(filesToUpload.count);
106+
[[LPRequestManager sharedManager] attachApiKeys:dict];
107+
@synchronized (self.pendingUploads) {
108+
self.pendingUploads[filesToUpload] = dict;
109+
}
110+
[self maybeSendNextUpload];
111+
112+
NSLog(@"Leanplum: Uploading files...");
113+
}
114+
115+
- (void)printUploadProgress
116+
{
117+
NSInteger totalFiles = [self.fileUploadSize count];
118+
int sentFiles = 0;
119+
int totalBytes = 0;
120+
int sentBytes = 0;
121+
for (NSString *filename in [self.fileUploadSize allKeys]) {
122+
int fileSize = [self.fileUploadSize[filename] intValue];
123+
double fileProgress = [self.fileUploadProgress[filename] doubleValue];
124+
if (fileProgress == 1) {
125+
sentFiles++;
126+
}
127+
sentBytes += (int)(fileSize * fileProgress);
128+
totalBytes += fileSize;
129+
}
130+
NSString *progressString = [NSString stringWithFormat:@"Uploading resources. %d/%ld files completed; %@/%@ transferred.",
131+
sentFiles, (long) totalFiles,
132+
[self getSizeAsString:sentBytes], [self getSizeAsString:totalBytes]];
133+
if (![self.fileUploadProgressString isEqualToString:progressString]) {
134+
self.fileUploadProgressString = progressString;
135+
NSLog(@"Leanplum: %@", progressString);
136+
}
137+
}
138+
139+
- (void)maybeSendNextUpload
140+
{
141+
NSMutableArray *filesToUpload;
142+
NSMutableDictionary *dict;
143+
NSString *url;
144+
@synchronized (self.pendingUploads) {
145+
for (NSMutableArray *item in self.pendingUploads) {
146+
filesToUpload = item;
147+
dict = self.pendingUploads[item];
148+
break;
149+
}
150+
if (dict) {
151+
if (!self.uploadUrl) {
152+
return;
153+
}
154+
url = self.uploadUrl;
155+
self.uploadUrl = nil;
156+
[self.pendingUploads removeObjectForKey:filesToUpload];
157+
}
158+
}
159+
if (dict == nil) {
160+
return;
161+
}
162+
id<LPNetworkOperationProtocol> op = [self.engine operationWithURLString:url
163+
params:dict
164+
httpMethod:@"POST"
165+
timeoutSeconds:60];
166+
167+
int fileIndex = 0;
168+
for (NSString *filename in filesToUpload) {
169+
if (filename.length) {
170+
[op addFile:filename forKey:[NSString stringWithFormat:LP_PARAM_FILES_PATTERN, fileIndex]];
171+
}
172+
fileIndex++;
173+
}
174+
175+
// Callbacks.
176+
[op addCompletionHandler:^(id<LPNetworkOperationProtocol> operation, id json) {
177+
LP_TRY
178+
for (NSString *filename in filesToUpload) {
179+
if (filename.length) {
180+
self.fileUploadProgress[filename] = @(1.0);
181+
}
182+
}
183+
[self printUploadProgress];
184+
LP_END_TRY
185+
LP_TRY
186+
@synchronized (self.pendingUploads) {
187+
self.uploadUrl = [[LPResponse getLastResponse:json]
188+
objectForKey:LP_KEY_UPLOAD_URL];
189+
}
190+
[self maybeSendNextUpload];
191+
LP_END_TRY
192+
} errorHandler:^(id<LPNetworkOperationProtocol> operation, NSError *err) {
193+
LP_TRY
194+
for (NSString *filename in filesToUpload) {
195+
if (filename.length) {
196+
[self.fileUploadProgress setObject:@(1.0) forKey:filename];
197+
}
198+
}
199+
[self printUploadProgress];
200+
NSLog(@"Leanplum: %@", err);
201+
[self maybeSendNextUpload];
202+
LP_END_TRY
203+
}];
204+
[op onUploadProgressChanged:^(double progress) {
205+
LP_TRY
206+
for (NSString *filename in filesToUpload) {
207+
if (filename.length) {
208+
[self.fileUploadProgress setObject:@(MIN(progress, 1.0)) forKey:filename];
209+
}
210+
}
211+
[self printUploadProgress];
212+
LP_END_TRY
213+
}];
214+
215+
// Send.
216+
[self.engine enqueueOperation: op];
217+
}
218+
219+
- (NSString *)getSizeAsString:(int)size
220+
{
221+
if (size < (1 << 10)) {
222+
return [NSString stringWithFormat:@"%d B", size];
223+
} else if (size < (1 << 20)) {
224+
return [NSString stringWithFormat:@"%d KB", (size >> 10)];
225+
} else {
226+
return [NSString stringWithFormat:@"%d MB", (size >> 20)];
227+
}
228+
}
229+
230+
- (void)downloadFile:(NSString *)path onResponse:(LPNetworkResponseBlock)responseBlock onError:(LPNetworkErrorBlock)errorBlock
231+
{
232+
RETURN_IF_TEST_MODE;
233+
if ([self.fileTransferStatus[path] boolValue]) {
234+
return;
235+
}
236+
self.pendingDownloads++;
237+
NSLog(@"Leanplum: Downloading resource %@", path);
238+
self.fileTransferStatus[path] = @(YES);
239+
LPRequest *request = [LPRequest get:LP_METHOD_DOWNLOAD_FILE params:nil];
240+
NSMutableDictionary *dict = [[LPRequestManager sharedManager] createArgsDictionaryForRequest:request];
241+
dict[LP_KEY_FILENAME] = path;
242+
[[LPRequestManager sharedManager] attachApiKeys:dict];
243+
244+
// Download it directly if the argument is URL.
245+
// Otherwise continue with the api request.
246+
id<LPNetworkOperationProtocol> op;
247+
if ([path hasPrefix:@"http://"] || [path hasPrefix:@"https://"]) {
248+
op = [self.engine operationWithURLString:path];
249+
} else {
250+
op = [self.engine operationWithPath:[LPConstantsState sharedState].apiServlet
251+
params:dict
252+
httpMethod:[LPNetworkFactory fileRequestMethod]
253+
ssl:[LPConstantsState sharedState].apiSSL
254+
timeoutSeconds:[LPConstantsState sharedState]
255+
.networkTimeoutSecondsForDownloads];
256+
}
257+
258+
[op addCompletionHandler:^(id<LPNetworkOperationProtocol> operation, id json) {
259+
LP_TRY
260+
[[operation responseData] writeToFile:[LPFileManager fileRelativeToDocuments:path
261+
createMissingDirectories:YES] atomically:YES];
262+
self.pendingDownloads--;
263+
if (responseBlock != nil) {
264+
responseBlock(operation, json);
265+
}
266+
if (self.pendingDownloads == 0 && self.noPendingDownloadsBlock) {
267+
self.noPendingDownloadsBlock();
268+
}
269+
LP_END_TRY
270+
} errorHandler:^(id<LPNetworkOperationProtocol> operation, NSError *err) {
271+
LP_TRY
272+
NSLog(@"Leanplum: %@", err);
273+
self.pendingDownloads--;
274+
if (errorBlock != nil) {
275+
errorBlock(err);
276+
}
277+
if (self.pendingDownloads == 0 && self.noPendingDownloadsBlock) {
278+
self.noPendingDownloadsBlock();
279+
}
280+
LP_END_TRY
281+
}];
282+
[self.engine enqueueOperation: op];
283+
}
284+
285+
- (int)numPendingDownloads
286+
{
287+
return _pendingDownloads;
288+
}
289+
290+
- (void)onNoPendingDownloads:(LeanplumVariablesChangedBlock)noPendingDownloadsBlock
291+
{
292+
self.noPendingDownloadsBlock = noPendingDownloadsBlock;
293+
}
294+
295+
296+
@end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// LPRequest.h
3+
// Leanplum
4+
//
5+
// Created by Mayank Sanganeria on 6/30/18.
6+
// Copyright (c) 2018 Leanplum, Inc. All rights reserved.
7+
//
8+
// Licensed to the Apache Software Foundation (ASF) under one
9+
// or more contributor license agreements. See the NOTICE file
10+
// distributed with this work for additional information
11+
// regarding copyright ownership. The ASF licenses this file
12+
// to you under the Apache License, Version 2.0 (the "License");
13+
// you may not use this file except in compliance with the License.
14+
// You may obtain a copy of the License at
15+
//
16+
// http://www.apache.org/licenses/LICENSE-2.0
17+
//
18+
// Unless required by applicable law or agreed to in writing,
19+
// software distributed under the License is distributed on an
20+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21+
// KIND, either express or implied. See the License for the
22+
// specific language governing permissions and limitations
23+
// under the License.
24+
25+
#import <Foundation/Foundation.h>
26+
#import "Leanplum.h"
27+
#import "LPNetworkFactory.h"
28+
29+
@interface LPRequest : NSObject
30+
31+
@property (nonatomic, strong) NSString *apiMethod;
32+
@property (nonatomic, strong) NSDictionary *params;
33+
@property (atomic) BOOL sent;
34+
@property (nonatomic, copy) LPNetworkResponseBlock responseBlock;
35+
@property (nonatomic, copy) LPNetworkErrorBlock errorBlock;
36+
37+
+ (LPRequest *)get:(NSString *)apiMethod params:(NSDictionary *)params;
38+
+ (LPRequest *)post:(NSString *)apiMethod params:(NSDictionary *)params;
39+
40+
- (void)onResponse:(LPNetworkResponseBlock)response;
41+
- (void)onError:(LPNetworkErrorBlock)error;
42+
43+
@end

0 commit comments

Comments
 (0)