@amazon-devices/expo-file-system 2.0.1758683737

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.eslintrc.js +2 -0
  2. package/CHANGELOG.md +317 -0
  3. package/CMakeLists.txt +52 -0
  4. package/LICENSE +7 -0
  5. package/README.kepler.md +260 -0
  6. package/README.md +46 -0
  7. package/THIRD_PARTY_NOTICES.txt +24 -0
  8. package/android/build.gradle +118 -0
  9. package/android/src/main/AndroidManifest.xml +17 -0
  10. package/android/src/main/java/expo/modules/filesystem/AppDirectoriesModule.kt +26 -0
  11. package/android/src/main/java/expo/modules/filesystem/CountingRequestBody.kt +52 -0
  12. package/android/src/main/java/expo/modules/filesystem/FilePermissionModule.kt +48 -0
  13. package/android/src/main/java/expo/modules/filesystem/FileSystemExceptions.kt +48 -0
  14. package/android/src/main/java/expo/modules/filesystem/FileSystemFileProvider.kt +5 -0
  15. package/android/src/main/java/expo/modules/filesystem/FileSystemModule.kt +1110 -0
  16. package/android/src/main/java/expo/modules/filesystem/FileSystemPackage.kt +10 -0
  17. package/android/src/main/java/expo/modules/filesystem/FileSystemRecords.kt +92 -0
  18. package/android/src/main/res/xml/file_system_provider_paths.xml +5 -0
  19. package/app.plugin.js +1 -0
  20. package/build/ExponentFileSystem.d.ts +4 -0
  21. package/build/ExponentFileSystem.d.ts.map +1 -0
  22. package/build/ExponentFileSystem.js +5 -0
  23. package/build/ExponentFileSystem.js.map +1 -0
  24. package/build/ExponentFileSystem.kepler.d.ts +4 -0
  25. package/build/ExponentFileSystem.kepler.d.ts.map +1 -0
  26. package/build/ExponentFileSystem.kepler.js +112 -0
  27. package/build/ExponentFileSystem.kepler.js.map +1 -0
  28. package/build/ExponentFileSystem.web.d.ts +3 -0
  29. package/build/ExponentFileSystem.web.d.ts.map +1 -0
  30. package/build/ExponentFileSystem.web.js +3 -0
  31. package/build/ExponentFileSystem.web.js.map +1 -0
  32. package/build/ExponentFileSystemShim.d.ts +4 -0
  33. package/build/ExponentFileSystemShim.d.ts.map +1 -0
  34. package/build/ExponentFileSystemShim.js +21 -0
  35. package/build/ExponentFileSystemShim.js.map +1 -0
  36. package/build/FileSystem.d.ts +361 -0
  37. package/build/FileSystem.d.ts.map +1 -0
  38. package/build/FileSystem.js +616 -0
  39. package/build/FileSystem.js.map +1 -0
  40. package/build/FileSystem.types.d.ts +304 -0
  41. package/build/FileSystem.types.d.ts.map +1 -0
  42. package/build/FileSystem.types.js +47 -0
  43. package/build/FileSystem.types.js.map +1 -0
  44. package/build/index.d.ts +3 -0
  45. package/build/index.d.ts.map +1 -0
  46. package/build/index.js +3 -0
  47. package/build/index.js.map +1 -0
  48. package/build/types.d.ts +35 -0
  49. package/build/types.d.ts.map +1 -0
  50. package/build/types.js +2 -0
  51. package/build/types.js.map +1 -0
  52. package/expo-module.config.json +11 -0
  53. package/ios/EXFilePermissionModule.h +16 -0
  54. package/ios/EXFilePermissionModule.m +68 -0
  55. package/ios/EXFileSystem.h +25 -0
  56. package/ios/EXFileSystem.m +1084 -0
  57. package/ios/EXFileSystemAssetLibraryHandler.h +6 -0
  58. package/ios/EXFileSystemAssetLibraryHandler.m +142 -0
  59. package/ios/EXFileSystemHandler.h +17 -0
  60. package/ios/EXFileSystemLocalFileHandler.h +7 -0
  61. package/ios/EXFileSystemLocalFileHandler.m +79 -0
  62. package/ios/EXSessionTasks/EXSessionCancelableUploadTaskDelegate.h +16 -0
  63. package/ios/EXSessionTasks/EXSessionCancelableUploadTaskDelegate.m +55 -0
  64. package/ios/EXSessionTasks/EXSessionDownloadTaskDelegate.h +13 -0
  65. package/ios/EXSessionTasks/EXSessionDownloadTaskDelegate.m +64 -0
  66. package/ios/EXSessionTasks/EXSessionHandler.h +19 -0
  67. package/ios/EXSessionTasks/EXSessionHandler.m +49 -0
  68. package/ios/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.h +18 -0
  69. package/ios/EXSessionTasks/EXSessionResumableDownloadTaskDelegate.m +66 -0
  70. package/ios/EXSessionTasks/EXSessionTaskDelegate.h +32 -0
  71. package/ios/EXSessionTasks/EXSessionTaskDelegate.m +58 -0
  72. package/ios/EXSessionTasks/EXSessionTaskDispatcher.h +19 -0
  73. package/ios/EXSessionTasks/EXSessionTaskDispatcher.m +96 -0
  74. package/ios/EXSessionTasks/EXSessionUploadTaskDelegate.h +8 -0
  75. package/ios/EXSessionTasks/EXSessionUploadTaskDelegate.m +52 -0
  76. package/ios/EXSessionTasks/EXTaskHandlersManager.h +21 -0
  77. package/ios/EXSessionTasks/EXTaskHandlersManager.m +56 -0
  78. package/ios/Encoding.swift +88 -0
  79. package/ios/ExpoFileSystem.h +1 -0
  80. package/ios/ExpoFileSystem.podspec +32 -0
  81. package/ios/FileSystemBackgroundSessionHandler.swift +25 -0
  82. package/ios/FileSystemExceptions.swift +69 -0
  83. package/ios/FileSystemHelpers.swift +66 -0
  84. package/ios/FileSystemModule.swift +263 -0
  85. package/ios/FileSystemRecords.swift +74 -0
  86. package/ios/NSData+EXFileSystem.h +9 -0
  87. package/ios/NSData+EXFileSystem.m +19 -0
  88. package/ios/NetworkingHelpers.swift +84 -0
  89. package/ios/Tests/EXFileSystemSpec.swift +55 -0
  90. package/jest.config.js +3 -0
  91. package/kepler/ExponentFileSystem.cpp +498 -0
  92. package/kepler/ExponentFileSystem.h +60 -0
  93. package/kepler/KeplerInit.cpp +28 -0
  94. package/kepler/NetworkingRequestHandler.cpp +47 -0
  95. package/kepler/test/FileSystem.cpp +425 -0
  96. package/package.json +1 -0
  97. package/plugin/build/withFileSystem.d.ts +3 -0
  98. package/plugin/build/withFileSystem.js +12 -0
  99. package/plugin/src/withFileSystem.ts +13 -0
  100. package/plugin/tsconfig.json +9 -0
  101. package/plugin/tsconfig.tsbuildinfo +1 -0
  102. package/react-native.config.js +21 -0
  103. package/src/ExponentFileSystem.kepler.ts +167 -0
  104. package/src/ExponentFileSystem.ts +7 -0
  105. package/src/ExponentFileSystem.web.ts +2 -0
  106. package/src/ExponentFileSystemShim.ts +23 -0
  107. package/src/FileSystem.ts +756 -0
  108. package/src/FileSystem.types.ts +339 -0
  109. package/src/index.ts +2 -0
  110. package/src/types.ts +34 -0
  111. package/tsconfig.json +9 -0
