Skip to content

Implement downloads for iOS #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion ios/Firestack/FirestackEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ static NSString *const DATABASE_CHILD_MOVED_EVENT = @"child_moved";
static NSString *const STORAGE_UPLOAD_PROGRESS = @"upload_progress";
static NSString *const STORAGE_UPLOAD_PAUSED = @"upload_paused";
static NSString *const STORAGE_UPLOAD_RESUMED = @"upload_resumed";
static NSString *const STORAGE_DOWNLOAD_PROGRESS = @"download_progress";
static NSString *const STORAGE_DOWNLOAD_PAUSED = @"download_paused";
static NSString *const STORAGE_DOWNLOAD_RESUMED = @"download_resumed";

// Messaging
static NSString *const MESSAGING_SUBSYSTEM_EVENT = @"messaging_event";
Expand All @@ -47,4 +50,4 @@ static NSString *const MESSAGING_TOKEN_REFRESH = @"messaging_token_refresh";
static NSString *const MESSAGING_MESSAGE_RECEIVED_REMOTE = @"messaging_remote_event_received";
static NSString *const MESSAGING_MESSAGE_RECEIVED_LOCAL = @"messaging_local_event_received";

#endif
#endif
127 changes: 111 additions & 16 deletions ios/Firestack/FirestackStorage.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ @implementation FirestackStorage
[err setValue:@"Call setStorageUrl() first" forKey:@"description"];
return callback(@[err]);
}

if ([path hasPrefix:@"assets-library://"]) {
NSURL *localFile = [[NSURL alloc] initWithString:path];
PHFetchResult* assets = [PHAsset fetchAssetsWithALAssetURLs:@[localFile] options:nil];
PHAsset *asset = [assets firstObject];
[asset requestContentEditingInputWithOptions:nil
completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
NSURL *imageFile = contentEditingInput.fullSizeImageURL;

[self performUpload:urlStr
name:name
file:imageFile
Expand All @@ -70,14 +70,14 @@ @implementation FirestackStorage
} else {
NSURL *localFile = [NSURL fileURLWithPath:path];
FIRStorageMetadata *firmetadata = [[FIRStorageMetadata alloc] initWithDictionary:metadata];

[self performUpload:urlStr
name:name
file:localFile
metadata:firmetadata
callback:callback];
}

}

- (void) performUpload:(NSString *) urlStr
Expand All @@ -88,10 +88,10 @@ - (void) performUpload:(NSString *) urlStr
{
FIRStorageReference *storageRef = [[FIRStorage storage] referenceForURL:urlStr];
FIRStorageReference *uploadRef = [storageRef child:name];

FIRStorageUploadTask *uploadTask = [uploadRef putFile:imageFile
metadata:firmetadata];

// Listen for state changes, errors, and completion of the upload.
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload resumed, also fires when the upload starts
Expand All @@ -100,7 +100,7 @@ - (void) performUpload:(NSString *) urlStr
@"ref": snapshot.reference.bucket
}];
}];

[uploadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload paused
[self sendJSEvent:STORAGE_UPLOAD_PAUSED props:@{
Expand All @@ -116,17 +116,17 @@ - (void) performUpload:(NSString *) urlStr
} else {
percentComplete = 100.0 * (snapshot.progress.completedUnitCount) / (snapshot.progress.totalUnitCount);
}

[self sendJSEvent:STORAGE_UPLOAD_PROGRESS props:@{
@"eventName": STORAGE_UPLOAD_PROGRESS,
@"progress": @(percentComplete)
}];

}];

[uploadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
[uploadTask removeAllObservers];

// Upload completed successfully
FIRStorageReference *ref = snapshot.reference;
NSDictionary *props = @{
Expand All @@ -135,14 +135,14 @@ - (void) performUpload:(NSString *) urlStr
@"name": ref.name,
@"metadata": [snapshot.metadata dictionaryRepresentation]
};

callback(@[[NSNull null], props]);
}];

[uploadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
if (snapshot.error != nil) {
NSDictionary *errProps = [[NSMutableDictionary alloc] init];

switch (snapshot.error.code) {
case FIRStorageErrorCodeObjectNotFound:
// File doesn't exist
Expand All @@ -161,17 +161,112 @@ - (void) performUpload:(NSString *) urlStr
[errProps setValue:@"Unknown error" forKey:@"description"];
break;
}


callback(@[errProps]);
}}];
}

