|
@@ -42,13 +42,12 @@ NSString *const FS_EVENT_ERROR = @"error";
|
42
|
42
|
|
43
|
43
|
|
44
|
44
|
|
45
|
|
-+ (NSString *) getCacheDir {
|
46
|
45
|
|
|
46
|
++ (NSString *) getCacheDir {
|
47
|
47
|
return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
|
48
|
48
|
}
|
49
|
49
|
|
50
|
50
|
+ (NSString *) getDocumentDir {
|
51
|
|
-
|
52
|
51
|
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
53
|
52
|
}
|
54
|
53
|
|
|
@@ -75,6 +74,12 @@ NSString *const FS_EVENT_ERROR = @"error";
|
75
|
74
|
return tempPath;
|
76
|
75
|
}
|
77
|
76
|
|
|
77
|
+- (id)init {
|
|
78
|
+ self = [super init];
|
|
79
|
+ return self;
|
|
80
|
+}
|
|
81
|
+
|
|
82
|
+
|
78
|
83
|
- (id)initWithCallback:(RCTResponseSenderBlock)callback {
|
79
|
84
|
self = [super init];
|
80
|
85
|
self.callback = callback;
|
|
@@ -83,12 +88,13 @@ NSString *const FS_EVENT_ERROR = @"error";
|
83
|
88
|
|
84
|
89
|
- (id)initWithBridgeRef:(RCTBridge *)bridgeRef {
|
85
|
90
|
self = [super init];
|
86
|
|
- self.callback = callback;
|
|
91
|
+ self.bridge = bridgeRef;
|
87
|
92
|
return self;
|
88
|
93
|
}
|
89
|
94
|
|
90
|
95
|
- (void)openWithPath:(NSString *)destPath {
|
91
|
96
|
self.outStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:YES];
|
|
97
|
+ [self.outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
92
|
98
|
[self.outStream open];
|
93
|
99
|
}
|
94
|
100
|
|
|
@@ -108,13 +114,25 @@ NSString *const FS_EVENT_ERROR = @"error";
|
108
|
114
|
}
|
109
|
115
|
|
110
|
116
|
- (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding {
|
111
|
|
- self.inStream = [[NSInputStream alloc]init];
|
|
117
|
+
|
|
118
|
+ self.inStream = [[NSInputStream alloc] initWithFileAtPath:path];
|
|
119
|
+ self.inStream.delegate = self;
|
112
|
120
|
self.encoding = encoding;
|
113
|
|
- [self.inStream setDelegate:self];
|
|
121
|
+ self.path = path;
|
|
122
|
+
|
|
123
|
+ // NSStream needs a runloop so let's create a run loop for it
|
|
124
|
+ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
|
|
125
|
+ // start NSStream is a runloop
|
|
126
|
+ dispatch_async(queue, ^ {
|
|
127
|
+ [inStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
|
|
128
|
+ forMode:NSDefaultRunLoopMode];
|
|
129
|
+ [inStream open];
|
|
130
|
+ [[NSRunLoop currentRunLoop] run];
|
|
131
|
+
|
|
132
|
+ });
|
114
|
133
|
|
115
|
134
|
}
|
116
|
135
|
|
117
|
|
-
|
118
|
136
|
// close file write stream
|
119
|
137
|
- (void)closeOutStream {
|
120
|
138
|
if(self.outStream != nil) {
|
|
@@ -133,10 +151,25 @@ NSString *const FS_EVENT_ERROR = @"error";
|
133
|
151
|
|
134
|
152
|
}
|
135
|
153
|
|
|
154
|
+void runOnMainQueueWithoutDeadlocking(void (^block)(void))
|
|
155
|
+{
|
|
156
|
+ if ([NSThread isMainThread])
|
|
157
|
+ {
|
|
158
|
+ block();
|
|
159
|
+ }
|
|
160
|
+ else
|
|
161
|
+ {
|
|
162
|
+ dispatch_sync(dispatch_get_main_queue(), block);
|
|
163
|
+ }
|
|
164
|
+}
|
|
165
|
+
|
|
166
|
+
|
136
|
167
|
#pragma mark RNFetchBlobFS read stream delegate
|
137
|
168
|
|
138
|
169
|
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
|
139
|
170
|
|
|
171
|
+ NSString * streamEventCode = [NSString stringWithFormat:@"RNFetchBlobStream+%@", self.path];
|
|
172
|
+
|
140
|
173
|
switch(eventCode) {
|
141
|
174
|
|
142
|
175
|
// write stream event
|
|
@@ -149,10 +182,7 @@ NSString *const FS_EVENT_ERROR = @"error";
|
149
|
182
|
// read stream incoming chunk
|
150
|
183
|
case NSStreamEventHasBytesAvailable:
|
151
|
184
|
{
|
152
|
|
-
|
153
|
|
-
|
154
|
185
|
NSMutableData * chunkData = [[NSMutableData data] init];
|
155
|
|
-
|
156
|
186
|
uint8_t buf[1024];
|
157
|
187
|
unsigned int len = 0;
|
158
|
188
|
len = [(NSInputStream *)stream read:buf maxLength:1024];
|
|
@@ -160,41 +190,41 @@ NSString *const FS_EVENT_ERROR = @"error";
|
160
|
190
|
if(len) {
|
161
|
191
|
[chunkData appendBytes:(const void *)buf length:len];
|
162
|
192
|
// TODO : file read progress ?
|
163
|
|
-// [bytesRead setIntValue:[bytesRead intValue]+len];
|
164
|
|
-
|
165
|
193
|
// dispatch data event
|
166
|
|
- NSString * encodedChunk = [NSString alloc];
|
167
|
|
- if( [self.encoding caseInsensitiveCompare:@"utf8"] ) {
|
|
194
|
+ NSString * encodedChunk;
|
|
195
|
+ if( [[self.encoding lowercaseString] isEqualToString:@"utf8"] ) {
|
168
|
196
|
encodedChunk = [encodedChunk initWithData:chunkData encoding:NSUTF8StringEncoding];
|
169
|
197
|
}
|
170
|
|
- else if ( [self.encoding caseInsensitiveCompare:@"ascii"] ) {
|
|
198
|
+ else if ( [[self.encoding lowercaseString] isEqualToString:@"ascii"] ) {
|
171
|
199
|
encodedChunk = [encodedChunk initWithData:chunkData encoding:NSASCIIStringEncoding];
|
172
|
200
|
}
|
173
|
|
- else if ( [self.encoding caseInsensitiveCompare:@"base64"] ) {
|
|
201
|
+ else if ( [[self.encoding lowercaseString] isEqualToString:@"base64"] ) {
|
174
|
202
|
encodedChunk = [chunkData base64EncodedStringWithOptions:0];
|
175
|
203
|
}
|
176
|
204
|
else {
|
177
|
205
|
[self.bridge.eventDispatcher
|
178
|
|
- sendAppEventWithName: [NSString stringWithFormat:@"RNFetchBlobStream%s", self.taskId]
|
179
|
|
- body:@{
|
|
206
|
+ sendDeviceEventWithName:streamEventCode
|
|
207
|
+ body:@{
|
180
|
208
|
@"event": FS_EVENT_ERROR,
|
181
|
209
|
@"detail": @"unrecognized encoding"
|
182
|
210
|
}
|
183
|
211
|
];
|
184
|
212
|
return;
|
185
|
213
|
}
|
186
|
|
- [self.bridge.eventDispatcher
|
187
|
|
- sendAppEventWithName: [NSString stringWithFormat:@"RNFetchBlobStream%s", self.taskId]
|
188
|
|
- body:@{
|
189
|
|
- @"event": FS_EVENT_DATA,
|
190
|
|
- @"detail": encodedChunk
|
191
|
|
- }
|
192
|
|
- ];
|
|
214
|
+ runOnMainQueueWithoutDeadlocking(^{
|
|
215
|
+ [self.bridge.eventDispatcher
|
|
216
|
+ sendDeviceEventWithName:streamEventCode
|
|
217
|
+ body:@{
|
|
218
|
+ @"event": FS_EVENT_DATA,
|
|
219
|
+ @"detail": encodedChunk
|
|
220
|
+ }
|
|
221
|
+ ];
|
|
222
|
+ });
|
193
|
223
|
}
|
194
|
224
|
// end of stream
|
195
|
225
|
else {
|
196
|
226
|
[self.bridge.eventDispatcher
|
197
|
|
- sendAppEventWithName: [NSString stringWithFormat:@"RNFetchBlobStream%s", self.taskId]
|
|
227
|
+ sendDeviceEventWithName:streamEventCode
|
198
|
228
|
body:@{
|
199
|
229
|
@"event": FS_EVENT_END,
|
200
|
230
|
@"detail": @""
|
|
@@ -208,7 +238,7 @@ NSString *const FS_EVENT_ERROR = @"error";
|
208
|
238
|
case NSStreamEventErrorOccurred:
|
209
|
239
|
{
|
210
|
240
|
[self.bridge.eventDispatcher
|
211
|
|
- sendAppEventWithName: [NSString stringWithFormat:@"RNFetchBlobStream%s", self.taskId]
|
|
241
|
+ sendDeviceEventWithName:streamEventCode
|
212
|
242
|
body:@{
|
213
|
243
|
@"event": FS_EVENT_ERROR,
|
214
|
244
|
@"detail": @"error when read file with stream"
|
|
@@ -318,7 +348,7 @@ NSString *const FS_EVENT_ERROR = @"error";
|
318
|
348
|
}
|
319
|
349
|
|
320
|
350
|
[self.bridge.eventDispatcher
|
321
|
|
- sendAppEventWithName:@"RNFetchBlobProgress"
|
|
351
|
+ sendDeviceEventWithName:@"RNFetchBlobProgress"
|
322
|
352
|
body:@{
|
323
|
353
|
@"taskId": taskId,
|
324
|
354
|
@"written": [NSString stringWithFormat:@"%d", receivedBytes],
|
|
@@ -332,7 +362,7 @@ NSString *const FS_EVENT_ERROR = @"error";
|
332
|
362
|
expectedBytes = totalBytesExpectedToWrite;
|
333
|
363
|
receivedBytes += totalBytesWritten;
|
334
|
364
|
[self.bridge.eventDispatcher
|
335
|
|
- sendAppEventWithName:@"RNFetchBlobProgress"
|
|
365
|
+ sendDeviceEventWithName:@"RNFetchBlobProgress"
|
336
|
366
|
body:@{
|
337
|
367
|
@"taskId": taskId,
|
338
|
368
|
@"written": [NSString stringWithFormat:@"%d", receivedBytes],
|