ソースを参照

fs.readStream redesign

Ben Hsieh 8 年 前
コミット
765de2308f
共有5 個のファイルを変更した111 個の追加234 個の削除を含む
  1. 10
    9
      src/class/RNFetchBlobReadStream.js
  2. 1
    0
      src/ios/RNFetchBlob/RNFetchBlob.h
  3. 15
    5
      src/ios/RNFetchBlob/RNFetchBlob.m
  4. 2
    3
      src/ios/RNFetchBlobFS.h
  5. 83
    217
      src/ios/RNFetchBlobFS.m

+ 10
- 9
src/class/RNFetchBlobReadStream.js ファイルの表示

@@ -8,6 +8,7 @@ import {
8 8
   DeviceEventEmitter,
9 9
   NativeAppEventEmitter,
10 10
 } from 'react-native'
11
+import UUID from '../utils/uuid'
11 12
 
12 13
 const RNFetchBlob = NativeModules.RNFetchBlob
13 14
 const emitter = DeviceEventEmitter
@@ -29,10 +30,10 @@ export default class RNFetchBlobReadStream {
29 30
     this._onData = () => {}
30 31
     this._onEnd = () => {}
31 32
     this._onError = () => {}
33
+    this.streamId = 'RNFBRS'+ UUID()
32 34
 
33 35
     // register for file stream event
34
-    let subscription = emitter.addListener(`RNFetchBlobStream+${this.path}`, (e) => {
35
-
36
+    let subscription = emitter.addListener(this.streamId, (e) => {
36 37
       let {event, detail} = e
37 38
       if(this._onData && event === 'data')
38 39
         this._onData(detail)
@@ -56,18 +57,18 @@ export default class RNFetchBlobReadStream {
56 57
 
57 58
   open() {
58 59
     if(!this.closed)
59
-      RNFetchBlob.readStream(this.path, this.encoding, this.bufferSize || 0)
60
+      RNFetchBlob.readStream(this.path, this.encoding, this.bufferSize || 0, this.streamId)
60 61
     else
61 62
       throw new Error('Stream closed')
62 63
   }
63 64
 
64 65
   onData(fn) {
65
-    if(this.encoding.toLowerCase() === 'ascii')
66
-      this._onData = (data) => {
67
-        fn(data)
68
-      }
69
-    else
70
-      this._onData = fn
66
+    // if(this.encoding.toLowerCase() === 'ascii')
67
+    //   this._onData = (data) => {
68
+    //     fn(data)
69
+    //   }
70
+    // else
71
+    this._onData = fn
71 72
   }
72 73
 
73 74
   onError(fn) {

+ 1
- 0
src/ios/RNFetchBlob/RNFetchBlob.h ファイルの表示

@@ -17,6 +17,7 @@
17 17
 
18 18
 @property (nonatomic) NSString * filePathPrefix;
19 19
 
20
++ (RCTBridge *)getRCTBridge;
20 21
 
21 22
 @end
22 23
 

+ 15
- 5
src/ios/RNFetchBlob/RNFetchBlob.m ファイルの表示

@@ -14,6 +14,8 @@
14 14
 #import "RNFetchBlobReqBuilder.h"
15 15
 
16 16
 
17
+RCTBridge * bridgeRef;
18
+
17 19
 ////////////////////////////////////////
18 20
 //
19 21
 //  Exported native methods
@@ -31,6 +33,11 @@
31 33
     return dispatch_queue_create("RNFetchBlob.queue", DISPATCH_QUEUE_SERIAL);
32 34
 }
33 35
 
36
++ (RCTBridge *)getRCTBridge
37
+{
38
+    return bridgeRef;
39
+}
40
+
34 41
 RCT_EXPORT_MODULE();
35 42
 
36 43
 - (id) init {
@@ -41,6 +48,7 @@ RCT_EXPORT_MODULE();
41 48
     if(![[NSFileManager defaultManager] fileExistsAtPath: [RNFetchBlobFS getTempPath] isDirectory:&isDir]) {
42 49
         [[NSFileManager defaultManager] createDirectoryAtPath:[RNFetchBlobFS getTempPath] withIntermediateDirectories:YES attributes:nil error:NULL];
43 50
     }
51
+    bridgeRef = _bridge;
44 52
     return self;
45 53
 }
46 54
 
@@ -366,18 +374,20 @@ RCT_EXPORT_METHOD(readFile:(NSString *)path encoding:(NSString *)encoding resolv
366 374
 })
367 375
 
368 376
 #pragma mark - fs.readStream
369
-RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize) {
377
+RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize streamId:(NSString *)streamId
378
+{
370 379
 
371
-    RNFetchBlobFS *fileStream = [[RNFetchBlobFS alloc] initWithBridgeRef:self.bridge];
380
+//    RNFetchBlobFS *fileStream = [[RNFetchBlobFS alloc] initWithBridgeRef:self.bridge];
372 381
     if(bufferSize == nil) {
373 382
         if([[encoding lowercaseString] isEqualToString:@"base64"])
374 383
             bufferSize = 4095;
375 384
         else
376 385
             bufferSize = 4096;
377 386
     }
378
-    // read asset stream
379
-    [fileStream readWithPath:path useEncoding:encoding bufferSize:bufferSize];
380
-}
387
+    
388
+//    [fileStream readWithPath:path useEncoding:encoding bufferSize:bufferSize];
389
+    [RNFetchBlobFS readStream:path encoding:encoding bufferSize:bufferSize streamId:streamId bridgeRef:_bridge];
390
+})
381 391
 
382 392
 #pragma mark - fs.getEnvionmentDirs
383 393
 RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {

+ 2
- 3
src/ios/RNFetchBlobFS.h ファイルの表示

@@ -55,7 +55,7 @@
55 55
 + (void) writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
56 56
 + (void) readFile:(NSString *)path encoding:(NSString *)encoding resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject onComplete:(void (^)(NSData * content))onComplete;
57 57
 + (void) readAssetFile:(NSData *)assetUrl completionBlock:(void(^)(NSData * content))completionBlock failBlock:(void(^)(NSError * err))failBlock;
58
-+ (void)slice:(NSString *)path
58
++ (void) slice:(NSString *)path
59 59
          dest:(NSString *)dest
60 60
         start:(nonnull NSNumber *)start
61 61
           end:(nonnull NSNumber *)end
@@ -64,6 +64,7 @@
64 64
      rejecter:(RCTPromiseRejectBlock)reject;
65 65
 //+ (void) writeFileFromFile:(NSString *)src toFile:(NSString *)dest append:(BOOL)append;
66 66
 + (void) writeAssetToPath:(ALAssetRepresentation * )rep dest:(NSString *)dest;
67
++ (void) readStream:(NSString *)uri encoding:(NSString * )encoding bufferSize:(int)bufferSize streamId:(NSString *)streamId bridgeRef:(RCTBridge *)bridgeRef;
67 68
 
68 69
 // constructor
69 70
 - (id) init;
@@ -73,12 +74,10 @@
73 74
 // file stream
74 75
 - (void) openWithDestination;
75 76
 - (NSString *)openWithPath:(NSString *)destPath encode:(nullable NSString *)encode appendData:(BOOL)append;
76
-- (void) startAssetReadStream:(NSData *)assetUrl;
77 77
 
78 78
 // file stream write data
79 79
 - (void)write:(NSData *) chunk;
80 80
 - (void)writeEncodeChunk:(NSString *) chunk;
81
-- (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding bufferSize:(int) bufferSize;
82 81
 
83 82
 - (void) closeInStream;
84 83
 - (void) closeOutStream;

+ 83
- 217
src/ios/RNFetchBlobFS.m ファイルの表示

@@ -9,6 +9,7 @@
9 9
 
10 10
 #import <Foundation/Foundation.h>
11 11
 #import "RCTBridge.h"
12
+#import "RNFetchBlob.h"
12 13
 #import "RCTEventDispatcher.h"
13 14
 #import "RNFetchBlobFS.h"
14 15
 #import "RNFetchBlobConst.h"
@@ -98,93 +99,99 @@ NSMutableDictionary *fileStreams = nil;
98 99
     return tempPath;
99 100
 }
100 101
 
101
-#pragma mark - read asset stream
102
+#pragma margk - readStream 
102 103
 
103
-- (void) startAssetReadStream:(NSString *)assetUrl
104
++ (void) readStream:(NSString *)uri
105
+           encoding:(NSString * )encoding
106
+         bufferSize:(int)bufferSize
107
+           streamId:(NSString *)streamId
108
+          bridgeRef:(RCTBridge *)bridgeRef
104 109
 {
105
-    ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
106
-    {
107
-        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
108
-        dispatch_async(queue, ^ {
109
-            NSString * streamEventCode = [NSString stringWithFormat:@"RNFetchBlobStream+%@", self.path];
110
-            ALAssetRepresentation *rep = [myasset defaultRepresentation];
111
-            Byte *buffer = (Byte*)malloc(self.bufferSize);
112
-            NSUInteger cursor = [rep getBytes:buffer fromOffset:0 length:self.bufferSize error:nil];
113
-            while(cursor > 0)
110
+    [[self class] getPathFromUri:uri completionHandler:^(NSString *path, ALAssetRepresentation *asset) {
111
+    
112
+        RCTEventDispatcher * event = bridgeRef.eventDispatcher;
113
+        @try
114
+        {
115
+            int read = 0;
116
+            int chunkSize = bufferSize;
117
+            uint8_t * buffer[bufferSize];
118
+            
119
+            if(path != nil)
114 120
             {
115
-                cursor += [rep getBytes:buffer fromOffset:cursor length:self.bufferSize error:nil];
116
-                NSData * chunkData = [NSData dataWithBytes:buffer length:self.bufferSize];
117
-                NSString * encodedChunk = @"";
118
-                // emit data
119
-                if( [[self.encoding lowercaseString] isEqualToString:@"utf8"] ) {
120
-                    encodedChunk = [encodedChunk initWithData:chunkData encoding:NSUTF8StringEncoding];
121
-                }
122
-                // when encoding is ASCII, send byte array data
123
-                else if ( [[self.encoding lowercaseString] isEqualToString:@"ascii"] ) {
124
-                    // RCTBridge only emits string data, so we have to create JSON byte array string
125
-                    NSMutableArray * asciiArray = [NSMutableArray array];
126
-                    unsigned char *bytePtr;
127
-                    if (chunkData.length > 0)
128
-                    {
129
-                        bytePtr = (unsigned char *)[chunkData bytes];
130
-                        NSInteger byteLen = chunkData.length/sizeof(uint8_t);
131
-                        for (int i = 0; i < byteLen; i++)
132
-                        {
133
-                            [asciiArray addObject:[NSNumber numberWithChar:bytePtr[i]]];
134
-                        }
135
-                    }
136
-                    
137
-                    [self.bridge.eventDispatcher
138
-                     sendDeviceEventWithName:streamEventCode
139
-                     body: @{
140
-                             @"event": FS_EVENT_DATA,
141
-                             @"detail": asciiArray
142
-                             }
143
-                     ];
144
-                    return;
145
-                }
146
-                // convert byte array to base64 data chunks
147
-                else if ( [[self.encoding lowercaseString] isEqualToString:@"base64"] ) {
148
-                    encodedChunk = [chunkData base64EncodedStringWithOptions:0];
121
+                NSInputStream * stream = [[NSInputStream alloc] initWithFileAtPath:path];
122
+                [stream open];
123
+                while((read = [stream read:buffer maxLength:bufferSize]) > 0)
124
+                {
125
+                    [[self class] emitDataChunks:[NSData dataWithBytes:buffer length:read] encoding:encoding streamId:streamId event:event];
149 126
                 }
150
-                // unknown encoding, send error event
151
-                else {
152
-                    [self.bridge.eventDispatcher
153
-                     sendDeviceEventWithName:streamEventCode
154
-                     body:@{
155
-                            @"event": FS_EVENT_ERROR,
156
-                            @"detail": @"unrecognized encoding"
157
-                            }
158
-                     ];
159
-                    return;
127
+                [stream close];
128
+            }
129
+            else if (asset != nil)
130
+            {
131
+                int cursor = 0;
132
+                NSError * err;
133
+                while((read = [asset getBytes:buffer fromOffset:cursor length:bufferSize error:&err]) > 0)
134
+                {
135
+                    cursor += read;
136
+                    [[self class] emitDataChunks:[NSData dataWithBytes:buffer length:read] encoding:encoding streamId:streamId event:event];
160 137
                 }
161
-                
162
-                [self.bridge.eventDispatcher
163
-                 sendDeviceEventWithName:streamEventCode
164
-                 body:@{
165
-                        @"event": FS_EVENT_DATA,
166
-                        @"detail": encodedChunk
167
-                        }
168
-                 ];
169 138
             }
170
-            free(buffer);
171
-        });
139
+            else
140
+            {
141
+                NSDictionary * payload = @{ @"event": FS_EVENT_ERROR, @"detail": @"RNFetchBlob.readStream unable to resolve URI" };
142
+                [event sendDeviceEventWithName:streamId body:payload];
143
+            }
144
+        }
145
+        @catch (NSError * err)
146
+        {
147
+            
148
+            NSDictionary * payload = @{ @"event": FS_EVENT_ERROR, @"detail": [NSString stringWithFormat:@"RNFetchBlob.readStream error %@", [err description]] };
149
+            [event sendDeviceEventWithName:streamId body:payload];
150
+        }
151
+        @finally
152
+        {
153
+            NSDictionary * payload = @{ @"event": FS_EVENT_END, @"detail": @"" };
154
+            [event sendDeviceEventWithName:streamId body:payload];
155
+        }
172 156
         
173
-    };
157
+    }];
174 158
     
175
-    ALAssetsLibraryAccessFailureBlock failureblock  = ^(NSError *error)
159
+}
160
+
161
+// send read stream chunks via native event emitter
162
++ (void) emitDataChunks:(NSData *)data encoding:(NSString *) encoding streamId:(NSString *)streamId event:(RCTEventDispatcher *)event
163
+{
164
+    NSString * encodedChunk = @"";
165
+    if([[encoding lowercaseString] isEqualToString:@"utf8"])
176 166
     {
177
-        
178
-    };
179
-    
180
-    if(assetUrl && [assetUrl length])
167
+        NSDictionary * payload = @{ @"event": FS_EVENT_DATA,  @"detail" : [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] };
168
+        [event sendDeviceEventWithName:streamId body:payload];
169
+    }
170
+    else if ([[encoding lowercaseString] isEqualToString:@"base64"])
181 171
     {
182
-        NSURL *asseturl = [NSURL URLWithString:assetUrl];
183
-        ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
184
-        [assetslibrary assetForURL:asseturl
185
-                       resultBlock:resultblock
186
-                      failureBlock:failureblock];
172
+        NSDictionary * payload = @{ @"event": FS_EVENT_DATA,  @"detail" : [data base64EncodedStringWithOptions:0] };
173
+        [event sendDeviceEventWithName:streamId body:payload];
187 174
     }
175
+    else if([[encoding lowercaseString] isEqualToString:@"ascii"])
176
+    {
177
+        // RCTBridge only emits string data, so we have to create JSON byte array string
178
+        NSMutableArray * asciiArray = [NSMutableArray array];
179
+        unsigned char *bytePtr;
180
+        if (data.length > 0)
181
+        {
182
+            bytePtr = (unsigned char *)[data bytes];
183
+            NSInteger byteLen = data.length/sizeof(uint8_t);
184
+            for (int i = 0; i < byteLen; i++)
185
+            {
186
+                [asciiArray addObject:[NSNumber numberWithChar:bytePtr[i]]];
187
+            }
188
+        }
189
+
190
+        NSDictionary * payload = @{ @"event": FS_EVENT_DATA,  @"detail" : asciiArray };
191
+        [event sendDeviceEventWithName:streamId body:payload];
192
+    }
193
+    
194
+    
188 195
 }
189 196
 
190 197
 # pragma write file from file
@@ -544,35 +551,6 @@ NSMutableDictionary *fileStreams = nil;
544 551
     
545 552
 }
546 553
 
547
-- (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding bufferSize:(int) bufferSize {
548
-    
549
-    self.inStream = [[NSInputStream alloc] initWithFileAtPath:path];
550
-    self.inStream.delegate = self;
551
-    self.encoding = encoding;
552
-    self.path = path;
553
-    self.bufferSize = bufferSize;
554
-    
555
-    if([path hasPrefix:AL_PREFIX])
556
-    {
557
-        [self startAssetReadStream:path];
558
-        return;
559
-    }
560
-    
561
-    // normalize file path
562
-    path = [[self class] getPathOfAsset:path];
563
-    
564
-    // NSStream needs a runloop so let's create a run loop for it
565
-    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
566
-    // start NSStream is a runloop
567
-    dispatch_async(queue, ^ {
568
-        [inStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
569
-                            forMode:NSDefaultRunLoopMode];
570
-        [inStream open];
571
-        [[NSRunLoop currentRunLoop] run];
572
-        
573
-    });
574
-}
575
-
576 554
 // Slice a file into another file, generally for support Blob implementation.
577 555
 + (void)slice:(NSString *)path
578 556
          dest:(NSString *)dest
@@ -690,118 +668,6 @@ NSMutableDictionary *fileStreams = nil;
690 668
     
691 669
 }
692 670
 
693
-#pragma mark RNFetchBlobFS read stream delegate
694
-
695
-- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
696
-    
697
-    NSString * streamEventCode = [NSString stringWithFormat:@"RNFetchBlobStream+%@", self.path];
698
-    
699
-    switch(eventCode) {
700
-            
701
-            // write stream event
702
-        case NSStreamEventHasSpaceAvailable:
703
-        {
704
-            
705
-            
706
-        }
707
-            
708
-            // read stream incoming chunk
709
-        case NSStreamEventHasBytesAvailable:
710
-        {
711
-            NSMutableData * chunkData = [[NSMutableData alloc] init];
712
-            NSInteger chunkSize = 4096;
713
-            if([[self.encoding lowercaseString] isEqualToString:@"base64"])
714
-                chunkSize = 4095;
715
-            if(self.bufferSize > 0)
716
-                chunkSize = self.bufferSize;
717
-            uint8_t buf[chunkSize];
718
-            unsigned int len = 0;
719
-            len = [(NSInputStream *)stream read:buf maxLength:chunkSize];
720
-            // still have data in stream
721
-            if(len) {
722
-                [chunkData appendBytes:buf length:len];
723
-                // dispatch data event
724
-                NSString * encodedChunk = [NSString alloc];
725
-                if( [[self.encoding lowercaseString] isEqualToString:@"utf8"] ) {
726
-                    encodedChunk = [encodedChunk initWithData:chunkData encoding:NSUTF8StringEncoding];
727
-                }
728
-                // when encoding is ASCII, send byte array data
729
-                else if ( [[self.encoding lowercaseString] isEqualToString:@"ascii"] ) {
730
-                    // RCTBridge only emits string data, so we have to create JSON byte array string
731
-                    NSMutableArray * asciiArray = [NSMutableArray array];
732
-                    unsigned char *bytePtr;
733
-                    if (chunkData.length > 0)
734
-                    {
735
-                        bytePtr = (unsigned char *)[chunkData bytes];
736
-                        NSInteger byteLen = chunkData.length/sizeof(uint8_t);
737
-                        for (int i = 0; i < byteLen; i++)
738
-                        {
739
-                            [asciiArray addObject:[NSNumber numberWithChar:bytePtr[i]]];
740
-                        }
741
-                    }
742
-                    
743
-                    [self.bridge.eventDispatcher
744
-                     sendDeviceEventWithName:streamEventCode
745
-                     body: @{
746
-                             @"event": FS_EVENT_DATA,
747
-                             @"detail": asciiArray
748
-                             }
749
-                     ];
750
-                    return;
751
-                }
752
-                // convert byte array to base64 data chunks
753
-                else if ( [[self.encoding lowercaseString] isEqualToString:@"base64"] ) {
754
-                    encodedChunk = [chunkData base64EncodedStringWithOptions:0];
755
-                }
756
-                // unknown encoding, send error event
757
-                else {
758
-                    [self.bridge.eventDispatcher
759
-                     sendDeviceEventWithName:streamEventCode
760
-                     body:@{
761
-                            @"event": FS_EVENT_ERROR,
762
-                            @"detail": @"unrecognized encoding"
763
-                            }
764
-                     ];
765
-                    return;
766
-                }
767
-                
768
-                [self.bridge.eventDispatcher
769
-                 sendDeviceEventWithName:streamEventCode
770
-                 body:@{
771
-                        @"event": FS_EVENT_DATA,
772
-                        @"detail": encodedChunk
773
-                        }
774
-                 ];
775
-            }
776
-            // end of stream
777
-            else {
778
-                [self.bridge.eventDispatcher
779
-                 sendDeviceEventWithName:streamEventCode
780
-                 body:@{
781
-                        @"event": FS_EVENT_END,
782
-                        @"detail": @""
783
-                        }
784
-                 ];
785
-            }
786
-            break;
787
-        }
788
-            
789
-            // stream error
790
-        case NSStreamEventErrorOccurred:
791
-        {
792
-            [self.bridge.eventDispatcher
793
-             sendDeviceEventWithName:streamEventCode
794
-             body:@{
795
-                    @"event": FS_EVENT_ERROR,
796
-                    @"detail": @"RNFetchBlob error when read file with stream, file may not exists"
797
-                    }
798
-             ];
799
-            break;
800
-        }
801
-            
802
-    }
803
-    
804
-}
805 671
 
806 672
 # pragma mark - get absolute path of resource
807 673