|
@@ -7,541 +7,11 @@
|
7
|
7
|
#import "RNFetchBlob.h"
|
8
|
8
|
#import "RCTConvert.h"
|
9
|
9
|
#import "RCTLog.h"
|
10
|
|
-#import <Foundation/Foundation.h>
|
11
|
10
|
#import "RCTBridge.h"
|
12
|
11
|
#import "RCTEventDispatcher.h"
|
13
|
|
-
|
14
|
|
-NSString *const FILE_PREFIX = @"RNFetchBlob-file://";
|
15
|
|
-
|
16
|
|
-// fetch configs
|
17
|
|
-NSString *const CONFIG_USE_TEMP = @"fileCache";
|
18
|
|
-NSString *const CONFIG_FILE_PATH = @"path";
|
19
|
|
-NSString *const CONFIG_FILE_EXT = @"appendExt";
|
20
|
|
-
|
21
|
|
-NSString *const MSG_EVENT = @"RNFetchBlobMessage";
|
22
|
|
-NSString *const MSG_EVENT_LOG = @"log";
|
23
|
|
-NSString *const MSG_EVENT_WARN = @"warn";
|
24
|
|
-NSString *const MSG_EVENT_ERROR = @"error";
|
25
|
|
-NSString *const FS_EVENT_DATA = @"data";
|
26
|
|
-NSString *const FS_EVENT_END = @"end";
|
27
|
|
-NSString *const FS_EVENT_WARN = @"warn";
|
28
|
|
-NSString *const FS_EVENT_ERROR = @"error";
|
29
|
|
-NSMutableDictionary *fileStreams = nil;
|
30
|
|
-
|
31
|
|
-////////////////////////////////////////
|
32
|
|
-//
|
33
|
|
-// File system access methods
|
34
|
|
-//
|
35
|
|
-////////////////////////////////////////
|
36
|
|
-
|
37
|
|
-@implementation FetchBlobFS
|
38
|
|
-
|
39
|
|
-
|
40
|
|
-@synthesize outStream;
|
41
|
|
-@synthesize inStream;
|
42
|
|
-@synthesize encoding;
|
43
|
|
-@synthesize callback;
|
44
|
|
-@synthesize taskId;
|
45
|
|
-@synthesize path;
|
46
|
|
-@synthesize appendData;
|
47
|
|
-@synthesize bufferSize;
|
48
|
|
-
|
49
|
|
-// static member getter
|
50
|
|
-+ (NSArray *) getFileStreams {
|
51
|
|
-
|
52
|
|
- if(fileStreams == nil)
|
53
|
|
- fileStreams = [[NSMutableDictionary alloc] init];
|
54
|
|
- return fileStreams;
|
55
|
|
-}
|
56
|
|
-
|
57
|
|
-+(void) setFileStream:(FetchBlobFS *) instance withId:(NSString *) uuid {
|
58
|
|
- if(fileStreams == nil)
|
59
|
|
- fileStreams = [[NSMutableDictionary alloc] init];
|
60
|
|
- [fileStreams setValue:instance forKey:uuid];
|
61
|
|
-}
|
62
|
|
-
|
63
|
|
-+ (NSString *) getCacheDir {
|
64
|
|
- return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
|
65
|
|
-}
|
66
|
|
-
|
67
|
|
-+ (NSString *) getDocumentDir {
|
68
|
|
- return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
69
|
|
-}
|
70
|
|
-
|
71
|
|
-+ (NSString *) getMusicDir {
|
72
|
|
- return [NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) firstObject];
|
73
|
|
-}
|
74
|
|
-
|
75
|
|
-+ (NSString *) getMovieDir {
|
76
|
|
- return [NSSearchPathForDirectoriesInDomains(NSMoviesDirectory, NSUserDomainMask, YES) firstObject];
|
77
|
|
-}
|
78
|
|
-
|
79
|
|
-+ (NSString *) getPictureDir {
|
80
|
|
- return [NSSearchPathForDirectoriesInDomains(NSPicturesDirectory, NSUserDomainMask, YES) firstObject];
|
81
|
|
-}
|
82
|
|
-
|
83
|
|
-
|
84
|
|
-+ (NSString *) getTempPath {
|
85
|
|
-
|
86
|
|
- return [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingString:@"/RNFetchBlob_tmp"];
|
87
|
|
-}
|
88
|
|
-
|
89
|
|
-+ (NSString *) getTempPath:(NSString*)taskId withExtension:(NSString *)ext {
|
90
|
|
-
|
91
|
|
- NSString * documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
92
|
|
- NSString * filename = [NSString stringWithFormat:@"/RNFetchBlob_tmp/RNFetchBlobTmp_%@", taskId];
|
93
|
|
- if(ext != nil)
|
94
|
|
- filename = [filename stringByAppendingString: [NSString stringWithFormat:@".%@", ext]];
|
95
|
|
- NSString * tempPath = [documentDir stringByAppendingString: filename];
|
96
|
|
- return tempPath;
|
97
|
|
-}
|
98
|
|
-
|
99
|
|
-+ (BOOL) mkdir:(NSString *) path {
|
100
|
|
- BOOL isDir;
|
101
|
|
- NSError * err = nil;
|
102
|
|
- // if temp folder not exists, create one
|
103
|
|
- if(![[NSFileManager defaultManager] fileExistsAtPath: path isDirectory:&isDir]) {
|
104
|
|
- [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&err];
|
105
|
|
- }
|
106
|
|
- return err == nil;
|
107
|
|
-}
|
108
|
|
-
|
109
|
|
-+ (NSDictionary *) stat:(NSString *) path error:(NSError **) error{
|
110
|
|
- NSMutableDictionary *stat = [[NSMutableDictionary alloc] init];
|
111
|
|
- BOOL isDir = NO;
|
112
|
|
- NSFileManager * fm = [NSFileManager defaultManager];
|
113
|
|
- if([fm fileExistsAtPath:path isDirectory:&isDir] == NO) {
|
114
|
|
- return nil;
|
115
|
|
- }
|
116
|
|
- NSDictionary * info = [fm attributesOfItemAtPath:path error:&error];
|
117
|
|
- NSString * size = [NSString stringWithFormat:@"%d", [info fileSize]];
|
118
|
|
- NSString * filename = [path lastPathComponent];
|
119
|
|
- NSDate * lastModified;
|
120
|
|
- [[NSURL fileURLWithPath:path] getResourceValue:&lastModified forKey:NSURLContentModificationDateKey error:&error];
|
121
|
|
- return @{
|
122
|
|
- @"size" : size,
|
123
|
|
- @"filename" : filename,
|
124
|
|
- @"path" : path,
|
125
|
|
- @"lastModified" : [NSString stringWithFormat:@"%d", [lastModified timeIntervalSince1970]],
|
126
|
|
- @"type" : isDir ? @"directory" : @"file"
|
127
|
|
- };
|
128
|
|
-}
|
129
|
|
-
|
130
|
|
-+ (BOOL) exists:(NSString *) path {
|
131
|
|
- return [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:NULL];
|
132
|
|
-}
|
133
|
|
-
|
134
|
|
-- (id)init {
|
135
|
|
- self = [super init];
|
136
|
|
- return self;
|
137
|
|
-}
|
138
|
|
-
|
139
|
|
-- (id)initWithCallback:(RCTResponseSenderBlock)callback {
|
140
|
|
- self = [super init];
|
141
|
|
- self.callback = callback;
|
142
|
|
- return self;
|
143
|
|
-}
|
144
|
|
-
|
145
|
|
-- (id)initWithBridgeRef:(RCTBridge *)bridgeRef {
|
146
|
|
- self = [super init];
|
147
|
|
- self.bridge = bridgeRef;
|
148
|
|
- return self;
|
149
|
|
-}
|
150
|
|
-
|
151
|
|
-// Create file stream for write data
|
152
|
|
-- (NSString *)openWithPath:(NSString *)destPath encode:(nullable NSString *)encode appendData:(BOOL)append {
|
153
|
|
- self.outStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:append];
|
154
|
|
- self.encoding = encode;
|
155
|
|
- [self.outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
156
|
|
- [self.outStream open];
|
157
|
|
- NSString *uuid = [[NSUUID UUID] UUIDString];
|
158
|
|
- self.streamId = uuid;
|
159
|
|
- [FetchBlobFS setFileStream:self withId:uuid];
|
160
|
|
- return uuid;
|
161
|
|
-}
|
162
|
|
-
|
163
|
|
-// Write file chunk into an opened stream
|
164
|
|
-- (void)writeEncodeChunk:(NSString *) chunk {
|
165
|
|
- NSMutableData * decodedData = [NSData alloc];
|
166
|
|
- if([[self.encoding lowercaseString] isEqualToString:@"base64"]) {
|
167
|
|
- decodedData = [[NSData alloc] initWithBase64EncodedData:chunk options:0];
|
168
|
|
- }
|
169
|
|
- if([[self.encoding lowercaseString] isEqualToString:@"utf8"]) {
|
170
|
|
- decodedData = [chunk dataUsingEncoding:NSUTF8StringEncoding];
|
171
|
|
- }
|
172
|
|
- else if([[self.encoding lowercaseString] isEqualToString:@"ascii"]) {
|
173
|
|
- decodedData = [chunk dataUsingEncoding:NSASCIIStringEncoding];
|
174
|
|
- }
|
175
|
|
- NSUInteger left = [decodedData length];
|
176
|
|
- NSUInteger nwr = 0;
|
177
|
|
- do {
|
178
|
|
- nwr = [self.outStream write:[decodedData bytes] maxLength:left];
|
179
|
|
- if (-1 == nwr) break;
|
180
|
|
- left -= nwr;
|
181
|
|
- } while (left > 0);
|
182
|
|
- if (left) {
|
183
|
|
- NSLog(@"stream error: %@", [self.outStream streamError]);
|
184
|
|
- }
|
185
|
|
-}
|
186
|
|
-
|
187
|
|
-// Write file chunk into an opened stream
|
188
|
|
-- (void)write:(NSData *) chunk {
|
189
|
|
- NSUInteger left = [chunk length];
|
190
|
|
- NSUInteger nwr = 0;
|
191
|
|
- do {
|
192
|
|
- nwr = [self.outStream write:[chunk bytes] maxLength:left];
|
193
|
|
- if (-1 == nwr) break;
|
194
|
|
- left -= nwr;
|
195
|
|
- } while (left > 0);
|
196
|
|
- if (left) {
|
197
|
|
- NSLog(@"stream error: %@", [self.outStream streamError]);
|
198
|
|
- }
|
199
|
|
-}
|
200
|
|
-
|
201
|
|
-// close file write stream
|
202
|
|
-- (void)closeOutStream {
|
203
|
|
- if(self.outStream != nil) {
|
204
|
|
- [self.outStream close];
|
205
|
|
- self.outStream = nil;
|
206
|
|
- }
|
207
|
|
-
|
208
|
|
-}
|
209
|
|
-
|
210
|
|
-- (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding bufferSize:(int) bufferSize{
|
211
|
|
-
|
212
|
|
- self.inStream = [[NSInputStream alloc] initWithFileAtPath:path];
|
213
|
|
- self.inStream.delegate = self;
|
214
|
|
- self.encoding = encoding;
|
215
|
|
- self.path = path;
|
216
|
|
- self.bufferSize = bufferSize;
|
217
|
|
-
|
218
|
|
- // NSStream needs a runloop so let's create a run loop for it
|
219
|
|
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
|
220
|
|
- // start NSStream is a runloop
|
221
|
|
- dispatch_async(queue, ^ {
|
222
|
|
- [inStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
|
223
|
|
- forMode:NSDefaultRunLoopMode];
|
224
|
|
- [inStream open];
|
225
|
|
- [[NSRunLoop currentRunLoop] run];
|
226
|
|
-
|
227
|
|
- });
|
228
|
|
-}
|
229
|
|
-
|
230
|
|
-// close file read stream
|
231
|
|
-- (void)closeInStream {
|
232
|
|
- if(self.inStream != nil) {
|
233
|
|
- [self.inStream close];
|
234
|
|
- [self.inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
235
|
|
- [[FetchBlobFS getFileStreams] setValue:nil forKey:self.streamId];
|
236
|
|
- self.streamId = nil;
|
237
|
|
- }
|
238
|
|
-
|
239
|
|
-}
|
240
|
|
-
|
241
|
|
-void runOnMainQueueWithoutDeadlocking(void (^block)(void))
|
242
|
|
-{
|
243
|
|
- if ([NSThread isMainThread])
|
244
|
|
- {
|
245
|
|
- block();
|
246
|
|
- }
|
247
|
|
- else
|
248
|
|
- {
|
249
|
|
- dispatch_sync(dispatch_get_main_queue(), block);
|
250
|
|
- }
|
251
|
|
-}
|
252
|
|
-
|
253
|
|
-
|
254
|
|
-#pragma mark RNFetchBlobFS read stream delegate
|
255
|
|
-
|
256
|
|
-- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
|
257
|
|
-
|
258
|
|
- NSString * streamEventCode = [NSString stringWithFormat:@"RNFetchBlobStream+%@", self.path];
|
259
|
|
-
|
260
|
|
- switch(eventCode) {
|
261
|
|
-
|
262
|
|
- // write stream event
|
263
|
|
- case NSStreamEventHasSpaceAvailable:
|
264
|
|
- {
|
265
|
|
-
|
266
|
|
-
|
267
|
|
- }
|
268
|
|
-
|
269
|
|
- // read stream incoming chunk
|
270
|
|
- case NSStreamEventHasBytesAvailable:
|
271
|
|
- {
|
272
|
|
- NSMutableData * chunkData = [[NSMutableData data] init];
|
273
|
|
- NSInteger chunkSize = 4096;
|
274
|
|
- if([[self.encoding lowercaseString] isEqualToString:@"base64"])
|
275
|
|
- chunkSize = 4095;
|
276
|
|
- if(self.bufferSize > 0)
|
277
|
|
- chunkSize = self.bufferSize;
|
278
|
|
- uint8_t buf[chunkSize];
|
279
|
|
- unsigned int len = 0;
|
280
|
|
-
|
281
|
|
- len = [(NSInputStream *)stream read:buf maxLength:chunkSize];
|
282
|
|
- // still have data in stream
|
283
|
|
- if(len) {
|
284
|
|
- [chunkData appendBytes:(const void *)buf length:len];
|
285
|
|
- // dispatch data event
|
286
|
|
- NSString * encodedChunk = [NSString alloc];
|
287
|
|
- if( [[self.encoding lowercaseString] isEqualToString:@"utf8"] ) {
|
288
|
|
- encodedChunk = [encodedChunk initWithData:chunkData encoding:NSUTF8StringEncoding];
|
289
|
|
- }
|
290
|
|
- // when encoding is ASCII, send byte array data
|
291
|
|
- else if ( [[self.encoding lowercaseString] isEqualToString:@"ascii"] ) {
|
292
|
|
- // RCTBridge only emits string data, so we have to create JSON byte array string
|
293
|
|
- NSString * asciiStr = @"[";
|
294
|
|
- if (chunkData.length > 0)
|
295
|
|
- {
|
296
|
|
- unsigned char *bytePtr = (unsigned char *)[chunkData bytes];
|
297
|
|
- NSInteger byteLen = chunkData.length/sizeof(uint8_t);
|
298
|
|
- for (int i = 0; i < byteLen; i++)
|
299
|
|
- {
|
300
|
|
- uint8_t * byteFromArray = chunkData.bytes;
|
301
|
|
- NSInteger val = bytePtr[i];
|
302
|
|
- if(i+1 < byteLen)
|
303
|
|
- asciiStr = [asciiStr stringByAppendingFormat:@"%d,", val];
|
304
|
|
- else
|
305
|
|
- asciiStr = [asciiStr stringByAppendingFormat:@"%d", val];
|
306
|
|
- }
|
307
|
|
- }
|
308
|
|
- asciiStr = [asciiStr stringByAppendingString:@"]"];
|
309
|
|
- [self.bridge.eventDispatcher
|
310
|
|
- sendDeviceEventWithName:streamEventCode
|
311
|
|
- body:@{
|
312
|
|
- @"event": FS_EVENT_DATA,
|
313
|
|
- @"detail": asciiStr
|
314
|
|
- }
|
315
|
|
- ];
|
316
|
|
- return;
|
317
|
|
- }
|
318
|
|
- // convert byte array to base64 data chunks
|
319
|
|
- else if ( [[self.encoding lowercaseString] isEqualToString:@"base64"] ) {
|
320
|
|
- encodedChunk = [chunkData base64EncodedStringWithOptions:0];
|
321
|
|
- }
|
322
|
|
- // unknown encoding, send erro event
|
323
|
|
- else {
|
324
|
|
- [self.bridge.eventDispatcher
|
325
|
|
- sendDeviceEventWithName:streamEventCode
|
326
|
|
- body:@{
|
327
|
|
- @"event": FS_EVENT_ERROR,
|
328
|
|
- @"detail": @"unrecognized encoding"
|
329
|
|
- }
|
330
|
|
- ];
|
331
|
|
- return;
|
332
|
|
- }
|
333
|
|
-
|
334
|
|
- [self.bridge.eventDispatcher
|
335
|
|
- sendDeviceEventWithName:streamEventCode
|
336
|
|
- body:@{
|
337
|
|
- @"event": FS_EVENT_DATA,
|
338
|
|
- @"detail": encodedChunk
|
339
|
|
- }
|
340
|
|
- ];
|
341
|
|
-
|
342
|
|
- }
|
343
|
|
- // end of stream
|
344
|
|
- else {
|
345
|
|
- [self.bridge.eventDispatcher
|
346
|
|
- sendDeviceEventWithName:streamEventCode
|
347
|
|
- body:@{
|
348
|
|
- @"event": FS_EVENT_END,
|
349
|
|
- @"detail": @""
|
350
|
|
- }
|
351
|
|
- ];
|
352
|
|
- }
|
353
|
|
- break;
|
354
|
|
- }
|
355
|
|
-
|
356
|
|
- // stream error
|
357
|
|
- case NSStreamEventErrorOccurred:
|
358
|
|
- {
|
359
|
|
- [self.bridge.eventDispatcher
|
360
|
|
- sendDeviceEventWithName:streamEventCode
|
361
|
|
- body:@{
|
362
|
|
- @"event": FS_EVENT_ERROR,
|
363
|
|
- @"detail": @"RNFetchBlob error when read file with stream, file may not exists"
|
364
|
|
- }
|
365
|
|
- ];
|
366
|
|
- break;
|
367
|
|
- }
|
368
|
|
-
|
369
|
|
- }
|
370
|
|
-
|
371
|
|
-}
|
372
|
|
-
|
373
|
|
-@end
|
374
|
|
-
|
375
|
|
-////////////////////////////////////////
|
376
|
|
-//
|
377
|
|
-// HTTP request handler
|
378
|
|
-//
|
379
|
|
-////////////////////////////////////////
|
380
|
|
-
|
381
|
|
-@implementation FetchBlobUtils
|
382
|
|
-
|
383
|
|
-
|
384
|
|
-@synthesize taskId;
|
385
|
|
-@synthesize expectedBytes;
|
386
|
|
-@synthesize receivedBytes;
|
387
|
|
-@synthesize respData;
|
388
|
|
-@synthesize callback;
|
389
|
|
-@synthesize bridge;
|
390
|
|
-@synthesize options;
|
391
|
|
-
|
392
|
|
-
|
393
|
|
-// removing case from headers
|
394
|
|
-+ (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers {
|
395
|
|
-
|
396
|
|
- NSMutableDictionary * mheaders = [[NSMutableDictionary alloc]init];
|
397
|
|
- for(NSString * key in headers) {
|
398
|
|
- [mheaders setValue:[headers valueForKey:key] forKey:[key lowercaseString]];
|
399
|
|
- }
|
400
|
|
-
|
401
|
|
- return mheaders;
|
402
|
|
-}
|
403
|
|
-
|
404
|
|
-- (id)init {
|
405
|
|
- self = [super init];
|
406
|
|
- return self;
|
407
|
|
-}
|
408
|
|
-
|
409
|
|
-
|
410
|
|
-- (void) sendRequest:(NSDictionary *)options bridge:(RCTBridge *)bridgeRef taskId:(NSString *)taskId withRequest:(NSURLRequest *)req callback:(RCTResponseSenderBlock) callback {
|
411
|
|
- self.taskId = taskId;
|
412
|
|
- self.respData = [[NSMutableData alloc] initWithLength:0];
|
413
|
|
- self.callback = callback;
|
414
|
|
- self.bridge = bridgeRef;
|
415
|
|
- self.expectedBytes = 0;
|
416
|
|
- self.receivedBytes = 0;
|
417
|
|
- self.options = options;
|
418
|
|
-
|
419
|
|
- NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
|
420
|
|
- NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
|
421
|
|
-
|
422
|
|
- // open file stream for write
|
423
|
|
- if( path != nil) {
|
424
|
|
- self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
|
425
|
|
- [self.fileStream openWithPath:path encode:@"ascii" appendData:YES ];
|
426
|
|
- }
|
427
|
|
- else if ( [self.options valueForKey:CONFIG_USE_TEMP]!= nil ) {
|
428
|
|
- self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
|
429
|
|
- [self.fileStream openWithPath:[FetchBlobFS getTempPath:taskId withExtension:ext] encode:@"ascii" appendData:YES];
|
430
|
|
- }
|
431
|
|
-
|
432
|
|
- NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:NO];
|
433
|
|
- [conn scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
434
|
|
- [conn start];
|
435
|
|
-
|
436
|
|
- if(!conn) {
|
437
|
|
- callback(@[[NSString stringWithFormat:@"RNFetchBlob could not initialize connection"], [NSNull null]]);
|
438
|
|
- }
|
439
|
|
-}
|
440
|
|
-
|
441
|
|
-
|
442
|
|
-#pragma mark NSURLConnection delegate methods
|
443
|
|
-
|
444
|
|
-
|
445
|
|
-- (void) connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response {
|
446
|
|
-// [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
|
447
|
|
- expectedBytes = [response expectedContentLength];
|
448
|
|
-}
|
449
|
|
-
|
450
|
|
-
|
451
|
|
-- (void) connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data {
|
452
|
|
- receivedBytes += [data length];
|
453
|
|
-
|
454
|
|
- Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
|
455
|
|
- NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
|
456
|
|
- if(path != nil) {
|
457
|
|
- [self.fileStream write:data];
|
458
|
|
- }
|
459
|
|
- // write to tmp file
|
460
|
|
- else if( fileCache != nil) {
|
461
|
|
- NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
|
462
|
|
- [self.fileStream write:data];
|
463
|
|
- }
|
464
|
|
- // cache data in memory
|
465
|
|
- else {
|
466
|
|
- [respData appendData:data];
|
467
|
|
- }
|
468
|
|
-
|
469
|
|
- [self.bridge.eventDispatcher
|
470
|
|
- sendDeviceEventWithName:@"RNFetchBlobProgress"
|
471
|
|
- body:@{
|
472
|
|
- @"taskId": taskId,
|
473
|
|
- @"written": [NSString stringWithFormat:@"%d", receivedBytes],
|
474
|
|
- @"total": [NSString stringWithFormat:@"%d", expectedBytes]
|
475
|
|
- }
|
476
|
|
- ];
|
477
|
|
-}
|
478
|
|
-
|
479
|
|
-- (void) connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
480
|
|
-
|
481
|
|
- expectedBytes = totalBytesExpectedToWrite;
|
482
|
|
- receivedBytes += totalBytesWritten;
|
483
|
|
- [self.bridge.eventDispatcher
|
484
|
|
- sendDeviceEventWithName:@"RNFetchBlobProgress"
|
485
|
|
- body:@{
|
486
|
|
- @"taskId": taskId,
|
487
|
|
- @"written": [NSString stringWithFormat:@"%d", receivedBytes],
|
488
|
|
- @"total": [NSString stringWithFormat:@"%d", expectedBytes]
|
489
|
|
- }
|
490
|
|
- ];
|
491
|
|
-
|
492
|
|
-}
|
493
|
|
-
|
494
|
|
-- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
495
|
|
-
|
496
|
|
-// [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
|
497
|
|
-
|
498
|
|
- [self.fileStream closeInStream];
|
499
|
|
- [self.fileStream closeOutStream];
|
500
|
|
-
|
501
|
|
- callback(@[[error localizedDescription], [NSNull null]]);
|
502
|
|
-}
|
503
|
|
-
|
504
|
|
-- (NSCachedURLResponse *) connection:(NSURLConnection *)connection willCacheResponse: (NSCachedURLResponse *)cachedResponse {
|
505
|
|
- return nil;
|
506
|
|
-}
|
507
|
|
-
|
508
|
|
-
|
509
|
|
-// handle 301 and 302 responses
|
510
|
|
-- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:response {
|
511
|
|
- return request;
|
512
|
|
-}
|
513
|
|
-
|
514
|
|
-// request complete
|
515
|
|
-- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
|
516
|
|
-
|
517
|
|
- NSData * data;
|
518
|
|
- if(respData != nil)
|
519
|
|
- data = [NSData dataWithData:respData];
|
520
|
|
- else
|
521
|
|
- data = [[NSData alloc] init];
|
522
|
|
-
|
523
|
|
- NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
|
524
|
|
- NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
|
525
|
|
- Boolean useCache = [self.options valueForKey:CONFIG_USE_TEMP];
|
526
|
|
-
|
527
|
|
- [self.fileStream closeInStream];
|
528
|
|
-
|
529
|
|
- // if fileCache is true or file path is given, return a path
|
530
|
|
- if( path != nil ) {
|
531
|
|
- callback(@[[NSNull null], path]);
|
532
|
|
- }
|
533
|
|
- // when fileCache option is set but no path specified, save to tmp path
|
534
|
|
- else if( [self.options valueForKey:CONFIG_USE_TEMP] != nil) {
|
535
|
|
- NSString * tmpPath = [FetchBlobFS getTempPath:taskId withExtension:ext];
|
536
|
|
- callback(@[[NSNull null], tmpPath]);
|
537
|
|
- }
|
538
|
|
- // otherwise return base64 string
|
539
|
|
- else {
|
540
|
|
- callback(@[[NSNull null], [data base64EncodedStringWithOptions:0]]);
|
541
|
|
- }
|
542
|
|
-}
|
543
|
|
-
|
544
|
|
-@end
|
|
12
|
+#import "RNFetchBlobFS.h"
|
|
13
|
+#import "RNFetchBlobResp.h"
|
|
14
|
+#import "RNFetchBlobConst.h"
|
545
|
15
|
|
546
|
16
|
|
547
|
17
|
////////////////////////////////////////
|
|
@@ -568,8 +38,8 @@ RCT_EXPORT_MODULE();
|
568
|
38
|
self.filePathPrefix = FILE_PREFIX;
|
569
|
39
|
BOOL isDir;
|
570
|
40
|
// if temp folder not exists, create one
|
571
|
|
- if(![[NSFileManager defaultManager] fileExistsAtPath: [FetchBlobFS getTempPath] isDirectory:&isDir]) {
|
572
|
|
- [[NSFileManager defaultManager] createDirectoryAtPath:[FetchBlobFS getTempPath] withIntermediateDirectories:YES attributes:nil error:NULL];
|
|
41
|
+ if(![[NSFileManager defaultManager] fileExistsAtPath: [RNFetchBlobFS getTempPath] isDirectory:&isDir]) {
|
|
42
|
+ [[NSFileManager defaultManager] createDirectoryAtPath:[RNFetchBlobFS getTempPath] withIntermediateDirectories:YES attributes:nil error:NULL];
|
573
|
43
|
}
|
574
|
44
|
return self;
|
575
|
45
|
}
|
|
@@ -577,9 +47,9 @@ RCT_EXPORT_MODULE();
|
577
|
47
|
- (NSDictionary *)constantsToExport
|
578
|
48
|
{
|
579
|
49
|
return @{
|
580
|
|
- @"DocumentDir": [FetchBlobFS getDocumentDir],
|
581
|
|
- @"CacheDir" : [FetchBlobFS getCacheDir]
|
582
|
|
- };
|
|
50
|
+ @"DocumentDir": [RNFetchBlobFS getDocumentDir],
|
|
51
|
+ @"CacheDir" : [RNFetchBlobFS getCacheDir]
|
|
52
|
+ };
|
583
|
53
|
}
|
584
|
54
|
|
585
|
55
|
// Fetch blob data request
|
|
@@ -608,8 +78,8 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
|
608
|
78
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
609
|
79
|
// if method is POST or PUT, convert data string format
|
610
|
80
|
if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
|
611
|
|
- NSMutableData * postData = [[NSMutableData alloc] init];
|
612
|
|
-
|
|
81
|
+ NSMutableData * postData = [[NSMutableData alloc] init];
|
|
82
|
+
|
613
|
83
|
// combine multipart/form-data body
|
614
|
84
|
for(id field in form) {
|
615
|
85
|
NSString * name = [field valueForKey:@"name"];
|
|
@@ -641,7 +111,7 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
|
641
|
111
|
}
|
642
|
112
|
|
643
|
113
|
}
|
644
|
|
-
|
|
114
|
+
|
645
|
115
|
// close form data
|
646
|
116
|
[postData appendData: [[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
647
|
117
|
[request setHTTPBody:postData];
|
|
@@ -650,7 +120,7 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
|
650
|
120
|
[mheaders setValue:[NSString stringWithFormat:@"100-continue",[postData length]] forKey:@"Expect"];
|
651
|
121
|
// appaned boundary to content-type
|
652
|
122
|
[mheaders setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] forKey:@"content-type"];
|
653
|
|
-
|
|
123
|
+
|
654
|
124
|
}
|
655
|
125
|
|
656
|
126
|
[request setHTTPMethod: method];
|
|
@@ -728,7 +198,7 @@ RCT_EXPORT_METHOD(createFile:(NSString *)path data:(NSString *)data encoding:(NS
|
728
|
198
|
callback(@[[NSNull null]]);
|
729
|
199
|
else
|
730
|
200
|
callback(@[[NSString stringWithFormat:@"failed to create new file at path %@ please ensure the folder exists"]]);
|
731
|
|
-
|
|
201
|
+
|
732
|
202
|
}
|
733
|
203
|
|
734
|
204
|
// method for create file with ASCII content
|
|
@@ -757,11 +227,11 @@ RCT_EXPORT_METHOD(exists:(NSString *)path callback:(RCTResponseSenderBlock)callb
|
757
|
227
|
BOOL exists = NO;
|
758
|
228
|
exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory: &isDir];
|
759
|
229
|
callback(@[@(exists), @(isDir)]);
|
760
|
|
-
|
|
230
|
+
|
761
|
231
|
}
|
762
|
232
|
|
763
|
233
|
RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize) {
|
764
|
|
- FetchBlobFS *fileStream = [[FetchBlobFS alloc] initWithBridgeRef:self.bridge];
|
|
234
|
+ RNFetchBlobFS *fileStream = [[RNFetchBlobFS alloc] initWithBridgeRef:self.bridge];
|
765
|
235
|
if(bufferSize == nil) {
|
766
|
236
|
if([[encoding lowercaseString] isEqualToString:@"base64"])
|
767
|
237
|
bufferSize = 4095;
|
|
@@ -772,7 +242,7 @@ RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding
|
772
|
242
|
}
|
773
|
243
|
|
774
|
244
|
RCT_EXPORT_METHOD(writeStream:(NSString *)path withEncoding:(NSString *)encoding appendData:(BOOL)append callback:(RCTResponseSenderBlock)callback) {
|
775
|
|
- FetchBlobFS * fileStream = [[FetchBlobFS alloc] initWithBridgeRef:self.bridge];
|
|
245
|
+ RNFetchBlobFS * fileStream = [[RNFetchBlobFS alloc] initWithBridgeRef:self.bridge];
|
776
|
246
|
NSFileManager * fm = [NSFileManager defaultManager];
|
777
|
247
|
BOOL isDir = nil;
|
778
|
248
|
BOOL exist = [fm fileExistsAtPath:path isDirectory:&isDir];
|
|
@@ -785,7 +255,7 @@ RCT_EXPORT_METHOD(writeStream:(NSString *)path withEncoding:(NSString *)encoding
|
785
|
255
|
}
|
786
|
256
|
|
787
|
257
|
RCT_EXPORT_METHOD(writeArrayChunk:(NSString *)streamId withArray:(NSArray *)dataArray callback:(RCTResponseSenderBlock) callback) {
|
788
|
|
- FetchBlobFS *fs = [[FetchBlobFS getFileStreams] valueForKey:streamId];
|
|
258
|
+ RNFetchBlobFS *fs = [[RNFetchBlobFS getFileStreams] valueForKey:streamId];
|
789
|
259
|
char bytes[[dataArray count]];
|
790
|
260
|
for(int i = 0; i < dataArray.count; i++) {
|
791
|
261
|
bytes[i] = [[dataArray objectAtIndex:i] charValue];
|
|
@@ -797,13 +267,13 @@ RCT_EXPORT_METHOD(writeArrayChunk:(NSString *)streamId withArray:(NSArray *)data
|
797
|
267
|
}
|
798
|
268
|
|
799
|
269
|
RCT_EXPORT_METHOD(writeChunk:(NSString *)streamId withData:(NSString *)data callback:(RCTResponseSenderBlock) callback) {
|
800
|
|
- FetchBlobFS *fs = [[FetchBlobFS getFileStreams] valueForKey:streamId];
|
|
270
|
+ RNFetchBlobFS *fs = [[RNFetchBlobFS getFileStreams] valueForKey:streamId];
|
801
|
271
|
[fs writeEncodeChunk:data];
|
802
|
272
|
callback(@[[NSNull null]]);
|
803
|
273
|
}
|
804
|
274
|
|
805
|
275
|
RCT_EXPORT_METHOD(closeStream:(NSString *)streamId callback:(RCTResponseSenderBlock) callback) {
|
806
|
|
- FetchBlobFS *fs = [[FetchBlobFS getFileStreams] valueForKey:streamId];
|
|
276
|
+ RNFetchBlobFS *fs = [[RNFetchBlobFS getFileStreams] valueForKey:streamId];
|
807
|
277
|
[fs closeOutStream];
|
808
|
278
|
callback(@[[NSNull null], @YES]);
|
809
|
279
|
}
|
|
@@ -862,7 +332,7 @@ RCT_EXPORT_METHOD(stat:(NSString *)path callback:(RCTResponseSenderBlock) callba
|
862
|
332
|
callback(@[[NSString stringWithFormat:@"failed to list path `%@` for it is not exist or it is not exist", path]]);
|
863
|
333
|
return ;
|
864
|
334
|
}
|
865
|
|
- NSData * res = [FetchBlobFS stat:path error:&error];
|
|
335
|
+ NSData * res = [RNFetchBlobFS stat:path error:&error];
|
866
|
336
|
|
867
|
337
|
if(error == nil)
|
868
|
338
|
callback(@[[NSNull null], res]);
|
|
@@ -882,16 +352,16 @@ RCT_EXPORT_METHOD(lstat:(NSString *)path callback:(RCTResponseSenderBlock) callb
|
882
|
352
|
}
|
883
|
353
|
NSError * error = nil;
|
884
|
354
|
NSArray * files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error];
|
885
|
|
-
|
|
355
|
+
|
886
|
356
|
NSMutableArray * res = [[NSMutableArray alloc] init];
|
887
|
357
|
if(isDir == YES) {
|
888
|
358
|
for(NSString * p in files) {
|
889
|
359
|
NSString * filePath = [NSString stringWithFormat:@"%@/%@", path, p];
|
890
|
|
- [res addObject:[FetchBlobFS stat:filePath error:&error]];
|
|
360
|
+ [res addObject:[RNFetchBlobFS stat:filePath error:&error]];
|
891
|
361
|
}
|
892
|
362
|
}
|
893
|
363
|
else {
|
894
|
|
- [res addObject:[FetchBlobFS stat:path error:&error]];
|
|
364
|
+ [res addObject:[RNFetchBlobFS stat:path error:&error]];
|
895
|
365
|
}
|
896
|
366
|
|
897
|
367
|
if(error == nil)
|
|
@@ -924,21 +394,21 @@ RCT_EXPORT_METHOD(mv:(NSString *)path toPath:(NSString *)dest callback:(RCTRespo
|
924
|
394
|
}
|
925
|
395
|
|
926
|
396
|
RCT_EXPORT_METHOD(mkdir:(NSString *)path callback:(RCTResponseSenderBlock) callback) {
|
927
|
|
- if([FetchBlobFS exists:path]) {
|
|
397
|
+ if([RNFetchBlobFS exists:path]) {
|
928
|
398
|
callback(@[@"mkdir failed, folder already exists"]);
|
929
|
399
|
return;
|
930
|
400
|
}
|
931
|
401
|
else
|
932
|
|
- [FetchBlobFS mkdir:path];
|
|
402
|
+ [RNFetchBlobFS mkdir:path];
|
933
|
403
|
callback(@[[NSNull null]]);
|
934
|
404
|
}
|
935
|
405
|
|
936
|
406
|
RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {
|
937
|
407
|
|
938
|
408
|
callback(@[
|
939
|
|
- [FetchBlobFS getDocumentDir],
|
940
|
|
- [FetchBlobFS getCacheDir],
|
941
|
|
- ]);
|
|
409
|
+ [RNFetchBlobFS getDocumentDir],
|
|
410
|
+ [RNFetchBlobFS getCacheDir],
|
|
411
|
+ ]);
|
942
|
412
|
}
|
943
|
413
|
|
944
|
414
|
#pragma mark RNFetchBlob private methods
|