Skip to content

Commit 2e21ca6

Browse files
authored
Custom File Upload Controller (#1114)
* Added pluggable PFFileUploadController protocol to PFFile. * Added PFFile’s filename to protocol. * Added missing implementation file for PFFileUploadResult. Added new files to other targets. * Converted to specifying the PFFileUploadController globally on Parse.configuration. Created a default PFFileUploadController policy for parse-server REST upload rather than hard coding it in PFFileController. * Backed out implementing standard upload as an implementation of PFFileUploadController; it exposed too many internals. * Added missing private variable declaration. * Changed copy to strong for global config reference. * Added missing equality and copy semantics in ParseClientConfiguration. * Marked PFFileUploadController.h as public in project. * Marked PFFileUploadResult.h as public in project. * Added PFFileUploadController.h and PFFileUploadResult.h to the global header file. Changed ref to PFFileUploadController.h to a forward declaration.
1 parent e194a9d commit 2e21ca6

File tree

9 files changed

+169
-15
lines changed

9 files changed

+169
-15
lines changed

Parse.xcodeproj/project.pbxproj

Lines changed: 48 additions & 0 deletions
Large diffs are not rendered by default.

Parse/Internal/File/Controller/PFFileController.m

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#import "PFMacros.h"
2525
#import "PFRESTFileCommand.h"
2626
#import "PFErrorUtilities.h"
27+
#import "Parse.h"
28+
#import "PFFileUploadController.h"
2729

2830
static NSString *const PFFileControllerCacheDirectoryName_ = @"PFFileCache";
2931

@@ -218,21 +220,41 @@ - (NSString *)_temporaryFileDownloadPathForFileState:(PFFileState *)fileState {
218220
return [BFTask taskWithError:error];
219221
}
220222

221-
PFRESTFileCommand *command = [PFRESTFileCommand uploadCommandForFileWithName:fileState.name sessionToken:sessionToken];
222-
@weakify(self);
223-
return [[self.dataSource.commandRunner runFileUploadCommandAsync:command
224-
withContentType:fileState.mimeType
225-
contentSourceFilePath:sourceFilePath
226-
options:PFCommandRunningOptionRetryIfFailed
227-
cancellationToken:cancellationToken
228-
progressBlock:progressBlock] continueWithSuccessBlock:^id(BFTask<PFCommandResult *> *task) {
229-
@strongify(self);
230-
PFCommandResult *result = task.result;
231-
PFFileState *fileState = [[PFFileState alloc] initWithName:result.result[@"name"]
232-
urlString:result.result[@"url"]
233-
mimeType:nil];
234-
return [[self _cacheFileAsyncWithState:fileState atPath:sourceFilePath] continueWithSuccessResult:fileState];
235-
}];
223+
224+
id<PFFileUploadController> customFileUploadController = Parse.currentConfiguration.fileUploadController;
225+
if (customFileUploadController) {
226+
@weakify(self);
227+
return [[customFileUploadController uploadSourceFilePath:sourceFilePath
228+
fileName:fileState.name
229+
mimeType:fileState.mimeType
230+
sessionToken:sessionToken
231+
cancellationToken:cancellationToken
232+
progressBlock:progressBlock]
233+
continueWithSuccessBlock:^id(BFTask<PFFileUploadResult *> *task) {
234+
@strongify(self);
235+
PFFileUploadResult *result = task.result;
236+
PFFileState *fileState = [[PFFileState alloc] initWithName:result.name
237+
urlString:result.url
238+
mimeType:nil];
239+
return [[self _cacheFileAsyncWithState:fileState atPath:sourceFilePath] continueWithSuccessResult:fileState];
240+
}];
241+
} else {
242+
PFRESTFileCommand *command = [PFRESTFileCommand uploadCommandForFileWithName:fileState.name sessionToken:sessionToken];
243+
@weakify(self);
244+
return [[self.dataSource.commandRunner runFileUploadCommandAsync:command
245+
withContentType:fileState.mimeType
246+
contentSourceFilePath:sourceFilePath
247+
options:PFCommandRunningOptionRetryIfFailed
248+
cancellationToken:cancellationToken
249+
progressBlock:progressBlock] continueWithSuccessBlock:^id(BFTask<PFCommandResult *> *task) {
250+
@strongify(self);
251+
PFCommandResult *result = task.result;
252+
PFFileState *fileState = [[PFFileState alloc] initWithName:result.result[@"name"]
253+
urlString:result.result[@"url"]
254+
mimeType:nil];
255+
return [[self _cacheFileAsyncWithState:fileState atPath:sourceFilePath] continueWithSuccessResult:fileState];
256+
}];
257+
}
236258
}
237259

238260
///--------------------------------------
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//
2+
// PFFileUploadResult.m
3+
// Parse
4+
//
5+
// Created by Ken Cooper on 2/21/17.
6+
// Copyright © 2017 Parse Inc. All rights reserved.
7+
//
8+
9+
#import "PFFileUploadResult.h"
10+
11+
@implementation PFFileUploadResult
12+
13+
@end

Parse/Internal/ParseClientConfiguration_Private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ extern NSString *const _ParseDefaultServerURLString;
1717

