|
@@ -35,6 +35,7 @@ NSString *const FS_EVENT_ERROR = @"error";
|
35
|
35
|
|
36
|
36
|
@implementation FetchBlobFS
|
37
|
37
|
|
|
38
|
+
|
38
|
39
|
@synthesize outStream;
|
39
|
40
|
@synthesize inStream;
|
40
|
41
|
@synthesize encoding;
|
|
@@ -43,8 +44,14 @@ NSString *const FS_EVENT_ERROR = @"error";
|
43
|
44
|
@synthesize path;
|
44
|
45
|
@synthesize bufferSize;
|
45
|
46
|
|
46
|
|
-
|
47
|
|
-
|
|
47
|
+// static member getter
|
|
48
|
++ (NSArray *) getFileStreams {
|
|
49
|
+
|
|
50
|
+ static NSMutableData *fileStreams = nil;
|
|
51
|
+ if(fileStreams == nil)
|
|
52
|
+ fileStreams = [[NSArray alloc] init];
|
|
53
|
+ return fileStreams;
|
|
54
|
+}
|
48
|
55
|
|
49
|
56
|
+ (NSString *) getCacheDir {
|
50
|
57
|
return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
|
|
@@ -67,22 +74,40 @@ NSString *const FS_EVENT_ERROR = @"error";
|
67
|
74
|
}
|
68
|
75
|
|
69
|
76
|
|
|
77
|
++ (NSString *) getTempPath {
|
|
78
|
+
|
|
79
|
+ return [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingString:@"/RNFetchBlob_tmp"];
|
|
80
|
+}
|
|
81
|
+
|
70
|
82
|
+ (NSString *) getTempPath:(NSString*)taskId withExtension:(NSString *)ext {
|
71
|
83
|
|
72
|
84
|
NSString * documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
73
|
|
- NSString * filename = [NSString stringWithFormat:@"/RNFetchBlobTmp_%@", taskId];
|
|
85
|
+ NSString * filename = [NSString stringWithFormat:@"/RNFetchBlob_tmp/RNFetchBlobTmp_%@", taskId];
|
74
|
86
|
if(ext != nil)
|
75
|
87
|
filename = [filename stringByAppendingString: [NSString stringWithFormat:@".%@", ext]];
|
76
|
88
|
NSString * tempPath = [documentDir stringByAppendingString: filename];
|
77
|
89
|
return tempPath;
|
78
|
90
|
}
|
79
|
91
|
|
|
92
|
++ (BOOL) mkdir:(NSString *) path {
|
|
93
|
+ BOOL isDir;
|
|
94
|
+ NSError * err = nil;
|
|
95
|
+ // if temp folder not exists, create one
|
|
96
|
+ if(![[NSFileManager defaultManager] fileExistsAtPath: path isDirectory:&isDir]) {
|
|
97
|
+ [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&err];
|
|
98
|
+ }
|
|
99
|
+ return err == nil;
|
|
100
|
+}
|
|
101
|
+
|
|
102
|
++ (BOOL) exists:(NSString *) path {
|
|
103
|
+ return [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:NULL];
|
|
104
|
+}
|
|
105
|
+
|
80
|
106
|
- (id)init {
|
81
|
107
|
self = [super init];
|
82
|
108
|
return self;
|
83
|
109
|
}
|
84
|
110
|
|
85
|
|
-
|
86
|
111
|
- (id)initWithCallback:(RCTResponseSenderBlock)callback {
|
87
|
112
|
self = [super init];
|
88
|
113
|
self.callback = callback;
|
|
@@ -95,15 +120,18 @@ NSString *const FS_EVENT_ERROR = @"error";
|
95
|
120
|
return self;
|
96
|
121
|
}
|
97
|
122
|
|
98
|
|
-- (void)openWithPath:(NSString *)destPath {
|
|
123
|
+- (NSString *)openWithPath:(NSString *)destPath {
|
99
|
124
|
self.outStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:YES];
|
100
|
125
|
[self.outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
101
|
126
|
[self.outStream open];
|
|
127
|
+ NSString *uuid = [[NSUUID UUID] UUIDString];
|
|
128
|
+ self.streamId = uuid;
|
|
129
|
+ [[FetchBlobFS getFileStreams] setValue:self forKey:uuid];
|
|
130
|
+ return uuid;
|
102
|
131
|
}
|
103
|
132
|
|
104
|
|
-
|
105
|
133
|
// Write file chunk into an opened stream
|
106
|
|
-- (void)write:(NSData *) chunk toPath:(NSString *) path{
|
|
134
|
+- (void)write:(NSData *) chunk {
|
107
|
135
|
NSUInteger left = [chunk length];
|
108
|
136
|
NSUInteger nwr = 0;
|
109
|
137
|
do {
|
|
@@ -134,7 +162,6 @@ NSString *const FS_EVENT_ERROR = @"error";
|
134
|
162
|
[[NSRunLoop currentRunLoop] run];
|
135
|
163
|
|
136
|
164
|
});
|
137
|
|
-
|
138
|
165
|
}
|
139
|
166
|
|
140
|
167
|
// close file write stream
|
|
@@ -151,6 +178,8 @@ NSString *const FS_EVENT_ERROR = @"error";
|
151
|
178
|
if(self.inStream != nil) {
|
152
|
179
|
[self.inStream close];
|
153
|
180
|
[self.inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
|
181
|
+ [[FetchBlobFS getFileStreams] setValue:nil forKey:self.streamId];
|
|
182
|
+ self.streamId = nil;
|
154
|
183
|
}
|
155
|
184
|
|
156
|
185
|
}
|
|
@@ -345,12 +374,12 @@ void runOnMainQueueWithoutDeadlocking(void (^block)(void))
|
345
|
374
|
Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
|
346
|
375
|
NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
|
347
|
376
|
if(path != nil) {
|
348
|
|
- [self.fileStream write:data toPath:path];
|
|
377
|
+ [self.fileStream write:data];
|
349
|
378
|
}
|
350
|
379
|
// write to tmp file
|
351
|
380
|
else if( fileCache != nil) {
|
352
|
381
|
NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
|
353
|
|
- [self.fileStream write:data toPath:[FetchBlobFS getTempPath:self.taskId withExtension:ext]];
|
|
382
|
+ [self.fileStream write:data];
|
354
|
383
|
}
|
355
|
384
|
// cache data in memory
|
356
|
385
|
else {
|
|
@@ -457,6 +486,11 @@ RCT_EXPORT_MODULE();
|
457
|
486
|
- (id) init {
|
458
|
487
|
self = [super init];
|
459
|
488
|
self.filePathPrefix = FILE_PREFIX;
|
|
489
|
+ BOOL isDir;
|
|
490
|
+ // if temp folder not exists, create one
|
|
491
|
+ if(![[NSFileManager defaultManager] fileExistsAtPath: [FetchBlobFS getTempPath] isDirectory:&isDir]) {
|
|
492
|
+ [[NSFileManager defaultManager] createDirectoryAtPath:[FetchBlobFS getTempPath] withIntermediateDirectories:YES attributes:nil error:NULL];
|
|
493
|
+ }
|
460
|
494
|
return self;
|
461
|
495
|
}
|
462
|
496
|
|
|
@@ -591,6 +625,32 @@ RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding
|
591
|
625
|
[fileStream readWithPath:path useEncoding:encoding bufferSize:bufferSize];
|
592
|
626
|
}
|
593
|
627
|
|
|
628
|
+RCT_EXPORT_METHOD(writeStream:(NSString *)path withEncoding:(NSString *)encoding callback:(RCTResponseSenderBlock)callback) {
|
|
629
|
+ FetchBlobFS *fileStream = [[FetchBlobFS alloc] initWithBridgeRef:self.bridge];
|
|
630
|
+ NSString * streamId = [fileStream openWithPath:path];
|
|
631
|
+ callback(@[streamId]);
|
|
632
|
+}
|
|
633
|
+
|
|
634
|
+RCT_EXPORT_METHOD(writeChunk:(NSString *)streamId withData:(NSString *)data encoding:(NSString *)encode callback:(RCTResponseSenderBlock) callback) {
|
|
635
|
+ FetchBlobFS *fs = [[FetchBlobFS getFileStreams] valueForKey:streamId];
|
|
636
|
+ NSMutableData * decodedData = [NSData alloc];
|
|
637
|
+ if([[encode lowercaseString] isEqualToString:@"base64"]) {
|
|
638
|
+ [fs write:[data dataUsingEncoding:NSUTF8StringEncoding]];
|
|
639
|
+ }
|
|
640
|
+ if([[encode lowercaseString] isEqualToString:@"utf8"]) {
|
|
641
|
+ [fs write:[data dataUsingEncoding:NSUTF8StringEncoding]];
|
|
642
|
+ }
|
|
643
|
+ else if([[encode lowercaseString] isEqualToString:@"ascii"]) {
|
|
644
|
+ [fs write:[data dataUsingEncoding:NSASCIIStringEncoding]];
|
|
645
|
+ }
|
|
646
|
+}
|
|
647
|
+
|
|
648
|
+RCT_EXPORT_METHOD(closeStream:(NSString *)streamId callback:(RCTResponseSenderBlock) callback) {
|
|
649
|
+ FetchBlobFS *fs = [[FetchBlobFS getFileStreams] valueForKey:streamId];
|
|
650
|
+ [fs closeOutStream];
|
|
651
|
+ callback(@[[NSNull null], @YES]);
|
|
652
|
+}
|
|
653
|
+
|
594
|
654
|
RCT_EXPORT_METHOD(unlink:(NSString *)path callback:(RCTResponseSenderBlock) callback) {
|
595
|
655
|
NSError * error = nil;
|
596
|
656
|
NSString * tmpPath = nil;
|
|
@@ -601,6 +661,62 @@ RCT_EXPORT_METHOD(unlink:(NSString *)path callback:(RCTResponseSenderBlock) call
|
601
|
661
|
callback(@[[NSString stringWithFormat:@"failed to unlink file or path at %@", path]]);
|
602
|
662
|
}
|
603
|
663
|
|
|
664
|
+RCT_EXPORT_METHOD(removeSession:(NSArray *)paths callback:(RCTResponseSenderBlock) callback) {
|
|
665
|
+ NSError * error = nil;
|
|
666
|
+ NSString * tmpPath = nil;
|
|
667
|
+
|
|
668
|
+ for(NSString * path in paths) {
|
|
669
|
+ [[NSFileManager defaultManager] removeItemAtPath:path error:&error];
|
|
670
|
+ if(error != nil) {
|
|
671
|
+ callback(@[[NSString stringWithFormat:@"failed to remove session path at %@", path]]);
|
|
672
|
+ return;
|
|
673
|
+ }
|
|
674
|
+ }
|
|
675
|
+ callback(@[[NSNull null]]);
|
|
676
|
+
|
|
677
|
+}
|
|
678
|
+
|
|
679
|
+RCT_EXPORT_METHOD(ls:(NSString *)path callback:(RCTResponseSenderBlock) callback) {
|
|
680
|
+ NSError * error = nil;
|
|
681
|
+ NSArray * result = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error];
|
|
682
|
+
|
|
683
|
+ if(error == nil)
|
|
684
|
+ callback(@[[NSNull null], result == nil ? [NSNull null] :result ]);
|
|
685
|
+ else
|
|
686
|
+ callback(@[[error localizedDescription], [NSNull null]]);
|
|
687
|
+
|
|
688
|
+}
|
|
689
|
+
|
|
690
|
+RCT_EXPORT_METHOD(cp:(NSString *)path toPath:(NSString *)dest callback:(RCTResponseSenderBlock) callback) {
|
|
691
|
+ NSError * error = nil;
|
|
692
|
+ BOOL result = [[NSFileManager defaultManager] copyItemAtURL:path toURL:dest error:&error];
|
|
693
|
+
|
|
694
|
+ if(error == nil)
|
|
695
|
+ callback(@[[NSNull null], @YES]);
|
|
696
|
+ else
|
|
697
|
+ callback(@[[error localizedDescription], @NO]);
|
|
698
|
+
|
|
699
|
+}
|
|
700
|
+
|
|
701
|
+RCT_EXPORT_METHOD(mv:(NSString *)path toPath:(NSString *)dest callback:(RCTResponseSenderBlock) callback) {
|
|
702
|
+ NSError * error = nil;
|
|
703
|
+ BOOL result = [[NSFileManager defaultManager] moveItemAtURL:path toURL:dest error:&error];
|
|
704
|
+
|
|
705
|
+ if(error == nil)
|
|
706
|
+ callback(@[[NSNull null], @YES]);
|
|
707
|
+ else
|
|
708
|
+ callback(@[[error localizedDescription], @NO]);
|
|
709
|
+
|
|
710
|
+}
|
|
711
|
+
|
|
712
|
+RCT_EXPORT_METHOD(mkdir:(NSString *)path callback:(RCTResponseSenderBlock) callback) {
|
|
713
|
+ if([FetchBlobFS exists:path])
|
|
714
|
+ callback(@[@"file path exists"]);
|
|
715
|
+ else
|
|
716
|
+ [FetchBlobFS mkdir:path];
|
|
717
|
+ callback(@[[NSNull null]]);
|
|
718
|
+}
|
|
719
|
+
|
604
|
720
|
RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {
|
605
|
721
|
|
606
|
722
|
callback(@[
|