[ios][storage] switch to native promises and implemented web error codes
This commit is contained in:
parent
b3b74d50da
commit
e23302fb24
|
@ -8,163 +8,234 @@
|
|||
RCT_EXPORT_MODULE(RNFirebaseStorage);
|
||||
|
||||
// Run on a different thread
|
||||
- (dispatch_queue_t)methodQueue
|
||||
{
|
||||
return dispatch_queue_create("com.invertase.firebase.storage", DISPATCH_QUEUE_SERIAL);
|
||||
- (dispatch_queue_t)methodQueue {
|
||||
return dispatch_queue_create("com.invertase.firebase.storage", DISPATCH_QUEUE_SERIAL);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(delete: (NSString *) path
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
/**
|
||||
Reject a promise with a storage exception
|
||||
|
||||
@param reject RCTPromiseRejectBlock
|
||||
@param error NSError
|
||||
*/
|
||||
- (void) promiseRejectStorageException:(RCTPromiseRejectBlock) reject error:(NSError *)error {
|
||||
NSString *code = @"storage/unknown";
|
||||
NSString *message = [error localizedDescription];
|
||||
|
||||
switch (error.code) {
|
||||
case FIRStorageErrorCodeUnknown:
|
||||
code = @"storage/unknown";
|
||||
message = @"An unknown error has occurred.";
|
||||
break;
|
||||
case FIRStorageErrorCodeObjectNotFound:
|
||||
code = @"storage/object-not-found";
|
||||
message = @"No object exists at the desired reference.";
|
||||
break;
|
||||
case FIRStorageErrorCodeBucketNotFound:
|
||||
code = @"storage/bucket-not-found";
|
||||
message = @"No bucket is configured for Firebase Storage.";
|
||||
break;
|
||||
case FIRStorageErrorCodeProjectNotFound:
|
||||
code = @"storage/project-not-found";
|
||||
message = @"No project is configured for Firebase Storage.";
|
||||
break;
|
||||
case FIRStorageErrorCodeQuotaExceeded:
|
||||
code = @"storage/quota-exceeded";
|
||||
message = @"Quota on your Firebase Storage bucket has been exceeded.";
|
||||
break;
|
||||
case FIRStorageErrorCodeUnauthenticated:
|
||||
code = @"storage/unauthenticated";
|
||||
message = @"User is unauthenticated. Authenticate and try again.";
|
||||
break;
|
||||
case FIRStorageErrorCodeUnauthorized:
|
||||
code = @"storage/unauthorized";
|
||||
message = @"User is not authorized to perform the desired action.";
|
||||
break;
|
||||
case FIRStorageErrorCodeRetryLimitExceeded:
|
||||
code = @"storage/retry-limit-exceeded";
|
||||
message = @"The maximum time limit on an operation (upload, download, delete, etc.) has been exceeded.";
|
||||
break;
|
||||
case FIRStorageErrorCodeNonMatchingChecksum:
|
||||
code = @"storage/non-matching-checksum";
|
||||
message = @"File on the client does not match the checksum of the file received by the server.";
|
||||
break;
|
||||
case FIRStorageErrorCodeDownloadSizeExceeded:
|
||||
code = @"storage/download-size-exceeded";
|
||||
message = @"Size of the downloaded file exceeds the amount of memory allocated for the download.";
|
||||
break;
|
||||
case FIRStorageErrorCodeCancelled:
|
||||
code = @"storage/cancelled";
|
||||
message = @"User cancelled the operation.";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
reject(code, message, error);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
delete
|
||||
|
||||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#delete
|
||||
@param NSString path
|
||||
*/
|
||||
RCT_EXPORT_METHOD(delete: (NSString *) path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
||||
FIRStorageReference *fileRef = [self getReference:path];
|
||||
|
||||
[fileRef deleteWithCompletion:^(NSError * _Nullable error) {
|
||||
if (error == nil) {
|
||||
NSDictionary *resp = @{
|
||||
@"status": @"success",
|
||||
@"path": path
|
||||
};
|
||||
callback(@[[NSNull null], resp]);
|
||||
if (error != nil) {
|
||||
[self promiseRejectStorageException:reject error: error];
|
||||
} else {
|
||||
NSDictionary *evt = @{
|
||||
@"status": @"error",
|
||||
@"path": path,
|
||||
@"message": [error debugDescription]
|
||||
};
|
||||
callback(@[evt]);
|
||||
resolve([NSNull null]);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(getDownloadURL: (NSString *) path
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
/**
|
||||
getDownloadURL
|
||||
|
||||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getDownloadURL
|
||||
@param NSString path
|
||||
*/
|
||||
RCT_EXPORT_METHOD(getDownloadURL: (NSString *) path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
||||
FIRStorageReference *fileRef = [self getReference:path];
|
||||
|
||||
[fileRef downloadURLWithCompletion:^(NSURL * _Nullable URL, NSError * _Nullable error) {
|
||||
if (error != nil) {
|
||||
NSDictionary *evt = @{
|
||||
@"status": @"error",
|
||||
@"path": path,
|
||||
@"message": [error debugDescription]
|
||||
};
|
||||
callback(@[evt]);
|
||||
[self promiseRejectStorageException:reject error: error];
|
||||
} else {
|
||||
callback(@[[NSNull null], [URL absoluteString]]);
|
||||
resolve([URL absoluteString]);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(getMetadata: (NSString *) path
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
/**
|
||||
getMetaData
|
||||
|
||||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getMetaData
|
||||
@param NSString path
|
||||
*/
|
||||
RCT_EXPORT_METHOD(getMetaData: (NSString *) path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
||||
FIRStorageReference *fileRef = [self getReference:path];
|
||||
|
||||
[fileRef metadataWithCompletion:^(FIRStorageMetadata * _Nullable metadata, NSError * _Nullable error) {
|
||||
if (error != nil) {
|
||||
NSDictionary *evt = @{
|
||||
@"status": @"error",
|
||||
@"path": path,
|
||||
@"message": [error debugDescription]
|
||||
};
|
||||
callback(@[evt]);
|
||||
[self promiseRejectStorageException:reject error: error];
|
||||
} else {
|
||||
NSDictionary *resp = [metadata dictionaryRepresentation];
|
||||
callback(@[[NSNull null], resp]);
|
||||
resolve([metadata dictionaryRepresentation]);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(updateMetadata: (NSString *) path
|
||||
metadata:(NSDictionary *) metadata
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
/**
|
||||
updateMetadata
|
||||
|
||||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#updateMetadata
|
||||
@param NSString path
|
||||
@param NSDictionary metadata
|
||||
*/
|
||||
RCT_EXPORT_METHOD(updateMetadata: (NSString *) path metadata:(NSDictionary *) metadata resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
||||
FIRStorageReference *fileRef = [self getReference:path];
|
||||
FIRStorageMetadata *firmetadata = [[FIRStorageMetadata alloc] initWithDictionary:metadata];
|
||||
|
||||
[fileRef updateMetadata:firmetadata completion:^(FIRStorageMetadata * _Nullable metadata, NSError * _Nullable error) {
|
||||
if (error != nil) {
|
||||
NSDictionary *evt = @{
|
||||
@"status": @"error",
|
||||
@"path": path,
|
||||
@"message": [error debugDescription]
|
||||
};
|
||||
callback(@[evt]);
|
||||
[self promiseRejectStorageException:reject error: error];
|
||||
} else {
|
||||
NSDictionary *resp = [metadata dictionaryRepresentation];
|
||||
callback(@[[NSNull null], resp]);
|
||||
resolve([metadata dictionaryRepresentation]);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(downloadFile: (NSString *) path
|
||||
localPath:(NSString *) localPath
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
/**
|
||||
downloadFile
|
||||
|
||||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#downloadFile
|
||||
@param NSString path
|
||||
@param NSString localPath
|
||||
*/
|
||||
RCT_EXPORT_METHOD(downloadFile: (NSString *) path localPath:(NSString *) localPath resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
||||
FIRStorageReference *fileRef = [self getReference:path];
|
||||
NSURL *localFile = [NSURL fileURLWithPath:localPath];
|
||||
|
||||
FIRStorageDownloadTask *downloadTask = [fileRef writeToFile:localFile];
|
||||
// Listen for state changes, errors, and completion of the download.
|
||||
|
||||
// listen for state changes, errors, and completion of the download.
|
||||
[downloadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
|
||||
// Download resumed, also fires when the upload starts
|
||||
// download resumed, also fires when the upload starts
|
||||
NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot];
|
||||
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
|
||||
}];
|
||||
|
||||
|
||||
[downloadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
|
||||
// Download paused
|
||||
// download paused
|
||||
NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot];
|
||||
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
|
||||
}];
|
||||
|
||||
[downloadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
|
||||
// Download reported progress
|
||||
// download reported progress
|
||||
NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot];
|
||||
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
|
||||
}];
|
||||
|
||||
|
||||
[downloadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
|
||||
// Download completed successfully
|
||||
// download completed successfully
|
||||
NSDictionary *resp = [self getDownloadTaskAsDictionary:snapshot];
|
||||
|
||||
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_DOWNLOAD_SUCCESS props:resp];
|
||||
callback(@[[NSNull null], resp]);
|
||||
resolve(resp);
|
||||
}];
|
||||
|
||||
|
||||
[downloadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
|
||||
// download task failed
|
||||
if (snapshot.error != nil) {
|
||||
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
|
||||
NSLog(@"Error in download: %@", snapshot.error);
|
||||
|
||||
switch (snapshot.error.code) {
|
||||
case FIRStorageErrorCodeObjectNotFound:
|
||||
// File doesn't exist
|
||||
[errProps setValue:@"File does not exist" forKey:@"message"];
|
||||
break;
|
||||
case FIRStorageErrorCodeUnauthorized:
|
||||
// User doesn't have permission to access file
|
||||
[errProps setValue:@"You do not have permissions" forKey:@"message"];
|
||||
break;
|
||||
case FIRStorageErrorCodeCancelled:
|
||||
// User canceled the upload
|
||||
[errProps setValue:@"Download canceled" forKey:@"message"];
|
||||
break;
|
||||
case FIRStorageErrorCodeUnknown:
|
||||
// Unknown error occurred, inspect the server response
|
||||
[errProps setValue:@"Unknown error" forKey:@"message"];
|
||||
break;
|
||||
}
|
||||
|
||||
//TODO: Error event
|
||||
callback(@[errProps]);
|
||||
}}];
|
||||
[self promiseRejectStorageException:reject error:snapshot.error];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
setMaxDownloadRetryTime
|
||||
|
||||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxDownloadRetryTime
|
||||
@param NSNumber milliseconds
|
||||
*/
|
||||
RCT_EXPORT_METHOD(setMaxDownloadRetryTime:(NSNumber *) milliseconds) {
|
||||
[[FIRStorage storage] setMaxDownloadRetryTime:[milliseconds doubleValue]];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(putFile:(NSString *) path
|
||||
localPath:(NSString *)localPath
|
||||
metadata:(NSDictionary *)metadata
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
/**
|
||||
setMaxOperationRetryTime
|
||||
|
||||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxOperationRetryTime
|
||||
@param NSNumber milliseconds
|
||||
*/
|
||||
RCT_EXPORT_METHOD(setMaxOperationRetryTime:(NSNumber *) milliseconds) {
|
||||
[[FIRStorage storage] setMaxOperationRetryTime:[milliseconds doubleValue]];
|
||||
}
|
||||
|
||||
/**
|
||||
setMaxUploadRetryTime
|
||||
|
||||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxUploadRetryTime
|
||||
*/
|
||||
RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSNumber *) milliseconds) {
|
||||
[[FIRStorage storage] setMaxUploadRetryTime:[milliseconds doubleValue]];
|
||||
}
|
||||
|
||||
/**
|
||||
putFile
|
||||
|
||||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#putFile
|
||||
@param NSString path
|
||||
@param NSString localPath
|
||||
@param NSDictionary metadata
|
||||
*/
|
||||
RCT_EXPORT_METHOD(putFile:(NSString *) path localPath:(NSString *)localPath metadata:(NSDictionary *)metadata resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
||||
if ([localPath hasPrefix:@"assets-library://"] || [localPath hasPrefix:@"ph://"]) {
|
||||
PHFetchResult* assets;
|
||||
|
||||
if ([localPath hasPrefix:@"assets-library://"]) {
|
||||
NSURL *localFile = [[NSURL alloc] initWithString:localPath];
|
||||
assets = [PHAsset fetchAssetsWithALAssetURLs:@[localFile] options:nil];
|
||||
|
@ -172,174 +243,109 @@ RCT_EXPORT_METHOD(putFile:(NSString *) path
|
|||
NSString *assetId = [localPath substringFromIndex:@"ph://".length];
|
||||
assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetId] options:nil];
|
||||
}
|
||||
|
||||
PHAsset *asset = [assets firstObject];
|
||||
|
||||
//NOTE: This is all based on http://stackoverflow.com/questions/35241449
|
||||
|
||||
// this is based on http://stackoverflow.com/questions/35241449
|
||||
if (asset.mediaType == PHAssetMediaTypeImage) {
|
||||
// images
|
||||
PHImageRequestOptions *options = [PHImageRequestOptions new];
|
||||
options.networkAccessAllowed = true;
|
||||
[[PHImageManager defaultManager] requestImageDataForAsset:asset
|
||||
options:options
|
||||
resultHandler:^(NSData * imageData, NSString * dataUTI, UIImageOrientation orientation, NSDictionary * info) {
|
||||
if ([info objectForKey:PHImageErrorKey] == nil) {
|
||||
[self uploadData:imageData metadata:metadata path:path callback:callback];
|
||||
} else {
|
||||
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
|
||||
[errProps setValue:@"Could not obtain image data" forKey:@"message"];
|
||||
//TODO: Error event
|
||||
callback(@[errProps]);
|
||||
}
|
||||
}];
|
||||
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * imageData, NSString * dataUTI, UIImageOrientation orientation, NSDictionary * info) {
|
||||
if ([info objectForKey:PHImageErrorKey] == nil) {
|
||||
[self uploadData:imageData metadata:metadata path:path resolver:resolve rejecter:reject];
|
||||
} else {
|
||||
reject(@"storage/request-image-data-failed", @"Could not obtain image data for the specified file.", nil);
|
||||
}
|
||||
}];
|
||||
} else if (asset.mediaType == PHAssetMediaTypeVideo) {
|
||||
// video
|
||||
PHVideoRequestOptions *options = [PHVideoRequestOptions new];
|
||||
options.networkAccessAllowed = true;
|
||||
[[PHImageManager defaultManager] requestExportSessionForVideo:asset
|
||||
options:options
|
||||
exportPreset:AVAssetExportPresetHighestQuality
|
||||
resultHandler:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
|
||||
if ([info objectForKey:PHImageErrorKey] == nil) {
|
||||
NSURL *tempUrl = [self temporaryFileUrl];
|
||||
exportSession.outputURL = tempUrl;
|
||||
|
||||
NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:asset];
|
||||
for (PHAssetResource *resource in resources)
|
||||
{
|
||||
exportSession.outputFileType = resource.uniformTypeIdentifier;
|
||||
if (exportSession.outputFileType != nil)
|
||||
break;
|
||||
}
|
||||
|
||||
[exportSession exportAsynchronouslyWithCompletionHandler:^{
|
||||
if (exportSession.status == AVAssetExportSessionStatusCompleted)
|
||||
{
|
||||
[self uploadFile:tempUrl metadata:metadata path:path callback:callback];
|
||||
//NOTE: we're not cleaning up the temporary file at the moment, just relying on the OS to do that in it's own time
|
||||
} else {
|
||||
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
|
||||
[errProps setValue:@"Could not create temporary file for upload" forKey:@"message"];
|
||||
//TODO: Error event
|
||||
callback(@[errProps]);
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
|
||||
[errProps setValue:@"Could not create export session for asset" forKey:@"message"];
|
||||
//TODO: Error event
|
||||
callback(@[errProps]);
|
||||
}
|
||||
}];
|
||||
[[PHImageManager defaultManager] requestExportSessionForVideo:asset options:options exportPreset:AVAssetExportPresetHighestQuality resultHandler:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
|
||||
if ([info objectForKey:PHImageErrorKey] == nil) {
|
||||
NSURL *tempUrl = [self temporaryFileUrl];
|
||||
exportSession.outputURL = tempUrl;
|
||||
|
||||
NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:asset];
|
||||
for (PHAssetResource *resource in resources) {
|
||||
exportSession.outputFileType = resource.uniformTypeIdentifier;
|
||||
if (exportSession.outputFileType != nil) break;
|
||||
}
|
||||
|
||||
[exportSession exportAsynchronouslyWithCompletionHandler:^{
|
||||
if (exportSession.status == AVAssetExportSessionStatusCompleted) {
|
||||
[self uploadFile:tempUrl metadata:metadata path:path resolver:resolve rejecter:reject];
|
||||
// we're not cleaning up the temporary file at the moment, just relying on the OS to do that in it's own time - todo?
|
||||
} else {
|
||||
reject(@"storage/temporary-file-failure", @"Unable to create temporary file for upload.", nil);
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
reject(@"storage/export-session-failure", @"Unable to create export session for asset.", nil);
|
||||
}
|
||||
}];
|
||||
}
|
||||
} else {
|
||||
NSURL *fileUrl = [NSURL fileURLWithPath:localPath];
|
||||
[self uploadFile:fileUrl metadata:metadata path:path callback:callback];
|
||||
[self uploadFile:fileUrl metadata:metadata path:path resolver:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (NSURL *) temporaryFileUrl
|
||||
{
|
||||
- (NSURL *) temporaryFileUrl {
|
||||
NSString *filename = [NSString stringWithFormat:@"%@.tmp", [[NSProcessInfo processInfo] globallyUniqueString]];
|
||||
return [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:filename];
|
||||
}
|
||||
|
||||
- (void) uploadFile:(NSURL *) url
|
||||
metadata:(NSDictionary *) metadata
|
||||
path:(NSString *) path
|
||||
callback:(RCTResponseSenderBlock) callback
|
||||
{
|
||||
- (void) uploadFile:(NSURL *) url metadata:(NSDictionary *) metadata path:(NSString *) path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
|
||||
FIRStorageReference *fileRef = [self getReference:path];
|
||||
FIRStorageMetadata *firmetadata = [[FIRStorageMetadata alloc] initWithDictionary:metadata];
|
||||
FIRStorageUploadTask *uploadTask = [fileRef putFile:url metadata:firmetadata];
|
||||
[self addUploadObservers:uploadTask path:path callback:callback];
|
||||
[self addUploadObservers:uploadTask path:path resolver:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
- (void) uploadData:(NSData *) data
|
||||
metadata:(NSDictionary *) metadata
|
||||
path:(NSString *) path
|
||||
callback:(RCTResponseSenderBlock) callback
|
||||
{
|
||||
- (void) uploadData:(NSData *) data metadata:(NSDictionary *) metadata path:(NSString *) path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject{
|
||||
FIRStorageReference *fileRef = [self getReference:path];
|
||||
FIRStorageMetadata *firmetadata = [[FIRStorageMetadata alloc] initWithDictionary:metadata];
|
||||
FIRStorageUploadTask *uploadTask = [fileRef putData:data metadata:firmetadata];
|
||||
[self addUploadObservers:uploadTask path:path callback:callback];
|
||||
[self addUploadObservers:uploadTask path:path resolver:resolve rejecter:reject];
|
||||
}
|
||||
|
||||
- (void) addUploadObservers:(FIRStorageUploadTask *) uploadTask
|
||||
path:(NSString *) path
|
||||
callback:(RCTResponseSenderBlock) callback
|
||||
{
|
||||
// Listen for state changes, errors, and completion of the upload.
|
||||
- (void) addUploadObservers:(FIRStorageUploadTask *) uploadTask path:(NSString *) path resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject{
|
||||
// listen for state changes, errors, and completion of the upload.
|
||||
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
|
||||
// Upload resumed, also fires when the upload starts
|
||||
// upload resumed, also fires when the upload starts
|
||||
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
|
||||
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
|
||||
}];
|
||||
|
||||
|
||||
[uploadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
|
||||
// Upload paused
|
||||
// upload paused
|
||||
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
|
||||
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
|
||||
}];
|
||||
[uploadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
|
||||
// Upload reported progress
|
||||
// upload reported progress
|
||||
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
|
||||
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
|
||||
}];
|
||||
|
||||
|
||||
[uploadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
|
||||
// Upload completed successfully
|
||||
// upload completed successfully
|
||||
NSDictionary *resp = [self getUploadTaskAsDictionary:snapshot];
|
||||
|
||||
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_UPLOAD_SUCCESS props:resp];
|
||||
callback(@[[NSNull null], resp]);
|
||||
resolve(resp);
|
||||
}];
|
||||
|
||||
|
||||
[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
|
||||
[errProps setValue:@"File does not exist" forKey:@"message"];
|
||||
break;
|
||||
case FIRStorageErrorCodeUnauthorized:
|
||||
// User doesn't have permission to access file
|
||||
[errProps setValue:@"You do not have permissions" forKey:@"message"];
|
||||
break;
|
||||
case FIRStorageErrorCodeCancelled:
|
||||
// User canceled the upload
|
||||
[errProps setValue:@"Upload cancelled" forKey:@"message"];
|
||||
break;
|
||||
case FIRStorageErrorCodeUnknown:
|
||||
// Unknown error occurred, inspect the server response
|
||||
[errProps setValue:@"Unknown error" forKey:@"message"];
|
||||
break;
|
||||
}
|
||||
|
||||
//TODO: Error event
|
||||
callback(@[errProps]);
|
||||
}}];
|
||||
[self promiseRejectStorageException:reject error:snapshot.error];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
//Firebase.Storage methods
|
||||
RCT_EXPORT_METHOD(setMaxDownloadRetryTime:(NSNumber *) milliseconds)
|
||||
{
|
||||
[[FIRStorage storage] setMaxDownloadRetryTime:[milliseconds doubleValue]];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setMaxOperationRetryTime:(NSNumber *) milliseconds)
|
||||
{
|
||||
[[FIRStorage storage] setMaxOperationRetryTime:[milliseconds doubleValue]];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSNumber *) milliseconds)
|
||||
{
|
||||
[[FIRStorage storage] setMaxUploadRetryTime:[milliseconds doubleValue]];
|
||||
}
|
||||
|
||||
- (FIRStorageReference *)getReference:(NSString *)path
|
||||
{
|
||||
- (FIRStorageReference *)getReference:(NSString *)path {
|
||||
if ([path hasPrefix:@"url::"]) {
|
||||
NSString *url = [path substringFromIndex:5];
|
||||
return [[FIRStorage storage] referenceForURL:url];
|
||||
|
@ -357,8 +363,7 @@ RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSNumber *) milliseconds)
|
|||
};
|
||||
}
|
||||
|
||||
- (NSDictionary *)getUploadTaskAsDictionary:(FIRStorageTaskSnapshot *)task
|
||||
{
|
||||
- (NSDictionary *)getUploadTaskAsDictionary:(FIRStorageTaskSnapshot *)task {
|
||||
NSString *downloadUrl = [task.metadata.downloadURL absoluteString];
|
||||
FIRStorageMetadata *metadata = [task.metadata dictionaryRepresentation];
|
||||
return @{
|
||||
|
@ -371,8 +376,7 @@ RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSNumber *) milliseconds)
|
|||
};
|
||||
}
|
||||
|
||||
- (NSString *)getTaskStatus:(FIRStorageTaskStatus)status
|
||||
{
|
||||
- (NSString *)getTaskStatus:(FIRStorageTaskStatus)status {
|
||||
if (status == FIRStorageTaskStatusResume || status == FIRStorageTaskStatusProgress) {
|
||||
return @"RUNNING";
|
||||
} else if (status == FIRStorageTaskStatusPause) {
|
||||
|
@ -386,60 +390,38 @@ RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSNumber *) milliseconds)
|
|||
}
|
||||
}
|
||||
|
||||
// This is just too good not to use, but I don't want to take credit for
|
||||
// this work from RNFS
|
||||
// https://github.com/johanneslumpe/react-native-fs/blob/master/RNFSManager.m
|
||||
- (NSString *)getPathForDirectory:(int)directory
|
||||
{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
|
||||
return [paths firstObject];
|
||||
- (NSString *)getPathForDirectory:(int)directory {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
|
||||
return [paths firstObject];
|
||||
}
|
||||
|
||||
- (NSDictionary *)constantsToExport
|
||||
{
|
||||
return @{
|
||||
@"MAIN_BUNDLE_PATH": [[NSBundle mainBundle] bundlePath],
|
||||
@"CACHES_DIRECTORY_PATH": [self getPathForDirectory:NSCachesDirectory],
|
||||
@"DOCUMENT_DIRECTORY_PATH": [self getPathForDirectory:NSDocumentDirectory],
|
||||
@"EXTERNAL_DIRECTORY_PATH": [NSNull null],
|
||||
@"EXTERNAL_STORAGE_DIRECTORY_PATH": [NSNull null],
|
||||
@"TEMP_DIRECTORY_PATH": NSTemporaryDirectory(),
|
||||
@"LIBRARY_DIRECTORY_PATH": [self getPathForDirectory:NSLibraryDirectory],
|
||||
@"FILETYPE_REGULAR": NSFileTypeRegular,
|
||||
@"FILETYPE_DIRECTORY": NSFileTypeDirectory
|
||||
};
|
||||
- (NSDictionary *)constantsToExport {
|
||||
return @{
|
||||
@"MAIN_BUNDLE_PATH": [[NSBundle mainBundle] bundlePath],
|
||||
@"CACHES_DIRECTORY_PATH": [self getPathForDirectory:NSCachesDirectory],
|
||||
@"DOCUMENT_DIRECTORY_PATH": [self getPathForDirectory:NSDocumentDirectory],
|
||||
@"EXTERNAL_DIRECTORY_PATH": [NSNull null],
|
||||
@"EXTERNAL_STORAGE_DIRECTORY_PATH": [NSNull null],
|
||||
@"TEMP_DIRECTORY_PATH": NSTemporaryDirectory(),
|
||||
@"LIBRARY_DIRECTORY_PATH": [self getPathForDirectory:NSLibraryDirectory],
|
||||
@"FILETYPE_REGULAR": NSFileTypeRegular,
|
||||
@"FILETYPE_DIRECTORY": NSFileTypeDirectory
|
||||
};
|
||||
}
|
||||
|
||||
// Not sure how to get away from this... yet
|
||||
- (NSArray<NSString *> *)supportedEvents {
|
||||
return @[STORAGE_EVENT, STORAGE_ERROR];
|
||||
}
|
||||
|
||||
- (void) sendJSError:(NSError *) error
|
||||
withPath:(NSString *) path
|
||||
{
|
||||
NSDictionary *evt = @{
|
||||
@"path": path,
|
||||
@"message": [error debugDescription]
|
||||
};
|
||||
- (void) sendJSError:(NSError *) error withPath:(NSString *) path {
|
||||
NSDictionary *evt = @{ @"path": path, @"message": [error debugDescription] };
|
||||
[self sendJSEvent:STORAGE_ERROR path:path title:STORAGE_ERROR props: evt];
|
||||
}
|
||||
|
||||
- (void) sendJSEvent:(NSString *)type
|
||||
path:(NSString *)path
|
||||
title:(NSString *)title
|
||||
props:(NSDictionary *)props
|
||||
{
|
||||
- (void) sendJSEvent:(NSString *)type path:(NSString *)path title:(NSString *)title props:(NSDictionary *)props {
|
||||
@try {
|
||||
[self sendEventWithName:type
|
||||
body:@{
|
||||
@"eventName": title,
|
||||
@"path": path,
|
||||
@"body": props
|
||||
}];
|
||||
|
||||
}
|
||||
@catch (NSException *err) {
|
||||
[self sendEventWithName:type body:@{ @"eventName": title, @"path": path, @"body": props }];
|
||||
} @catch (NSException *err) {
|
||||
NSLog(@"An error occurred in sendJSEvent: %@", [err debugDescription]);
|
||||
NSLog(@"Tried to send: %@ with %@", title, props);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue