Browse Source

Improve file API consistency #18

Ben Hsieh 8 years ago
parent
commit
c5212450e3
4 changed files with 110 additions and 40 deletions
  1. 52
    18
      src/fs.js
  2. 2
    1
      src/index.js
  3. 3
    0
      src/ios/RNFetchBlob/RNFetchBlob.h
  4. 53
    21
      src/ios/RNFetchBlob/RNFetchBlob.m

+ 52
- 18
src/fs.js View File

@@ -24,15 +24,15 @@ let sessions = {}
24 24
 
25 25
 /**
26 26
  * Get path of system directories.
27
- * @return {object} Map contains PictureDir, MovieDir, DocumentDir, CacheDir,
28
- * MusicDir, and DCIMDir, some directory might not be supported by platform.
27
+ * @return {object} Map contains DocumentDir, CacheDir, DCIMDir, DownloadDir,
28
+ * , some directory might not be supported by platform.
29 29
  */
30 30
 function getSystemDirs() {
31 31
   return new Promise((resolve, reject) => {
32 32
     try {
33 33
       RNFetchBlob.getEnvironmentDirs((...dirs) => {
34
-        let [PictureDir, MovieDir, DocumentDir, CacheDir, MusicDir, DCIMDir] = [...dirs]
35
-        resolve({PictureDir, MovieDir, DocumentDir, CacheDir, MusicDir, DCIMDir})
34
+        let [DocumentDir, CacheDir, DCIMDir, DownloadDir] = [...dirs]
35
+        resolve({DocumentDir, CacheDir, DCIMDir, DownloadDir})
36 36
       })
37 37
     } catch(err) {
38 38
       reject(err)
@@ -55,32 +55,42 @@ function session(name:string):RNFetchBlobSession {
55 55
   }
56 56
 }
57 57
 
58
+/**
59
+ * Create write stream to a file.
60
+ * @param  {string} path Target path of file stream.
61
+ * @param  {string} encoding Encoding of input data.
62
+ * @param  {bool} append  A flag represent if data append to existing ones.
63
+ * @return {Promise<WriteStream>} A promise resolves a `WriteStream` object.
64
+ */
58 65
 function writeStream(
59
-  path:string,
60
-  encoding:'utf8' | 'ascii' | 'base64',
61
-  callback:(streamId:string) => void
66
+  path : string,
67
+  encoding : 'utf8' | 'ascii' | 'base64',
68
+  append? : ?bool,
62 69
 ):Promise<WriteStream> {
63 70
   if(!path)
64 71
     throw Error('RNFetchBlob could not open file stream with empty `path`')
65 72
   encoding = encoding || 'base64'
66 73
   return new Promise((resolve, reject) => {
67
-    RNFetchBlob.writeStream(path, encoding || 'base64', (streamId:string) => {
68
-      resolve(new WriteStream(streamId))
74
+    RNFetchBlob.writeStream(path, encoding || 'base64', append || false, (err, streamId:string) => {
75
+      if(err)
76
+        reject(err)
77
+      else
78
+        resolve(new WriteStream(streamId))
69 79
     })
70 80
   })
71 81
 }
72 82
 
73 83
 /**
74 84
  * Create file stream from file at `path`.
75
- * @param  {String} path   The file path.
76
- * @param  {String} encoding Data encoding, should be one of `base64`, `utf8`, `ascii`
77
- * @param  {String} bufferSize Size of stream buffer.
85
+ * @param  {string} path   The file path.
86
+ * @param  {string} encoding Data encoding, should be one of `base64`, `utf8`, `ascii`
87
+ * @param  {boolean} bufferSize Size of stream buffer.
78 88
  * @return {RNFetchBlobStream} RNFetchBlobStream stream instance.
79 89
  */
80 90
 function readStream(
81
-  path:string,
82
-  encoding:'utf8' | 'ascii' | 'base64',
83
-  bufferSize?:?number
91
+  path : string,
92
+  encoding : 'utf8' | 'ascii' | 'base64',
93
+  bufferSize? : ?number
84 94
 ):RNFetchBlobStream {
85 95
 
86 96
   if(!path)
@@ -183,6 +193,25 @@ function unlink(path:string):Promise {
183 193
   })
184 194
 }
185 195
 
196
+/**
197
+ * Check if file exists and if it is a folder.
198
+ * @param  {string} path Path to check
199
+ * @return {Promise<bool, bool>}
200
+ */
201
+function exists(path:string):Promise<bool, bool> {
202
+
203
+  return new Promise((resolve, reject) => {
204
+    try {
205
+      RNFetchBlob.exists(path, (exist, isDir) => {
206
+        resolve(exist, isDir)
207
+      })
208
+    } catch(err) {
209
+      reject(err)
210
+    }
211
+  })
212
+
213
+}
214
+
186 215
 /**
187 216
  * Session class
188 217
  * @class RNFetchBlobSession
@@ -244,17 +273,22 @@ class WriteStream {
244 273
 
245 274
   id : string;
246 275
   encoding : string;
276
+  append : bool;
247 277
 
248
-  constructor(streamId:string, encoding:string) {
278
+  constructor(streamId:string, encoding:string, append:string) {
249 279
     this.id = streamId
250 280
     this.encoding = encoding
281
+    this.append = append
251 282
   }
252 283
 
253 284
   write() {
254 285
     return new Promise((resolve, reject) => {
255 286
       try {
256
-        RNFetchBlob.writeChunk(this.id, data, this.encoding, () => {
257
-          resolve()
287
+        RNFetchBlob.writeChunk(this.id, data, (error) => {
288
+          if(error)
289
+            reject(error)
290
+          else
291
+            resolve()
258 292
         })
259 293
       } catch(err) {
260 294
         reject(err)

+ 2
- 1
src/index.js View File

@@ -26,6 +26,7 @@ const {
26 26
   unlink,
27 27
   mkdir,
28 28
   session,
29
+  writeStream,
29 30
   ls,
30 31
   mv,
31 32
   cp
@@ -244,5 +245,5 @@ function getUUID() {
244 245
 }
245 246
 
246 247
 export default {
247
-  fetch, base64, config, getSystemDirs, readStream, unlink, session, ls, mkdir, mv, cp
248
+  fetch, base64, config, getSystemDirs, readStream, unlink, session, ls, mkdir, mv, cp, writeStream
248 249
 }

+ 3
- 0
src/ios/RNFetchBlob/RNFetchBlob.h View File

@@ -35,6 +35,7 @@ extern NSString *const FS_EVENT_ERROR;
35 35
     Boolean isOpen;
36 36
     NSString * encoding;
37 37
     int bufferSize;
38
+    BOOL appendData;
38 39
     NSString * taskId;
39 40
     NSString * path;
40 41
     NSString * streamId;
@@ -49,6 +50,7 @@ extern NSString *const FS_EVENT_ERROR;
49 50
 @property (nonatomic) NSString * path;
50 51
 @property (nonatomic) int bufferSize;
51 52
 @property (nonatomic) NSString * streamId;
53
+@property (nonatomic) BOOL appendData;
52 54
 
53 55
 + (NSString *) getTempPath;
54 56
 + (FetchBlobFS *) getFileStreams;
@@ -85,6 +87,7 @@ extern NSString *const FS_EVENT_ERROR;
85 87
 @property (nonatomic) NSDictionary * options;
86 88
 @property (nonatomic) FetchBlobFS * fileStream;
87 89
 
90
+
88 91
 - (id) init;
89 92
 - (void) sendRequest;
90 93
 

+ 53
- 21
src/ios/RNFetchBlob/RNFetchBlob.m View File

@@ -42,6 +42,7 @@ NSString *const FS_EVENT_ERROR = @"error";
42 42
 @synthesize callback;
43 43
 @synthesize taskId;
44 44
 @synthesize path;
45
+@synthesize appendData;
45 46
 @synthesize bufferSize;
46 47
 
47 48
 // static member getter
@@ -120,8 +121,10 @@ NSString *const FS_EVENT_ERROR = @"error";
120 121
     return self;
121 122
 }
122 123
 
123
-- (NSString *)openWithPath:(NSString *)destPath {
124
-    self.outStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:YES];
124
+// Create file stream for write data
125
+- (NSString *)openWithPath:(NSString *)destPath encode:(nullable NSString *)encode appendData:(BOOL)append {
126
+    self.outStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:append];
127
+    self.encoding = encode;
125 128
     [self.outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
126 129
     [self.outStream open];
127 130
     NSString *uuid = [[NSUUID UUID] UUIDString];
@@ -130,6 +133,30 @@ NSString *const FS_EVENT_ERROR = @"error";
130 133
     return uuid;
131 134
 }
132 135
 
136
+// Write file chunk into an opened stream
137
+- (void)writeEncodeChunk:(NSString *) chunk {
138
+    NSMutableData * decodedData = [NSData alloc];
139
+    if([[self.encoding lowercaseString] isEqualToString:@"base64"]) {
140
+        decodedData = [chunk dataUsingEncoding:NSUTF8StringEncoding];
141
+    }
142
+    if([[self.encoding lowercaseString] isEqualToString:@"utf8"]) {
143
+        decodedData = [chunk dataUsingEncoding:NSUTF8StringEncoding];
144
+    }
145
+    else if([[self.encoding lowercaseString] isEqualToString:@"ascii"]) {
146
+        decodedData = [chunk dataUsingEncoding:NSASCIIStringEncoding];
147
+    }
148
+    NSUInteger left = [chunk length];
149
+    NSUInteger nwr = 0;
150
+    do {
151
+        nwr = [self.outStream write:[decodedData bytes] maxLength:left];
152
+        if (-1 == nwr) break;
153
+        left -= nwr;
154
+    } while (left > 0);
155
+    if (left) {
156
+        NSLog(@"stream error: %@", [self.outStream streamError]);
157
+    }
158
+}
159
+
133 160
 // Write file chunk into an opened stream
134 161
 - (void)write:(NSData *) chunk {
135 162
     NSUInteger left = [chunk length];
@@ -342,11 +369,11 @@ void runOnMainQueueWithoutDeadlocking(void (^block)(void))
342 369
     // open file stream for write
343 370
     if( path != nil) {
344 371
         self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
345
-        [self.fileStream openWithPath:path];
372
+        [self.fileStream openWithPath:path encode:@"ascii" appendData:YES ];
346 373
     }
347 374
     else if ( [self.options valueForKey:CONFIG_USE_TEMP]!= nil ) {
348 375
         self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
349
-        [self.fileStream openWithPath:[FetchBlobFS getTempPath:taskId withExtension:ext]];
376
+        [self.fileStream openWithPath:[FetchBlobFS getTempPath:taskId withExtension:ext] encode:@"ascii" appendData:YES];
350 377
     }
351 378
     
352 379
     NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:NO];
@@ -620,29 +647,36 @@ RCT_EXPORT_METHOD(fetchBlob:(NSDictionary *)options
620 647
     });
621 648
 }
622 649
 
650
+RCT_EXPORT_METHOD(exists:(NSString *)path callback:(RCTResponseSenderBlock)callback) {
651
+    BOOL isDir = NO;
652
+    BOOL exists = NO;
653
+    exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory: &isDir];
654
+    callback(@[@(exists), @(isDir)]);
655
+
656
+}
657
+
623 658
 RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize) {
624 659
     FetchBlobFS *fileStream = [[FetchBlobFS alloc] initWithBridgeRef:self.bridge];
625 660
     [fileStream readWithPath:path useEncoding:encoding bufferSize:bufferSize];
626 661
 }
627 662
 
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]);
663
+RCT_EXPORT_METHOD(writeStream:(NSString *)path withEncoding:(NSString *)encoding appendData:(BOOL)append callback:(RCTResponseSenderBlock)callback) {
664
+    FetchBlobFS * fileStream = [[FetchBlobFS alloc] initWithBridgeRef:self.bridge];
665
+    NSFileManager * fm = [NSFileManager defaultManager];
666
+    BOOL isDir = nil;
667
+    BOOL exist = ![fm fileExistsAtPath:path isDirectory:&isDir];
668
+    if( exist == NO || isDir == YES) {
669
+        callback(@[[NSString stringWithFormat:@"target path `%@` may not exists or it's a folder", path]]);
670
+        return;
671
+    }
672
+    NSString * streamId = [fileStream openWithPath:path encode:encoding appendData:append];
673
+    callback(@[[NSNull null], streamId]);
632 674
 }
633 675
 
634
-RCT_EXPORT_METHOD(writeChunk:(NSString *)streamId withData:(NSString *)data encoding:(NSString *)encode callback:(RCTResponseSenderBlock) callback) {
676
+RCT_EXPORT_METHOD(writeChunk:(NSString *)streamId withData:(NSString *)data callback:(RCTResponseSenderBlock) callback) {
635 677
     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
-    }
678
+    [fs writeEncodeChunk:data];
679
+    callback(@[[NSNull null]]);
646 680
 }
647 681
 
648 682
 RCT_EXPORT_METHOD(closeStream:(NSString *)streamId callback:(RCTResponseSenderBlock) callback) {
@@ -720,8 +754,6 @@ RCT_EXPORT_METHOD(mkdir:(NSString *)path callback:(RCTResponseSenderBlock) callb
720 754
 RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {
721 755
     
722 756
     callback(@[
723
-               [FetchBlobFS getPictureDir],
724
-               [FetchBlobFS getMovieDir],
725 757
                [FetchBlobFS getDocumentDir],
726 758
                [FetchBlobFS getCacheDir],
727 759
             ]);