RCT_EXPORT_METHOD(downloadFile: (NSString *) urlStr
path:(NSString *) path
localFile:(NSString *) file
callback:(RCTResponseSenderBlock) callback)
{
if (urlStr == nil) {
NSError *err = [[NSError alloc] init];
[err setValue:@"Storage configuration error" forKey:@"name"];
[err setValue:@"Call setStorageUrl() first" forKey:@"description"];
return callback(@[err]);
}

FIRStorageReference *storageRef = [[FIRStorage storage] referenceForURL:urlStr];
FIRStorageReference *fileRef = [storageRef child:path];

NSURL *localFile = [NSURL fileURLWithPath:file];

FIRStorageDownloadTask *downloadTask = [fileRef writeToFile:localFile];
// Listen for state changes, errors, and completion of the download.
[downloadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload resumed, also fires when the upload starts
[self sendJSEvent:STORAGE_DOWNLOAD_RESUMED props:@{
@"eventName": STORAGE_DOWNLOAD_RESUMED,
@"ref": snapshot.reference.bucket
}];
}];

[downloadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload paused
[self sendJSEvent:STORAGE_DOWNLOAD_PAUSED props:@{
@"eventName": STORAGE_DOWNLOAD_PAUSED,
@"ref": snapshot.reference.bucket
}];
}];
[downloadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload reported progress
float percentComplete;
if (snapshot.progress.totalUnitCount == 0) {
percentComplete = 0.0;
} else {
percentComplete = 100.0 * (snapshot.progress.completedUnitCount) / (snapshot.progress.totalUnitCount);
}

[self sendJSEvent:STORAGE_DOWNLOAD_PROGRESS props:@{
@"eventName": STORAGE_DOWNLOAD_PROGRESS,
@"progress": @(percentComplete)
}];

}];

[downloadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
[downloadTask removeAllObservers];

// Upload completed successfully
FIRStorageReference *ref = snapshot.reference;
NSDictionary *props = @{
@"fullPath": ref.fullPath,
@"bucket": ref.bucket,
@"name": ref.name
};

callback(@[[NSNull null], props]);
}];

[downloadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
if (snapshot.error != nil) {
NSDictionary *errProps = [[NSMutableDictionary alloc] init];

switch (snapshot.error.code) {
case FIRStorageErrorCodeObjectNotFound:
// File doesn't exist
[errProps setValue:@"File does not exist" forKey:@"description"];
break;
case FIRStorageErrorCodeUnauthorized:
// User doesn't have permission to access file
[errProps setValue:@"You do not have permissions" forKey:@"description"];
break;
case FIRStorageErrorCodeCancelled:
// User canceled the upload
[errProps setValue:@"Download canceled" forKey:@"description"];
break;
case FIRStorageErrorCodeUnknown:
// Unknown error occurred, inspect the server response
[errProps setValue:@"Unknown error" forKey:@"description"];
break;
}

callback(@[errProps]);
}}];
}


// Not sure how to get away from this... yet
- (NSArray<NSString *> *)supportedEvents {
return @[
STORAGE_UPLOAD_PAUSED,
STORAGE_UPLOAD_RESUMED,
STORAGE_UPLOAD_PROGRESS
STORAGE_UPLOAD_PROGRESS,
STORAGE_DOWNLOAD_PAUSED,
STORAGE_DOWNLOAD_RESUMED,
STORAGE_DOWNLOAD_PROGRESS
];
}

Expand Down
32 changes: 28 additions & 4 deletions lib/modules/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,36 @@ class StorageRef extends ReferenceBase {
constructor(storage, path) {
super(storage.firestack, path);

this.storageUrl = storage.storageUrl;
this.storage = storage;
}

downloadUrl() {
const path = this.pathToString();
return promisify('downloadUrl', FirestackStorage)(this.storageUrl, path);
return promisify('downloadUrl', FirestackStorage)(this.storage.storageUrl, path);
}

/**
* Downloads a reference to the device
* @param {String} downloadPath Where to store the file
* @return {Promise}
*/
download (downloadPath, cb) {
let callback = cb;
if (!callback || typeof callback !== 'function') {
callback = (evt) => {};
}

const listeners = [];
listeners.push(this.storage._addListener('download_progress', callback));
listeners.push(this.storage._addListener('download_paused', callback));
listeners.push(this.storage._addListener('download_resumed', callback));

const path = this.pathToString();
return promisify('downloadFile', FirestackStorage)(this.storage.storageUrl, path, downloadPath)
.then((res) => {
listeners.forEach(this.storage._removeListener);
return res;
});
}
}

Expand All @@ -42,7 +66,7 @@ export class Storage extends Base {
}
return this.refs[key];
}

/**
* Upload a filepath
* @param {string} name The destination for the file
Expand Down Expand Up @@ -91,4 +115,4 @@ export class Storage extends Base {
}
}

export default Storage
export default Storage