2015-05-08 17:05:37 +00:00
|
|
|
//
|
|
|
|
// RNFSManager.m
|
|
|
|
// RNFSManager
|
|
|
|
//
|
|
|
|
// Created by Johannes Lumpe on 08/05/15.
|
|
|
|
// Copyright (c) 2015 Johannes Lumpe. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "RNFSManager.h"
|
2017-02-20 09:05:45 +00:00
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
#import "NSArray+Map.h"
|
2015-11-19 00:20:09 +00:00
|
|
|
#import "Downloader.h"
|
2016-05-30 22:13:50 +00:00
|
|
|
#import "Uploader.h"
|
2017-02-20 09:05:45 +00:00
|
|
|
|
2017-01-10 16:09:17 +00:00
|
|
|
#import <React/RCTEventDispatcher.h>
|
2017-04-27 22:59:29 +00:00
|
|
|
#import <React/RCTUtils.h>
|
|
|
|
#import <React/RCTImageLoader.h>
|
2017-02-20 09:05:45 +00:00
|
|
|
|
2016-11-16 20:33:24 +00:00
|
|
|
#import <CommonCrypto/CommonDigest.h>
|
2017-04-27 22:59:29 +00:00
|
|
|
#import <Photos/Photos.h>
|
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
|
2015-11-23 16:29:25 +00:00
|
|
|
@interface RNFSManager()
|
|
|
|
|
|
|
|
@property (retain) NSMutableDictionary* downloaders;
|
2016-05-30 22:13:50 +00:00
|
|
|
@property (retain) NSMutableDictionary* uploaders;
|
2015-11-23 16:29:25 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
@implementation RNFSManager
|
|
|
|
|
2015-11-20 00:16:13 +00:00
|
|
|
@synthesize bridge = _bridge;
|
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
RCT_EXPORT_MODULE();
|
|
|
|
|
2015-08-18 15:12:44 +00:00
|
|
|
- (dispatch_queue_t)methodQueue
|
|
|
|
{
|
2015-05-10 18:13:13 +00:00
|
|
|
return dispatch_queue_create("pe.lum.rnfs", DISPATCH_QUEUE_SERIAL);
|
|
|
|
}
|
2015-05-08 17:05:37 +00:00
|
|
|
|
2015-10-22 00:25:52 +00:00
|
|
|
RCT_EXPORT_METHOD(readDir:(NSString *)dirPath
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2015-08-18 15:12:44 +00:00
|
|
|
{
|
2015-05-08 17:05:37 +00:00
|
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
2015-05-10 18:13:13 +00:00
|
|
|
NSError *error = nil;
|
2015-10-22 00:25:52 +00:00
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
NSArray *contents = [fileManager contentsOfDirectoryAtPath:dirPath error:&error];
|
2015-05-08 20:47:54 +00:00
|
|
|
|
2015-08-18 15:12:44 +00:00
|
|
|
contents = [contents rnfs_mapObjectsUsingBlock:^id(NSString *obj, NSUInteger idx) {
|
2015-10-20 22:31:29 +00:00
|
|
|
NSString *path = [dirPath stringByAppendingPathComponent:obj];
|
|
|
|
NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:nil];
|
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
return @{
|
2017-04-27 11:07:19 +00:00
|
|
|
@"ctime": [self dateToTimeIntervalNumber:(NSDate *)[attributes objectForKey:NSFileCreationDate]],
|
|
|
|
@"mtime": [self dateToTimeIntervalNumber:(NSDate *)[attributes objectForKey:NSFileModificationDate]],
|
2016-06-29 23:08:53 +00:00
|
|
|
@"name": obj,
|
|
|
|
@"path": path,
|
|
|
|
@"size": [attributes objectForKey:NSFileSize],
|
|
|
|
@"type": [attributes objectForKey:NSFileType]
|
|
|
|
};
|
2015-05-08 17:05:37 +00:00
|
|
|
}];
|
2015-05-08 20:47:54 +00:00
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
if (error) {
|
2016-05-14 20:29:17 +00:00
|
|
|
return [self reject:reject withError:error];
|
2015-05-08 17:05:37 +00:00
|
|
|
}
|
2015-05-08 20:47:54 +00:00
|
|
|
|
2016-05-14 20:25:04 +00:00
|
|
|
resolve(contents);
|
2015-05-08 17:05:37 +00:00
|
|
|
}
|
|
|
|
|
2016-01-28 18:20:02 +00:00
|
|
|
RCT_EXPORT_METHOD(exists:(NSString *)filepath
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(__unused RCTPromiseRejectBlock)reject)
|
2016-01-28 13:36:31 +00:00
|
|
|
{
|
|
|
|
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filepath];
|
|
|
|
|
2016-05-14 20:25:04 +00:00
|
|
|
resolve([NSNumber numberWithBool:fileExists]);
|
2016-01-28 13:36:31 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 15:12:44 +00:00
|
|
|
RCT_EXPORT_METHOD(stat:(NSString *)filepath
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2015-08-18 15:12:44 +00:00
|
|
|
{
|
2015-05-10 18:13:13 +00:00
|
|
|
NSError *error = nil;
|
2015-05-08 17:05:37 +00:00
|
|
|
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filepath error:&error];
|
2015-05-08 20:47:54 +00:00
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
if (error) {
|
2016-05-14 20:29:17 +00:00
|
|
|
return [self reject:reject withError:error];
|
2015-05-08 17:05:37 +00:00
|
|
|
}
|
2015-05-08 20:47:54 +00:00
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
attributes = @{
|
2016-06-29 23:08:53 +00:00
|
|
|
@"ctime": [self dateToTimeIntervalNumber:(NSDate *)[attributes objectForKey:NSFileCreationDate]],
|
|
|
|
@"mtime": [self dateToTimeIntervalNumber:(NSDate *)[attributes objectForKey:NSFileModificationDate]],
|
|
|
|
@"size": [attributes objectForKey:NSFileSize],
|
|
|
|
@"type": [attributes objectForKey:NSFileType],
|
|
|
|
@"mode": @([[NSString stringWithFormat:@"%ld", (long)[(NSNumber *)[attributes objectForKey:NSFilePosixPermissions] integerValue]] integerValue])
|
|
|
|
};
|
2015-05-08 20:47:54 +00:00
|
|
|
|
2016-05-14 20:25:04 +00:00
|
|
|
resolve(attributes);
|
2015-05-08 17:05:37 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 15:12:44 +00:00
|
|
|
RCT_EXPORT_METHOD(writeFile:(NSString *)filepath
|
|
|
|
contents:(NSString *)base64Content
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2015-08-18 15:12:44 +00:00
|
|
|
{
|
2015-05-08 20:47:54 +00:00
|
|
|
NSData *data = [[NSData alloc] initWithBase64EncodedString:base64Content options:NSDataBase64DecodingIgnoreUnknownCharacters];
|
2016-06-29 23:08:53 +00:00
|
|
|
|
2016-08-02 19:15:06 +00:00
|
|
|
BOOL success = [[NSFileManager defaultManager] createFileAtPath:filepath contents:data attributes:nil];
|
2016-06-29 23:08:53 +00:00
|
|
|
|
|
|
|
if (!success) {
|
2016-07-18 21:46:13 +00:00
|
|
|
return reject(@"ENOENT", [NSString stringWithFormat:@"ENOENT: no such file or directory, open '%@'", filepath], nil);
|
2015-05-08 20:47:54 +00:00
|
|
|
}
|
2016-06-29 23:08:53 +00:00
|
|
|
|
2016-07-18 21:46:13 +00:00
|
|
|
return resolve(nil);
|
2016-06-29 23:08:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(appendFile:(NSString *)filepath
|
|
|
|
contents:(NSString *)base64Content
|
2016-07-18 21:46:13 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2016-06-29 23:08:53 +00:00
|
|
|
{
|
|
|
|
NSData *data = [[NSData alloc] initWithBase64EncodedString:base64Content options:NSDataBase64DecodingIgnoreUnknownCharacters];
|
|
|
|
|
|
|
|
NSFileManager *fM = [NSFileManager defaultManager];
|
|
|
|
|
|
|
|
if (![fM fileExistsAtPath:filepath])
|
2016-06-22 09:05:47 +00:00
|
|
|
{
|
2016-08-02 19:15:06 +00:00
|
|
|
BOOL success = [[NSFileManager defaultManager] createFileAtPath:filepath contents:data attributes:nil];
|
2016-06-29 23:08:53 +00:00
|
|
|
|
|
|
|
if (!success) {
|
2016-07-18 21:46:13 +00:00
|
|
|
return reject(@"ENOENT", [NSString stringWithFormat:@"ENOENT: no such file or directory, open '%@'", filepath], nil);
|
2016-06-29 23:08:53 +00:00
|
|
|
} else {
|
2016-07-18 21:46:13 +00:00
|
|
|
return resolve(nil);
|
2016-06-22 09:05:47 +00:00
|
|
|
}
|
2016-06-29 23:08:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@try {
|
2016-06-22 09:05:47 +00:00
|
|
|
NSFileHandle *fH = [NSFileHandle fileHandleForUpdatingAtPath:filepath];
|
2016-06-29 23:08:53 +00:00
|
|
|
|
2016-06-22 09:05:47 +00:00
|
|
|
[fH seekToEndOfFile];
|
|
|
|
[fH writeData:data];
|
2016-06-29 23:08:53 +00:00
|
|
|
|
2016-07-18 21:46:13 +00:00
|
|
|
return resolve(nil);
|
2016-06-29 23:08:53 +00:00
|
|
|
} @catch (NSException *e) {
|
2016-07-18 21:46:13 +00:00
|
|
|
return [self reject:reject withError:e];
|
2016-06-22 09:05:47 +00:00
|
|
|
}
|
2015-05-08 20:47:54 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 15:12:44 +00:00
|
|
|
RCT_EXPORT_METHOD(unlink:(NSString*)filepath
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2015-08-18 15:12:44 +00:00
|
|
|
{
|
2015-05-08 21:17:10 +00:00
|
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
|
|
BOOL exists = [manager fileExistsAtPath:filepath isDirectory:false];
|
|
|
|
|
|
|
|
if (!exists) {
|
2016-07-18 21:46:13 +00:00
|
|
|
return reject(@"ENOENT", [NSString stringWithFormat:@"ENOENT: no such file or directory, open '%@'", filepath], nil);
|
2015-05-08 21:17:10 +00:00
|
|
|
}
|
2016-07-18 21:46:13 +00:00
|
|
|
|
2015-05-10 18:13:13 +00:00
|
|
|
NSError *error = nil;
|
2015-05-08 21:17:10 +00:00
|
|
|
BOOL success = [manager removeItemAtPath:filepath error:&error];
|
|
|
|
|
|
|
|
if (!success) {
|
2016-05-14 20:29:17 +00:00
|
|
|
return [self reject:reject withError:error];
|
2015-05-08 21:17:10 +00:00
|
|
|
}
|
|
|
|
|
2016-07-18 21:46:13 +00:00
|
|
|
resolve(nil);
|
2015-05-08 21:17:10 +00:00
|
|
|
}
|
|
|
|
|
2016-08-01 18:36:15 +00:00
|
|
|
RCT_EXPORT_METHOD(mkdir:(NSString *)filepath
|
|
|
|
options:(NSDictionary *)options
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2015-10-20 22:31:29 +00:00
|
|
|
{
|
|
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
BOOL success = [manager createDirectoryAtPath:filepath withIntermediateDirectories:YES attributes:nil error:&error];
|
|
|
|
|
|
|
|
if (!success) {
|
2016-05-14 20:25:04 +00:00
|
|
|
return [self reject:reject withError:error];
|
2015-10-20 22:31:29 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 00:25:52 +00:00
|
|
|
NSURL *url = [NSURL fileURLWithPath:filepath];
|
|
|
|
|
2016-08-01 18:36:15 +00:00
|
|
|
if ([[options allKeys] containsObject:@"NSURLIsExcludedFromBackupKey"]) {
|
|
|
|
NSNumber *value = options[@"NSURLIsExcludedFromBackupKey"];
|
|
|
|
success = [url setResourceValue: value forKey: NSURLIsExcludedFromBackupKey error: &error];
|
2015-10-22 00:25:52 +00:00
|
|
|
|
2016-08-01 18:36:15 +00:00
|
|
|
if (!success) {
|
|
|
|
return [self reject:reject withError:error];
|
|
|
|
}
|
2015-10-22 00:25:52 +00:00
|
|
|
}
|
|
|
|
|
2016-07-18 21:46:13 +00:00
|
|
|
resolve(nil);
|
2015-10-20 22:31:29 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 15:12:44 +00:00
|
|
|
RCT_EXPORT_METHOD(readFile:(NSString *)filepath
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2015-08-18 15:12:44 +00:00
|
|
|
{
|
2016-07-26 23:15:41 +00:00
|
|
|
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filepath];
|
2015-05-08 21:17:10 +00:00
|
|
|
|
2016-07-26 23:15:41 +00:00
|
|
|
if (!fileExists) {
|
2016-07-18 21:46:13 +00:00
|
|
|
return reject(@"ENOENT", [NSString stringWithFormat:@"ENOENT: no such file or directory, open '%@'", filepath], nil);
|
2015-05-08 17:05:37 +00:00
|
|
|
}
|
2015-05-08 20:47:54 +00:00
|
|
|
|
2016-07-26 23:15:41 +00:00
|
|
|
NSError *error = nil;
|
|
|
|
|
|
|
|
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filepath error:&error];
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
return [self reject:reject withError:error];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([attributes objectForKey:NSFileType] == NSFileTypeDirectory) {
|
|
|
|
return reject(@"EISDIR", @"EISDIR: illegal operation on a directory, read", nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
NSData *content = [[NSFileManager defaultManager] contentsAtPath:filepath];
|
|
|
|
NSString *base64Content = [content base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
|
|
|
|
|
2016-05-14 20:25:04 +00:00
|
|
|
resolve(base64Content);
|
2015-05-08 17:05:37 +00:00
|
|
|
}
|
|
|
|
|
2016-11-16 20:33:24 +00:00
|
|
|
RCT_EXPORT_METHOD(hash:(NSString *)filepath
|
|
|
|
algorithm:(NSString *)algorithm
|
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
|
|
{
|
|
|
|
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filepath];
|
|
|
|
|
|
|
|
if (!fileExists) {
|
|
|
|
return reject(@"ENOENT", [NSString stringWithFormat:@"ENOENT: no such file or directory, open '%@'", filepath], nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
|
|
|
|
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filepath error:&error];
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
return [self reject:reject withError:error];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([attributes objectForKey:NSFileType] == NSFileTypeDirectory) {
|
|
|
|
return reject(@"EISDIR", @"EISDIR: illegal operation on a directory, read", nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
NSData *content = [[NSFileManager defaultManager] contentsAtPath:filepath];
|
|
|
|
|
|
|
|
NSArray *keys = [NSArray arrayWithObjects:@"md5", @"sha1", @"sha224", @"sha256", @"sha384", @"sha512", nil];
|
|
|
|
|
|
|
|
NSArray *digestLengths = [NSArray arrayWithObjects:
|
|
|
|
@CC_MD5_DIGEST_LENGTH,
|
|
|
|
@CC_SHA1_DIGEST_LENGTH,
|
|
|
|
@CC_SHA224_DIGEST_LENGTH,
|
|
|
|
@CC_SHA256_DIGEST_LENGTH,
|
|
|
|
@CC_SHA384_DIGEST_LENGTH,
|
|
|
|
@CC_SHA512_DIGEST_LENGTH,
|
|
|
|
nil];
|
|
|
|
|
|
|
|
NSDictionary *keysToDigestLengths = [NSDictionary dictionaryWithObjects:digestLengths forKeys:keys];
|
|
|
|
|
|
|
|
int digestLength = [[keysToDigestLengths objectForKey:algorithm] intValue];
|
|
|
|
|
|
|
|
if (!digestLength) {
|
|
|
|
return reject(@"Error", [NSString stringWithFormat:@"Invalid hash algorithm '%@'", algorithm], nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char buffer[digestLength];
|
|
|
|
|
|
|
|
if ([algorithm isEqualToString:@"md5"]) {
|
|
|
|
CC_MD5(content.bytes, (CC_LONG)content.length, buffer);
|
|
|
|
} else if ([algorithm isEqualToString:@"sha1"]) {
|
|
|
|
CC_SHA1(content.bytes, (CC_LONG)content.length, buffer);
|
|
|
|
} else if ([algorithm isEqualToString:@"sha224"]) {
|
|
|
|
CC_SHA224(content.bytes, (CC_LONG)content.length, buffer);
|
|
|
|
} else if ([algorithm isEqualToString:@"sha256"]) {
|
|
|
|
CC_SHA256(content.bytes, (CC_LONG)content.length, buffer);
|
|
|
|
} else if ([algorithm isEqualToString:@"sha384"]) {
|
|
|
|
CC_SHA384(content.bytes, (CC_LONG)content.length, buffer);
|
|
|
|
} else if ([algorithm isEqualToString:@"sha512"]) {
|
|
|
|
CC_SHA512(content.bytes, (CC_LONG)content.length, buffer);
|
|
|
|
} else {
|
|
|
|
return reject(@"Error", [NSString stringWithFormat:@"Invalid hash algorithm '%@'", algorithm], nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
NSMutableString *output = [NSMutableString stringWithCapacity:digestLength * 2];
|
|
|
|
for(int i = 0; i < digestLength; i++)
|
|
|
|
[output appendFormat:@"%02x",buffer[i]];
|
|
|
|
|
|
|
|
resolve(output);
|
|
|
|
}
|
|
|
|
|
2016-01-16 18:52:56 +00:00
|
|
|
RCT_EXPORT_METHOD(moveFile:(NSString *)filepath
|
2016-01-27 16:52:56 +00:00
|
|
|
destPath:(NSString *)destPath
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2016-01-16 18:52:56 +00:00
|
|
|
{
|
2016-06-29 23:08:53 +00:00
|
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
2016-04-07 19:29:36 +00:00
|
|
|
|
2016-06-29 23:08:53 +00:00
|
|
|
NSError *error = nil;
|
|
|
|
BOOL success = [manager moveItemAtPath:filepath toPath:destPath error:&error];
|
2016-04-07 19:29:36 +00:00
|
|
|
|
2016-06-29 23:08:53 +00:00
|
|
|
if (!success) {
|
2016-05-14 20:29:17 +00:00
|
|
|
return [self reject:reject withError:error];
|
2016-06-29 23:08:53 +00:00
|
|
|
}
|
2016-04-07 19:29:36 +00:00
|
|
|
|
2016-07-18 21:46:13 +00:00
|
|
|
resolve(nil);
|
2016-01-16 18:52:56 +00:00
|
|
|
}
|
|
|
|
|
2016-07-03 10:10:24 +00:00
|
|
|
RCT_EXPORT_METHOD(copyFile:(NSString *)filepath
|
|
|
|
destPath:(NSString *)destPath
|
2016-07-18 22:15:07 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2016-07-03 10:10:24 +00:00
|
|
|
{
|
|
|
|
NSFileManager *manager = [NSFileManager defaultManager];
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
BOOL success = [manager copyItemAtPath:filepath toPath:destPath error:&error];
|
|
|
|
|
|
|
|
if (!success) {
|
2016-07-18 22:15:07 +00:00
|
|
|
return [self reject:reject withError:error];
|
2016-07-03 10:10:24 +00:00
|
|
|
}
|
|
|
|
|
2016-07-18 22:15:07 +00:00
|
|
|
resolve(nil);
|
2016-07-03 10:10:24 +00:00
|
|
|
}
|
|
|
|
|
2016-06-01 23:49:01 +00:00
|
|
|
RCT_EXPORT_METHOD(downloadFile:(NSDictionary *)options
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2015-10-20 23:17:03 +00:00
|
|
|
{
|
2016-07-21 07:59:37 +00:00
|
|
|
RNFSDownloadParams* params = [RNFSDownloadParams alloc];
|
2016-04-07 19:29:36 +00:00
|
|
|
|
2016-06-01 23:49:01 +00:00
|
|
|
NSNumber* jobId = options[@"jobId"];
|
|
|
|
params.fromUrl = options[@"fromUrl"];
|
|
|
|
params.toFile = options[@"toFile"];
|
|
|
|
NSDictionary* headers = options[@"headers"];
|
|
|
|
params.headers = headers;
|
|
|
|
NSNumber* background = options[@"background"];
|
|
|
|
params.background = [background boolValue];
|
2016-06-08 16:52:08 +00:00
|
|
|
NSNumber* progressDivider = options[@"progressDivider"];
|
2016-05-31 09:46:03 +00:00
|
|
|
params.progressDivider = progressDivider;
|
2015-11-23 16:29:25 +00:00
|
|
|
|
2016-05-30 22:13:50 +00:00
|
|
|
params.completeCallback = ^(NSNumber* statusCode, NSNumber* bytesWritten) {
|
2016-10-13 10:42:56 +00:00
|
|
|
NSMutableDictionary* result = [[NSMutableDictionary alloc] initWithDictionary: @{@"jobId": jobId}];
|
|
|
|
if (statusCode) {
|
|
|
|
[result setObject:statusCode forKey: @"statusCode"];
|
|
|
|
}
|
2016-01-20 04:00:34 +00:00
|
|
|
if (bytesWritten) {
|
2016-01-20 05:42:04 +00:00
|
|
|
[result setObject:bytesWritten forKey: @"bytesWritten"];
|
2016-01-20 04:00:34 +00:00
|
|
|
}
|
2016-05-14 20:25:04 +00:00
|
|
|
return resolve(result);
|
2015-11-19 00:20:09 +00:00
|
|
|
};
|
2015-10-22 23:13:12 +00:00
|
|
|
|
2015-11-23 17:08:52 +00:00
|
|
|
params.errorCallback = ^(NSError* error) {
|
2016-05-14 20:25:04 +00:00
|
|
|
return [self reject:reject withError:error];
|
2015-11-19 00:20:09 +00:00
|
|
|
};
|
2016-04-07 19:29:36 +00:00
|
|
|
|
2015-11-23 16:29:25 +00:00
|
|
|
params.beginCallback = ^(NSNumber* statusCode, NSNumber* contentLength, NSDictionary* headers) {
|
|
|
|
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"DownloadBegin-%@", jobId]
|
|
|
|
body:@{@"jobId": jobId,
|
|
|
|
@"statusCode": statusCode,
|
2015-11-20 00:16:13 +00:00
|
|
|
@"contentLength": contentLength,
|
2015-11-23 16:29:25 +00:00
|
|
|
@"headers": headers}];
|
|
|
|
};
|
2016-04-07 19:29:36 +00:00
|
|
|
|
2015-11-23 16:29:25 +00:00
|
|
|
params.progressCallback = ^(NSNumber* contentLength, NSNumber* bytesWritten) {
|
|
|
|
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"DownloadProgress-%@", jobId]
|
2016-04-07 19:29:36 +00:00
|
|
|
body:@{@"jobId": jobId,
|
|
|
|
@"contentLength": contentLength,
|
2015-11-20 00:16:13 +00:00
|
|
|
@"bytesWritten": bytesWritten}];
|
2015-11-19 00:20:09 +00:00
|
|
|
};
|
2015-10-20 23:17:03 +00:00
|
|
|
|
2015-11-23 17:08:52 +00:00
|
|
|
if (!self.downloaders) self.downloaders = [[NSMutableDictionary alloc] init];
|
2016-04-07 19:29:36 +00:00
|
|
|
|
2016-07-21 07:59:37 +00:00
|
|
|
RNFSDownloader* downloader = [RNFSDownloader alloc];
|
2015-11-19 00:20:09 +00:00
|
|
|
|
2015-11-23 16:29:25 +00:00
|
|
|
[downloader downloadFile:params];
|
2016-04-07 19:29:36 +00:00
|
|
|
|
2015-11-23 16:29:25 +00:00
|
|
|
[self.downloaders setValue:downloader forKey:[jobId stringValue]];
|
|
|
|
}
|
|
|
|
|
2015-11-23 17:08:52 +00:00
|
|
|
RCT_EXPORT_METHOD(stopDownload:(nonnull NSNumber *)jobId)
|
2015-11-23 16:29:25 +00:00
|
|
|
{
|
2016-07-21 07:59:37 +00:00
|
|
|
RNFSDownloader* downloader = [self.downloaders objectForKey:[jobId stringValue]];
|
2016-04-07 19:29:36 +00:00
|
|
|
|
2015-11-23 16:29:25 +00:00
|
|
|
if (downloader != nil) {
|
|
|
|
[downloader stopDownload];
|
|
|
|
}
|
2015-10-20 23:17:03 +00:00
|
|
|
}
|
|
|
|
|
2016-05-30 22:13:50 +00:00
|
|
|
RCT_EXPORT_METHOD(uploadFiles:(NSDictionary *)options
|
2016-07-18 21:46:13 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2016-05-30 22:13:50 +00:00
|
|
|
{
|
2016-07-21 07:59:37 +00:00
|
|
|
RNFSUploadParams* params = [RNFSUploadParams alloc];
|
2016-05-30 22:13:50 +00:00
|
|
|
|
|
|
|
NSNumber* jobId = options[@"jobId"];
|
|
|
|
params.toUrl = options[@"toUrl"];
|
|
|
|
params.files = options[@"files"];
|
|
|
|
NSDictionary* headers = options[@"headers"];
|
|
|
|
NSDictionary* fields = options[@"fields"];
|
|
|
|
NSString* method = options[@"method"];
|
|
|
|
params.headers = headers;
|
|
|
|
params.fields = fields;
|
|
|
|
params.method = method;
|
|
|
|
|
2016-06-15 09:51:43 +00:00
|
|
|
params.completeCallback = ^(NSString* body, NSURLResponse *resp) {
|
2016-06-15 10:33:35 +00:00
|
|
|
|
2016-05-30 22:13:50 +00:00
|
|
|
NSMutableDictionary* result = [[NSMutableDictionary alloc] initWithDictionary: @{@"jobId": jobId,
|
2016-08-02 18:38:22 +00:00
|
|
|
@"body": body}];
|
2016-06-15 09:51:43 +00:00
|
|
|
if ([resp isKindOfClass:[NSHTTPURLResponse class]]) {
|
|
|
|
[result setValue:((NSHTTPURLResponse *)resp).allHeaderFields forKey:@"headers"];
|
|
|
|
[result setValue:[NSNumber numberWithUnsignedInteger:((NSHTTPURLResponse *)resp).statusCode] forKey:@"statusCode"];
|
|
|
|
}
|
2016-07-18 21:46:13 +00:00
|
|
|
return resolve(result);
|
2016-05-30 22:13:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
params.errorCallback = ^(NSError* error) {
|
2016-07-18 21:46:13 +00:00
|
|
|
return [self reject:reject withError:error];
|
2016-05-30 22:13:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
params.beginCallback = ^() {
|
|
|
|
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"UploadBegin-%@", jobId]
|
|
|
|
body:@{@"jobId": jobId}];
|
|
|
|
};
|
|
|
|
|
|
|
|
params.progressCallback = ^(NSNumber* totalBytesExpectedToSend, NSNumber* totalBytesSent) {
|
|
|
|
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"UploadProgress-%@", jobId]
|
2016-06-29 23:08:53 +00:00
|
|
|
body:@{@"jobId": jobId,
|
|
|
|
@"totalBytesExpectedToSend": totalBytesExpectedToSend,
|
2016-05-30 22:13:50 +00:00
|
|
|
@"totalBytesSent": totalBytesSent}];
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!self.uploaders) self.uploaders = [[NSMutableDictionary alloc] init];
|
|
|
|
|
2016-07-21 07:59:37 +00:00
|
|
|
RNFSUploader* uploader = [RNFSUploader alloc];
|
2016-05-30 22:13:50 +00:00
|
|
|
|
|
|
|
[uploader uploadFiles:params];
|
|
|
|
|
|
|
|
[self.uploaders setValue:uploader forKey:[jobId stringValue]];
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(stopUpload:(nonnull NSNumber *)jobId)
|
|
|
|
{
|
2016-07-21 07:59:37 +00:00
|
|
|
RNFSUploader* uploader = [self.uploaders objectForKey:[jobId stringValue]];
|
2016-05-30 22:13:50 +00:00
|
|
|
|
|
|
|
if (uploader != nil) {
|
|
|
|
[uploader stopUpload];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-18 15:12:44 +00:00
|
|
|
RCT_EXPORT_METHOD(pathForBundle:(NSString *)bundleNamed
|
2016-05-14 20:25:04 +00:00
|
|
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
|
|
rejecter:(RCTPromiseRejectBlock)reject)
|
2015-08-18 15:12:44 +00:00
|
|
|
{
|
2016-06-29 23:08:53 +00:00
|
|
|
NSString *path = [[NSBundle mainBundle].bundlePath stringByAppendingFormat:@"/%@.bundle", bundleNamed];
|
|
|
|
NSBundle *bundle = [NSBundle bundleWithPath:path];
|
2015-08-27 17:30:57 +00:00
|
|
|
|
2016-06-29 23:08:53 +00:00
|
|
|
if (!bundle) {
|
|
|
|
bundle = [NSBundle bundleForClass:NSClassFromString(bundleNamed)];
|
|
|
|
path = bundle.bundlePath;
|
|
|
|
}
|
2015-10-20 22:31:29 +00:00
|
|
|
|
2016-06-29 23:08:53 +00:00
|
|
|
if (!bundle.isLoaded) {
|
|
|
|
[bundle load];
|
|
|
|
}
|
2015-08-18 15:12:44 +00:00
|
|
|
|
2016-06-29 23:08:53 +00:00
|
|
|
if (path) {
|
2016-05-14 20:29:17 +00:00
|
|
|
resolve(path);
|
2016-06-29 23:08:53 +00:00
|
|
|
} else {
|
2016-05-14 20:29:17 +00:00
|
|
|
NSError *error = [NSError errorWithDomain:NSPOSIXErrorDomain
|
|
|
|
code:NSFileNoSuchFileError
|
|
|
|
userInfo:nil];
|
2016-05-14 20:25:04 +00:00
|
|
|
|
2016-05-14 20:29:17 +00:00
|
|
|
[self reject:reject withError:error];
|
2016-06-29 23:08:53 +00:00
|
|
|
}
|
2015-08-18 15:12:44 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 20:25:04 +00:00
|
|
|
RCT_EXPORT_METHOD(getFSInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
2016-03-18 17:53:00 +00:00
|
|
|
{
|
2016-06-29 23:08:53 +00:00
|
|
|
unsigned long long totalSpace = 0;
|
|
|
|
unsigned long long totalFreeSpace = 0;
|
|
|
|
|
|
|
|
__autoreleasing NSError *error = nil;
|
|
|
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
2016-05-14 20:29:17 +00:00
|
|
|
NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error:&error];
|
2016-06-29 23:08:53 +00:00
|
|
|
|
|
|
|
if (dictionary) {
|
|
|
|
NSNumber *fileSystemSizeInBytes = [dictionary objectForKey: NSFileSystemSize];
|
|
|
|
NSNumber *freeFileSystemSizeInBytes = [dictionary objectForKey:NSFileSystemFreeSize];
|
|
|
|
totalSpace = [fileSystemSizeInBytes unsignedLongLongValue];
|
|
|
|
totalFreeSpace = [freeFileSystemSizeInBytes unsignedLongLongValue];
|
|
|
|
|
2016-05-14 20:29:17 +00:00
|
|
|
resolve(@{
|
|
|
|
@"totalSpace": [NSNumber numberWithUnsignedLongLong:totalSpace],
|
|
|
|
@"freeSpace": [NSNumber numberWithUnsignedLongLong:totalFreeSpace]
|
|
|
|
});
|
2016-06-29 23:08:53 +00:00
|
|
|
} else {
|
2016-05-14 20:29:17 +00:00
|
|
|
[self reject:reject withError:error];
|
2016-06-29 23:08:53 +00:00
|
|
|
}
|
2016-03-18 17:53:00 +00:00
|
|
|
}
|
|
|
|
|
2017-04-27 22:59:29 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* iOS Only: copy images from the assets-library (camera-roll) to a specific path, asuming
|
|
|
|
* JPEG-Images. Video-Support will follow up, not implemented yet.
|
|
|
|
*
|
|
|
|
* It is also supported to scale the image via scale-factor (0.0-1.0) or with a specific
|
|
|
|
* width and height. Also the resizeMode will be considered.
|
|
|
|
*/
|
|
|
|
RCT_EXPORT_METHOD(copyAssetsFileIOS: (NSString *) imageUri
|
|
|
|
toFilepath: (NSString *) destination
|
|
|
|
width: (NSInteger) width
|
|
|
|
height: (NSInteger) height
|
|
|
|
scale: (CGFloat) scale
|
|
|
|
compression: (CGFloat) compression
|
|
|
|
resizeMode: (RCTResizeMode) resizeMode
|
|
|
|
resolver: (RCTPromiseResolveBlock) resolve
|
|
|
|
rejecter: (RCTPromiseRejectBlock) reject)
|
|
|
|
|
|
|
|
{
|
|
|
|
CGSize size = CGSizeMake(width, height);
|
|
|
|
|
|
|
|
NSURL* url = [NSURL URLWithString:imageUri];
|
|
|
|
PHFetchResult *results = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
|
|
|
|
|
|
|
|
if (results.count == 0) {
|
|
|
|
NSString *errorText = [NSString stringWithFormat:@"Failed to fetch PHAsset with local identifier %@ with no error message.", imageUri];
|
|
|
|
|
|
|
|
NSMutableDictionary* details = [NSMutableDictionary dictionary];
|
|
|
|
[details setValue:errorText forKey:NSLocalizedDescriptionKey];
|
|
|
|
NSError *error = [NSError errorWithDomain:@"RNFS" code:500 userInfo:details];
|
|
|
|
[self reject: reject withError:error];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PHAsset *asset = [results firstObject];
|
|
|
|
PHImageRequestOptions *imageOptions = [PHImageRequestOptions new];
|
|
|
|
|
|
|
|
// Allow us to fetch images from iCloud
|
|
|
|
imageOptions.networkAccessAllowed = YES;
|
|
|
|
|
|
|
|
|
|
|
|
// Note: PhotoKit defaults to a deliveryMode of PHImageRequestOptionsDeliveryModeOpportunistic
|
|
|
|
// which means it may call back multiple times - we probably don't want that
|
|
|
|
imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
|
|
|
|
|
|
|
|
BOOL useMaximumSize = CGSizeEqualToSize(size, CGSizeZero);
|
|
|
|
CGSize targetSize;
|
|
|
|
if (useMaximumSize) {
|
|
|
|
targetSize = PHImageManagerMaximumSize;
|
|
|
|
imageOptions.resizeMode = PHImageRequestOptionsResizeModeNone;
|
|
|
|
} else {
|
|
|
|
targetSize = CGSizeApplyAffineTransform(size, CGAffineTransformMakeScale(scale, scale));
|
|
|
|
imageOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
|
|
|
|
}
|
|
|
|
|
|
|
|
PHImageContentMode contentMode = PHImageContentModeAspectFill;
|
|
|
|
if (resizeMode == RCTResizeModeContain) {
|
|
|
|
contentMode = PHImageContentModeAspectFit;
|
|
|
|
}
|
|
|
|
|
|
|
|
// PHImageRequestID requestID =
|
|
|
|
[[PHImageManager defaultManager] requestImageForAsset:asset
|
|
|
|
targetSize:targetSize
|
|
|
|
contentMode:contentMode
|
|
|
|
options:imageOptions
|
|
|
|
resultHandler:^(UIImage *result, NSDictionary<NSString *, id> *info) {
|
|
|
|
if (result) {
|
|
|
|
|
|
|
|
NSData *imageData = UIImageJPEGRepresentation(result, compression );
|
|
|
|
[imageData writeToFile:destination atomically:YES];
|
|
|
|
resolve(destination);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
NSMutableDictionary* details = [NSMutableDictionary dictionary];
|
|
|
|
[details setValue:info[PHImageErrorKey] forKey:NSLocalizedDescriptionKey];
|
|
|
|
NSError *error = [NSError errorWithDomain:@"RNFS" code:501 userInfo:details];
|
|
|
|
[self reject: reject withError:error];
|
|
|
|
|
|
|
|
}
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-08-27 17:30:57 +00:00
|
|
|
- (NSNumber *)dateToTimeIntervalNumber:(NSDate *)date
|
2015-08-18 15:12:44 +00:00
|
|
|
{
|
|
|
|
return @([date timeIntervalSince1970]);
|
2015-05-08 17:05:37 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 20:25:04 +00:00
|
|
|
- (void)reject:(RCTPromiseRejectBlock)reject withError:(NSError *)error
|
2015-08-18 15:12:44 +00:00
|
|
|
{
|
2016-05-14 20:25:04 +00:00
|
|
|
NSString *codeWithDomain = [NSString stringWithFormat:@"E%@%zd", error.domain.uppercaseString, error.code];
|
|
|
|
reject(codeWithDomain, error.localizedDescription, error);
|
2015-05-08 17:05:37 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 15:12:44 +00:00
|
|
|
- (NSString *)getPathForDirectory:(int)directory
|
|
|
|
{
|
2015-05-08 17:17:59 +00:00
|
|
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
|
2015-08-18 15:12:44 +00:00
|
|
|
return [paths firstObject];
|
2015-05-08 17:17:59 +00:00
|
|
|
}
|
|
|
|
|
2015-05-08 17:05:37 +00:00
|
|
|
- (NSDictionary *)constantsToExport
|
|
|
|
{
|
|
|
|
return @{
|
2016-08-10 18:53:24 +00:00
|
|
|
@"RNFSMainBundlePath": [[NSBundle mainBundle] bundlePath],
|
|
|
|
@"RNFSCachesDirectoryPath": [self getPathForDirectory:NSCachesDirectory],
|
|
|
|
@"RNFSDocumentDirectoryPath": [self getPathForDirectory:NSDocumentDirectory],
|
|
|
|
@"RNFSExternalDirectoryPath": [NSNull null],
|
2016-08-10 19:07:04 +00:00
|
|
|
@"RNFSExternalStorageDirectoryPath": [NSNull null],
|
2016-08-10 18:53:24 +00:00
|
|
|
@"RNFSTemporaryDirectoryPath": NSTemporaryDirectory(),
|
|
|
|
@"RNFSLibraryDirectoryPath": [self getPathForDirectory:NSLibraryDirectory],
|
|
|
|
@"RNFSFileTypeRegular": NSFileTypeRegular,
|
|
|
|
@"RNFSFileTypeDirectory": NSFileTypeDirectory
|
2016-06-29 23:08:53 +00:00
|
|
|
};
|
2015-05-08 17:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|