@@ -0,0 +1,6 @@
1
+
2
+ #import <ExpoFileSystem/EXFileSystemHandler.h>
3
+
4
+ @interface EXFileSystemAssetLibraryHandler : NSObject <EXFileSystemHandler>
5
+
6
+ @end
@@ -0,0 +1,142 @@
1
+
2
+ #import <ExpoFileSystem/EXFileSystemAssetLibraryHandler.h>
3
+ #import <ExpoFileSystem/NSData+EXFileSystem.h>
4
+
5
+ #import <Photos/Photos.h>
6
+
7
+ @implementation EXFileSystemAssetLibraryHandler
8
+
9
+ + (void)getInfoForFile:(NSURL *)fileUri
10
+ withOptions:(NSDictionary *)options
11
+ resolver:(EXPromiseResolveBlock)resolve
12
+ rejecter:(EXPromiseRejectBlock)reject
13
+ {
14
+ NSError *error;
15
+ PHFetchResult<PHAsset *> *fetchResult = [self fetchResultForUri:fileUri error:&error];
16
+ if (error) {
17
+ reject(@"E_UNSUPPORTED_ARG", error.description, error);
18
+ return;
19
+ }
20
+ if (fetchResult.count > 0) {
21
+ PHAsset *asset = fetchResult[0];
22
+ NSMutableDictionary *result = [NSMutableDictionary dictionary];
23
+ result[@"exists"] = @(YES);
24
+ result[@"isDirectory"] = @(NO);
25
+ result[@"uri"] = fileUri;
26
+ result[@"modificationTime"] = @(asset.modificationDate.timeIntervalSince1970);
27
+ if (options[@"md5"] || options[@"size"]) {
28
+ [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
29
+ result[@"size"] = @(imageData.length);
30
+ if (options[@"md5"]) {
31
+ result[@"md5"] = [imageData md5String];
32
+ }
33
+ resolve(result);
34
+ }];
35
+ } else {
36
+ resolve(result);
37
+ }
38
+ } else {
39
+ resolve(@{@"exists": @(NO), @"isDirectory": @(NO)});
40
+ }
41
+ }
42
+
43
+ + (void)copyFrom:(NSURL *)from
44
+ to:(NSURL *)to
45
+ resolver:(EXPromiseResolveBlock)resolve
46
+ rejecter:(EXPromiseRejectBlock)reject
47
+ {
48
+ NSString *toPath = [to.path stringByStandardizingPath];
49
+
50
+ // NOTE: The destination-delete and the copy should happen atomically, but we hope for the best for now
51
+ NSError *error;
52
+ if ([[NSFileManager defaultManager] fileExistsAtPath:toPath]) {
53
+ if (![[NSFileManager defaultManager] removeItemAtPath:toPath error:&error]) {
54
+ reject(@"E_FILE_NOT_COPIED",
55
+ [NSString stringWithFormat:@"File '%@' could not be copied to '%@' because a file already exists at "
56
+ "the destination and could not be deleted.", from, to],
57
+ error);
58
+ return;
59
+ }
60
+ }
61
+
62
+ PHFetchResult<PHAsset *> *fetchResult = [self fetchResultForUri:from error:&error];
63
+ if (error) {
64
+ reject(@"E_UNSUPPORTED_ARG", error.description, error);
65
+ return;
66
+ }
67
+
68
+ if (fetchResult.count > 0) {
69
+ PHAsset *asset = fetchResult[0];
70
+ if (asset.mediaType == PHAssetMediaTypeVideo) {
71
+ [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:nil resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
72
+ if (![asset isKindOfClass:[AVURLAsset class]]) {
73
+ reject(@"ERR_INCORRECT_ASSET_TYPE",
74
+ [NSString stringWithFormat:@"File '%@' has incorrect asset type.", from],
75
+ nil);
76
+ return;
77
+ }
78
+
79
+ AVURLAsset* urlAsset = (AVURLAsset*)asset;
80
+ NSNumber *size;
81
+ [urlAsset.URL getResourceValue:&size forKey:NSURLFileSizeKey error:nil];
82
+ NSData *data = [NSData dataWithContentsOfURL:urlAsset.URL];
83
+
84
+ [EXFileSystemAssetLibraryHandler copyData:data toPath:toPath resolver:resolve rejecter:reject];
85
+ }];
86
+ } else {
87
+ [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
88
+ [EXFileSystemAssetLibraryHandler copyData:imageData toPath:toPath resolver:resolve rejecter:reject];
89
+ }];
90
+ }
91
+ } else {
92
+ reject(@"E_FILE_NOT_COPIED",
93
+ [NSString stringWithFormat:@"File '%@' could not be found.", from],
94
+ error);
95
+ }
96
+ }
97
+
98
+ // adapted from RCTImageLoader.m
99
+ + (PHFetchResult<PHAsset *> *)fetchResultForUri:(NSURL *)url error:(NSError **)error
100
+ {
101
+ if ([url.scheme caseInsensitiveCompare:@"ph"] == NSOrderedSame) {
102
+ // Fetch assets using PHAsset localIdentifier (recommended)
103
+ NSString *const localIdentifier = [url.absoluteString substringFromIndex:@"ph://".length];
104
+ return [PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil];
105
+ } else if ([url.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame) {
106
+ #if TARGET_OS_MACCATALYST
107
+ static BOOL hasWarned = NO;
108
+ if (!hasWarned) {
109
+ NSLog(@"assets-library:// URLs have been deprecated and cannot be accessed in macOS Catalyst. Returning nil (future warnings will be suppressed).");
110
+ hasWarned = YES;
111
+ }
112
+ return nil;
113
+ #else
114
+ // This is the older, deprecated way of fetching assets from assets-library
115
+ // using the "assets-library://" protocol
116
+ return [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
117
+ #endif
118
+ }
119
+
120
+ NSString *description = [NSString stringWithFormat:@"Invalid URL provided, expected scheme to be either 'ph' or 'assets-library', was '%@'.", url.scheme];
121
+ *error = [[NSError alloc] initWithDomain:NSURLErrorDomain
122
+ code:NSURLErrorUnsupportedURL
123
+ userInfo:@{NSLocalizedDescriptionKey: description}];
124
+ return nil;
125
+ }
126
+
127
+
128
+ + (void)copyData:(NSData *)data
129
+ toPath:(NSString *)path
130
+ resolver:(EXPromiseResolveBlock)resolve
131
+ rejecter:(EXPromiseRejectBlock)reject
132
+ {
133
+ if ([data writeToFile:path atomically:YES]) {
134
+ resolve(nil);
135
+ } else {
136
+ reject(@"E_FILE_NOT_COPIED",
137
+ [NSString stringWithFormat:@"File could not be copied to '%@'.", path],
138
+ nil);
139
+ }
140
+ }
141
+
142
+ @end
@@ -0,0 +1,17 @@
1
+ // Copyright 2023-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/ExpoModulesCore.h>
4
+
5
+ @protocol EXFileSystemHandler
6
+
7
+ + (void)getInfoForFile:(NSURL *)fileUri
8
+ withOptions:(NSDictionary *)optionxs
9
+ resolver:(EXPromiseResolveBlock)resolve
10
+ rejecter:(EXPromiseRejectBlock)reject;
11
+
12
+ + (void)copyFrom:(NSURL *)from
13
+ to:(NSURL *)to
14
+ resolver:(EXPromiseResolveBlock)resolve
15
+ rejecter:(EXPromiseRejectBlock)reject;
16
+
17
+ @end
@@ -0,0 +1,7 @@
1
+ // Copyright 2023-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoFileSystem/EXFileSystemHandler.h>
4
+
5
+ @interface EXFileSystemLocalFileHandler : NSObject <EXFileSystemHandler>
6
+
7
+ @end
@@ -0,0 +1,79 @@
1
+
2
+ #import <ExpoFileSystem/EXFileSystemLocalFileHandler.h>
3
+ #import <ExpoFileSystem/NSData+EXFileSystem.h>
4
+
5
+ @implementation EXFileSystemLocalFileHandler
6
+
7
+ + (void)getInfoForFile:(NSURL *)fileUri
8
+ withOptions:(NSDictionary *)options
9
+ resolver:(EXPromiseResolveBlock)resolve
10
+ rejecter:(EXPromiseRejectBlock)reject
11
+ {
12
+ NSString *path = fileUri.path;
13
+ BOOL isDirectory;
14
+ if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) {
15
+ NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
16
+ NSMutableDictionary *result = [NSMutableDictionary dictionary];
17
+ result[@"exists"] = @(YES);
18
+ result[@"isDirectory"] = @(isDirectory);
19
+ result[@"uri"] = [NSURL fileURLWithPath:path].absoluteString;
20
+ if (options[@"md5"]) {
21
+ result[@"md5"] = [[NSData dataWithContentsOfFile:path] md5String];
22
+ }
23
+ result[@"size"] = @([EXFileSystemLocalFileHandler getFileSize:path attributes:attributes]);
24
+ result[@"modificationTime"] = @(attributes.fileModificationDate.timeIntervalSince1970);
25
+ resolve(result);
26
+ } else {
27
+ resolve(@{@"exists": @(NO), @"isDirectory": @(NO)});
28
+ }
29
+ }
30
+
31
+ + (unsigned long long)getFileSize:(NSString *)path attributes:(NSDictionary<NSFileAttributeKey, id> *)attributes
32
+ {
33
+ if (attributes.fileType != NSFileTypeDirectory) {
34
+ return attributes.fileSize;
35
+ }
36
+
37
+ // The path is pointing to the folder
38
+ NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
39
+ NSEnumerator *contentsEnumurator = [contents objectEnumerator];
40
+ NSString *file;
41
+ unsigned long long folderSize = 0;
42
+ while (file = [contentsEnumurator nextObject]) {
43
+ NSString *filePath = [path stringByAppendingPathComponent:file];
44
+ NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
45
+ folderSize += [EXFileSystemLocalFileHandler getFileSize:filePath attributes:fileAttributes];
46
+ }
47
+
48
+ return folderSize;
49
+ }
50
+
51
+ + (void)copyFrom:(NSURL *)from
52
+ to:(NSURL *)to
53
+ resolver:(EXPromiseResolveBlock)resolve
54
+ rejecter:(EXPromiseRejectBlock)reject
55
+ {
56
+ NSString *fromPath = [from.path stringByStandardizingPath];
57
+ NSString *toPath = [to.path stringByStandardizingPath];
58
+
59
+ NSError *error;
60
+ if ([[NSFileManager defaultManager] fileExistsAtPath:toPath]) {
61
+ if (![[NSFileManager defaultManager] removeItemAtPath:toPath error:&error]) {
62
+ reject(@"E_FILE_NOT_COPIED",
63
+ [NSString stringWithFormat:@"File '%@' could not be copied to '%@' because a file already exists at "
64
+ "the destination and could not be deleted.", from, to],
65
+ error);
66
+ return;
67
+ }
68
+ }
69
+
70
+ if ([[NSFileManager defaultManager] copyItemAtPath:fromPath toPath:toPath error:&error]) {
71
+ resolve(nil);
72
+ } else {
73
+ reject(@"E_FILE_NOT_COPIED",
74
+ [NSString stringWithFormat:@"File '%@' could not be copied to '%@'.", from, to],
75
+ error);
76
+ }
77
+ }
78
+
79
+ @end
@@ -0,0 +1,16 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoFileSystem/EXSessionUploadTaskDelegate.h>
4
+ #import <ExpoFileSystem/EXTaskHandlersManager.h>
5
+
6
+ typedef void (^EXUploadDelegateOnSendCallback)(NSURLSessionUploadTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend);
7
+
8
+ @interface EXSessionCancelableUploadTaskDelegate : EXSessionUploadTaskDelegate
9
+
10
+ - (nonnull instancetype)initWithResolve:(EXPromiseResolveBlock)resolve
11
+ reject:(EXPromiseRejectBlock)reject
12
+ onSendCallback:(EXUploadDelegateOnSendCallback)onSendCallback
13
+ resumableManager:(EXTaskHandlersManager *)manager
14
+ uuid:(NSString *)uuid;
15
+
16
+ @end
@@ -0,0 +1,55 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoFileSystem/EXSessionCancelableUploadTaskDelegate.h>
4
+
5
+ @interface EXSessionCancelableUploadTaskDelegate ()
6
+
7
+ @property (strong, nonatomic, readonly) EXUploadDelegateOnSendCallback onSendCallback;
8
+ @property (weak, nonatomic) EXTaskHandlersManager *manager;
9
+ @property (strong, nonatomic) NSString *uuid;
10
+
11
+ @end
12
+
13
+ @implementation EXSessionCancelableUploadTaskDelegate
14
+
15
+ - (nonnull instancetype)initWithResolve:(EXPromiseResolveBlock)resolve
16
+ reject:(EXPromiseRejectBlock)reject
17
+ onSendCallback:(EXUploadDelegateOnSendCallback)onSendCallback
18
+ resumableManager:(EXTaskHandlersManager *)manager
19
+ uuid:(NSString *)uuid;
20
+ {
21
+ if (self = [super initWithResolve:resolve
22
+ reject:reject]) {
23
+ _onSendCallback = onSendCallback;
24
+ _manager = manager;
25
+ _uuid = uuid;
26
+ }
27
+ return self;
28
+ }
29
+
30
+ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
31
+ {
32
+ if (error) {
33
+ // The task was paused by us. So, we shouldn't throw.
34
+ if (error.code == NSURLErrorCancelled) {
35
+ self.resolve([NSNull null]);
36
+ [_manager unregisterTask:_uuid];
37
+ return;
38
+ }
39
+ }
40
+
41
+ [super URLSession:session task:task didCompleteWithError:error];
42
+ [_manager unregisterTask:_uuid];
43
+ }
44
+
45
+ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
46
+ didSendBodyData:(int64_t)bytesSent
47
+ totalBytesSent:(int64_t)totalBytesSent
48
+ totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
49
+ {
50
+ if (_onSendCallback && bytesSent > 0) {
51
+ _onSendCallback(task, bytesSent, totalBytesSent, totalBytesExpectedToSend);
52
+ }
53
+ }
54
+
55
+ @end
@@ -0,0 +1,13 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoFileSystem/EXSessionTaskDelegate.h>
4
+
5
+ @interface EXSessionDownloadTaskDelegate : EXSessionTaskDelegate
6
+
7
+ - (nonnull instancetype)initWithResolve:(EXPromiseResolveBlock)resolve
8
+ reject:(EXPromiseRejectBlock)reject
9
+ localUrl:(NSURL *)localUrl
10
+ shouldCalculateMd5:(BOOL)shouldCalculateMd5;
11
+
12
+ @end
13
+
@@ -0,0 +1,64 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoFileSystem/EXSessionDownloadTaskDelegate.h>
4
+ #import <ExpoFileSystem/NSData+EXFileSystem.h>
5
+
6
+ @interface EXSessionDownloadTaskDelegate ()
7
+
8
+ @property (strong, nonatomic) NSURL *localUrl;
9
+ @property (nonatomic) BOOL shouldCalculateMd5;
10
+
11
+ @end
12
+
13
+ @implementation EXSessionDownloadTaskDelegate
14
+
15
+ - (nonnull instancetype)initWithResolve:(EXPromiseResolveBlock)resolve
16
+ reject:(EXPromiseRejectBlock)reject
17
+ localUrl:(NSURL *)localUrl
18
+ shouldCalculateMd5:(BOOL)shouldCalculateMd5
19
+ {
20
+ if (self = [super initWithResolve:resolve reject:reject])
21
+ {
22
+ _localUrl = localUrl;
23
+ _shouldCalculateMd5 = shouldCalculateMd5;
24
+ }
25
+ return self;
26
+ }
27
+
28
+ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
29
+ {
30
+ NSError *error;
31
+ NSFileManager *fileManager = [NSFileManager defaultManager];
32
+ if ([fileManager fileExistsAtPath:_localUrl.path]) {
33
+ [fileManager removeItemAtURL:_localUrl error:&error];
34
+ if (error) {
35
+ self.reject(@"ERR_FILESYSTEM_CANNOT_REMOVE",
36
+ [NSString stringWithFormat:@"Unable to remove file from local URI: '%@'", error.description],
37
+ error);
38
+ return;
39
+ }
40
+ }
41
+
42
+ [fileManager moveItemAtURL:location toURL:_localUrl error:&error];
43
+ if (error) {
44
+ self.reject(@"ERR_FILESYSTEM_CANNOT_SAVE",
45
+ [NSString stringWithFormat:@"Unable to save file to local URI: '%@'", error.description],
46
+ error);
47
+ return;
48
+ }
49
+
50
+ self.resolve([self parseServerResponse:downloadTask.response]);
51
+ }
52
+
53
+ - (NSDictionary *)parseServerResponse:(NSURLResponse *)response
54
+ {
55
+ NSMutableDictionary *result = [[super parseServerResponse:response] mutableCopy];
56
+ result[@"uri"] = _localUrl.absoluteString;
57
+ if (_shouldCalculateMd5) {
58
+ NSData *data = [NSData dataWithContentsOfURL:_localUrl];
59
+ result[@"md5"] = [data md5String];
60
+ }
61
+ return result;
62
+ }
63
+
64
+ @end
@@ -0,0 +1,19 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <Foundation/Foundation.h>
4
+ #import <ExpoModulesCore/EXSingletonModule.h>
5
+ #import <UIKit/UIKit.h>
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ @protocol EXSessionHandler
10
+
11
+ - (void)invokeCompletionHandlerForSessionIdentifier:(NSString *)identifier;
12
+
13
+ @end
14
+
15
+ @interface EXSessionHandler : EXSingletonModule <UIApplicationDelegate, EXSessionHandler>
16
+
17
+ @end
18
+
19
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,49 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoFileSystem/EXSessionHandler.h>
4
+
5
+ #import <ExpoModulesCore/EXDefines.h>
6
+
7
+ @interface EXSessionHandler ()
8
+
9
+ @property (nonatomic, strong) NSMutableDictionary<NSString *, void (^)(void)> *completionHandlers;
10
+
11
+ @end
12
+
13
+ @implementation EXSessionHandler
14
+
15
+ EX_REGISTER_SINGLETON_MODULE(SessionHandler);
16
+
17
+ - (instancetype)init
18
+ {
19
+ if (self = [super init]) {
20
+ _completionHandlers = [NSMutableDictionary dictionary];
21
+ }
22
+
23
+ return self;
24
+ }
25
+
26
+ - (void)invokeCompletionHandlerForSessionIdentifier:(NSString *)identifier
27
+ {
28
+ if (!identifier) {
29
+ return;
30
+ }
31
+
32
+ void (^completionHandler)(void) = _completionHandlers[identifier];
33
+ if (completionHandler) {
34
+ // We need to run completionHandler explicite on the main thread because is's part of UIKit
35
+ dispatch_async(dispatch_get_main_queue(), ^{
36
+ completionHandler();
37
+ });
38
+ [_completionHandlers removeObjectForKey:identifier];
39
+ }
40
+ }
41
+
42
+ #pragma mark - AppDelegate
43
+
44
+ - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler
45
+ {
46
+ _completionHandlers[identifier] = completionHandler;
47
+ }
48
+
49
+ @end
@@ -0,0 +1,18 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoFileSystem/EXSessionDownloadTaskDelegate.h>
4
+ #import <ExpoFileSystem/EXTaskHandlersManager.h>
5
+
6
+ typedef void (^EXDownloadDelegateOnWriteCallback)(NSURLSessionDownloadTask *task, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
7
+
8
+ @interface EXSessionResumableDownloadTaskDelegate : EXSessionDownloadTaskDelegate
9
+
10
+ - (nonnull instancetype)initWithResolve:(EXPromiseResolveBlock)resolve
11
+ reject:(EXPromiseRejectBlock)reject
12
+ localUrl:(NSURL *)localUrl
13
+ shouldCalculateMd5:(BOOL)shouldCalculateMd5
14
+ onWriteCallback:(EXDownloadDelegateOnWriteCallback)onWriteCallback
15
+ resumableManager:(EXTaskHandlersManager *)manager
16
+ uuid:(NSString *)uuid;
17
+
18
+ @end
@@ -0,0 +1,66 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoFileSystem/EXSessionResumableDownloadTaskDelegate.h>
4
+
5
+ @interface EXSessionResumableDownloadTaskDelegate ()
6
+
7
+ @property (strong, nonatomic, readonly) EXDownloadDelegateOnWriteCallback onWriteCallback;
8
+ @property (weak, nonatomic) EXTaskHandlersManager *manager;
9
+ @property (strong, nonatomic) NSString *uuid;
10
+
11
+ @end
12
+
13
+ @implementation EXSessionResumableDownloadTaskDelegate
14
+
15
+ - (nonnull instancetype)initWithResolve:(EXPromiseResolveBlock)resolve
16
+ reject:(EXPromiseRejectBlock)reject
17
+ localUrl:(NSURL *)localUrl
18
+ shouldCalculateMd5:(BOOL)shouldCalculateMd5
19
+ onWriteCallback:(EXDownloadDelegateOnWriteCallback)onWriteCallback
20
+ resumableManager:(EXTaskHandlersManager *)manager
21
+ uuid:(NSString *)uuid;
22
+ {
23
+ if (self = [super initWithResolve:resolve
24
+ reject:reject
25
+ localUrl:localUrl
26
+ shouldCalculateMd5:shouldCalculateMd5]) {
27
+ _onWriteCallback = onWriteCallback;
28
+ _manager = manager;
29
+ _uuid = uuid;
30
+ }
31
+ return self;
32
+ }
33
+
34
+ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
35
+ {
36
+ [super URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
37
+ [_manager unregisterTask:_uuid];
38
+ }
39
+
40
+ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
41
+ {
42
+ if (error) {
43
+ // The task was paused by us. So, we shouldn't throw.
44
+ if (error.code == NSURLErrorCancelled) {
45
+ self.resolve([NSNull null]);
46
+ } else {
47
+ self.reject(@"ERR_FILESYSTEM_CANNOT_DOWNLOAD",
48
+ [NSString stringWithFormat:@"Unable to download file: %@", error.description],
49
+ error);
50
+ }
51
+ }
52
+
53
+ [_manager unregisterTask:_uuid];
54
+ }
55
+
56
+ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
57
+ didWriteData:(int64_t)bytesWritten
58
+ totalBytesWritten:(int64_t)totalBytesWritten
59
+ totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
60
+ {
61
+ if (_onWriteCallback && bytesWritten > 0) {
62
+ _onWriteCallback(downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
63
+ }
64
+ }
65
+
66
+ @end
@@ -0,0 +1,32 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <Foundation/Foundation.h>
4
+ #import <ExpoModulesCore/EXDefines.h>
5
+
6
+ @interface EXSessionTaskDelegate : NSObject
7
+
8
+ @property (nonatomic, strong, readonly) EXPromiseResolveBlock resolve;
9
+ @property (nonatomic, strong, readonly) EXPromiseRejectBlock reject;
10
+
11
+ - (nonnull instancetype)initWithResolve:(EXPromiseResolveBlock)resolve
12
+ reject:(EXPromiseRejectBlock)reject;
13
+
14
+ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location;
15
+
16
+ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error;
17
+
18
+ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
19
+ didWriteData:(int64_t)bytesWritten
20
+ totalBytesWritten:(int64_t)totalBytesWritten
21
+ totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
22
+
23
+ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data;
24
+
25
+ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
26
+ didSendBodyData:(int64_t)bytesSent
27
+ totalBytesSent:(int64_t)totalBytesSent
28
+ totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend;
29
+
30
+ - (NSDictionary *)parseServerResponse:(NSURLResponse *)response;
31
+
32
+ @end
@@ -0,0 +1,58 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoFileSystem/EXSessionTaskDelegate.h>
4
+
5
+ @implementation EXSessionTaskDelegate
6
+
7
+ - (nonnull instancetype)initWithResolve:(EXPromiseResolveBlock)resolve
8
+ reject:(EXPromiseRejectBlock)reject
9
+ {
10
+ if (self = [super init]) {
11
+ _resolve = resolve;
12
+ _reject = reject;
13
+ }
14
+ return self;
15
+ }
16
+
17
+ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
18
+ {
19
+ if (error) {
20
+ self.reject(@"ERR_FILESYSTEM_CANNOT_DOWNLOAD",
21
+ [NSString stringWithFormat:@"Unable to download file: %@", error.description],
22
+ error);
23
+ }
24
+ }
25
+
26
+ - (NSDictionary *)parseServerResponse:(NSURLResponse *)response
27
+ {
28
+ NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
29
+ return @{
30
+ @"status": @([httpResponse statusCode]),
31
+ @"headers": [httpResponse allHeaderFields],
32
+ @"mimeType": EXNullIfNil([httpResponse MIMEType])
33
+ };
34
+ }
35
+
36
+ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
37
+ {
38
+ }
39
+
40
+ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
41
+ didWriteData:(int64_t)bytesWritten
42
+ totalBytesWritten:(int64_t)totalBytesWritten
43
+ totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
44
+ {
45
+ }
46
+
47
+ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
48
+ {
49
+ }
50
+
51
+ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
52
+ didSendBodyData:(int64_t)bytesSent
53
+ totalBytesSent:(int64_t)totalBytesSent
54
+ totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
55
+ {
56
+ }
57
+
58
+ @end
@@ -0,0 +1,19 @@
1
+ // Copyright 2015-present 650 Industries. All rights reserved.
2
+
3
+ #import <Foundation/Foundation.h>
4
+ #import <ExpoFileSystem/EXSessionTaskDelegate.h>
5
+ #import <ExpoFileSystem/EXSessionHandler.h>
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ @interface EXSessionTaskDispatcher : NSObject <NSURLSessionDelegate>
10
+
11
+ - (instancetype)initWithSessionHandler:(nullable id<EXSessionHandler>)sessionHandler;
12
+
13
+ - (void)registerTaskDelegate:(EXSessionTaskDelegate *)delegate forTask:(NSURLSessionTask *)task;
14
+
15
+ - (void)deactivate;
16
+
17
+ @end
18
+
19
+ NS_ASSUME_NONNULL_END