1818
@property (nullable, nonatomic, copy, readwrite) NSString *applicationId;
1919
@property (nullable, nonatomic, copy, readwrite) NSString *clientKey;
20+
@property (nullable, nonatomic, strong, readwrite) id<PFFileUploadController> fileUploadController;
2021

2122
@property (nonatomic, copy, readwrite) NSString *server;
2223

Parse/PFFileUploadController.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// PFUploadController.h
3+
// Parse
4+
//
5+
// Created by Ken Cooper on 2/20/17.
6+
// Copyright © 2017 Parse Inc. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
#import <Bolts/BFTask.h>
11+
12+
/**
13+
A policy interface for overriding the default upload behavior of uploading a PFFile
14+
to application's parse server. Allows for direct uploads to other file storage
15+
providers.
16+
*/
17+
@protocol PFFileUploadController <NSObject>
18+
19+
/**
20+
Uploads a file asynchronously from file path for a given file state.
21+
22+
@param sourceFilePath Path to the file to upload.
23+
@param fileName The PFFile's fileName.
24+
@param mimeType The PFFile's mime type.
25+
@param sessionToken The current users's session token.
26+
@param cancellationToken Cancellation token.
27+
@param progressBlock Progress block to call (optional).
28+
29+
@return `BFTask` with a success result set to `PFFileUploadResult` containing the url and name of the uploaded file.
30+
*/
31+
-(BFTask<PFFileUploadResult *> * _Nonnull)uploadSourceFilePath:(NSString * _Nonnull)sourceFilePath
32+
fileName:(NSString * _Nullable)fileName
33+
mimeType:(NSString * _Nullable)mimeType
34+
sessionToken:(NSString * _Nonnull)sessionToken
35+
cancellationToken:(BFCancellationToken * _Nonnull)cancellationToken
36+
progressBlock:(PFProgressBlock _Nonnull)progressBlock;
37+
@end

Parse/PFFileUploadResult.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// PFFileUploadResult.h
3+
// Parse
4+
//
5+
// Created by Ken Cooper on 2/21/17.
6+
// Copyright © 2017 Parse Inc. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
/**
12+
Response provided by a custom `PFFileUploadController`.
13+
*/
14+
@interface PFFileUploadResult : NSObject
15+
@property (strong, nonatomic) NSString *url;
16+
@property (strong, nonatomic) NSString *name;
17+
@end

Parse/Parse.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
#import <Parse/PFUser+Synchronous.h>
4040
#import <Parse/PFUser+Deprecated.h>
4141
#import <Parse/PFUserAuthenticationDelegate.h>
42+
#import <Parse/PFFileUploadResult.h>
43+
#import <Parse/PFFileUploadController.h>
4244

4345
#if TARGET_OS_IOS
4446

Parse/ParseClientConfiguration.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#import <Parse/PFConstants.h>
1313

14+
@protocol PFFileUploadController;
15+
1416
NS_ASSUME_NONNULL_BEGIN
1517

1618
/**
@@ -49,6 +51,11 @@ NS_ASSUME_NONNULL_BEGIN
4951
*/
5052
@property (nonatomic, copy) NSString *server;
5153

54+
/**
55+
Sets a custom file upload controller that uploads PFFiles using its own policy.
56+
*/
57+
@property (nonatomic, strong, readwrite, nullable) id<PFFileUploadController> fileUploadController;
58+
5259
///--------------------------------------
5360
#pragma mark - Enabling Local Datastore
5461
///--------------------------------------
@@ -120,6 +127,11 @@ NS_ASSUME_NONNULL_BEGIN
120127
*/
121128
@property (nonatomic, copy, readonly) NSString *server;
122129

130+
/**
131+
The custom upload controller that synchronously uploads PFFiles using its own policy.
132+
*/
133+
@property (nonatomic, strong, readonly, nullable) id<PFFileUploadController> fileUploadController;
134+
123135
///--------------------------------------
124136
#pragma mark - Enabling Local Datastore
125137
///--------------------------------------

Parse/ParseClientConfiguration.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ - (BOOL)isEqual:(id)object {
112112
return ([PFObjectUtilities isObject:self.applicationId equalToObject:other.applicationId] &&
113113
[PFObjectUtilities isObject:self.clientKey equalToObject:other.clientKey] &&
114114
[self.server isEqualToString:other.server] &&
115+
self.fileUploadController == other.fileUploadController &&
115116
self.localDatastoreEnabled == other.localDatastoreEnabled &&
116117
[PFObjectUtilities isObject:self.applicationGroupIdentifier equalToObject:other.applicationGroupIdentifier] &&
117118
[PFObjectUtilities isObject:self.containingApplicationBundleIdentifier equalToObject:other.containingApplicationBundleIdentifier] &&
@@ -128,6 +129,7 @@ - (instancetype)copyWithZone:(NSZone *)zone {
128129
configuration->_applicationId = [self->_applicationId copy];
129130
configuration->_clientKey = [self->_clientKey copy];
130131
configuration->_server = [self.server copy];
132+
configuration->_fileUploadController = self->_fileUploadController;
131133
configuration->_localDatastoreEnabled = self->_localDatastoreEnabled;
132134
configuration->_applicationGroupIdentifier = [self->_applicationGroupIdentifier copy];
133135
configuration->_containingApplicationBundleIdentifier = [self->_containingApplicationBundleIdentifier copy];

0 commit comments

Comments
 (0)