@react-native-firebase/storage 26.3.3 → 27.0.0
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.
- package/CHANGELOG.md +21 -0
- package/RNFBStorage.podspec +9 -4
- package/android/build.gradle +6 -0
- package/android/src/main/java/io/invertase/firebase/storage/NativeRNFBTurboStorage.java +24 -4
- package/android/src/main/java/io/invertase/firebase/storage/RNFBStorageTaskRegistry.kt +88 -0
- package/android/src/main/java/io/invertase/firebase/storage/ReactNativeFirebaseStorageTask.java +25 -46
- package/android/src/main/java/io/invertase/firebase/storage/StoragePendingHandle.java +30 -0
- package/android/src/test/java/io/invertase/firebase/storage/RNFBStorageTaskRegistryTest.java +237 -0
- package/android/src/test/java/io/invertase/firebase/storage/ReactNativeFirebaseStorageTaskTest.java +285 -0
- package/dist/module/index.js +1 -2
- package/dist/module/index.js.map +1 -1
- package/dist/module/version.js +1 -1
- package/dist/typescript/lib/index.d.ts +1 -1
- package/dist/typescript/lib/types/internal.d.ts +2 -3
- package/dist/typescript/lib/types/internal.d.ts.map +1 -1
- package/dist/typescript/lib/version.d.ts +1 -1
- package/ios/RNFBStorage/RNFBStorageCommon.m +17 -98
- package/ios/RNFBStorage/RNFBStorageErrorCodeMapper.swift +122 -0
- package/ios/RNFBStorage/RNFBStorageErrorSnapshotDictBuilder.swift +70 -0
- package/ios/RNFBStorage/RNFBStorageHelper.m +38 -13
- package/ios/RNFBStorage/RNFBStorageTaskRegistry.h +42 -0
- package/ios/RNFBStorage/RNFBStorageTaskRegistry.m +87 -0
- package/ios/RNFBStorage/RNFBStorageTaskRegistryStorage.swift +87 -0
- package/ios/RNFBStorage/RNFBStorageTaskStatusMapper.swift +57 -0
- package/ios/RNFBStorage.xcodeproj/project.pbxproj +26 -0
- package/ios/RNFBStorageUnitTests/RNFBStorageErrorCodeMapperFacadeTests.m +91 -0
- package/ios/RNFBStorageUnitTests/RNFBStorageErrorCodeMapperTests.swift +211 -0
- package/ios/RNFBStorageUnitTests/RNFBStorageErrorSnapshotDictBuilderFacadeTests.m +125 -0
- package/ios/RNFBStorageUnitTests/RNFBStorageTaskRegistryStorageTests.swift +154 -0
- package/ios/RNFBStorageUnitTests/RNFBStorageTaskRegistryTests.m +225 -0
- package/ios/RNFBStorageUnitTests/RNFBStorageTaskStatusMapperFacadeTests.m +52 -0
- package/ios/RNFBStorageUnitTests/RNFBStorageTaskStatusMapperTests.swift +58 -0
- package/ios/RNFBStorageUnitTests/RNFBStorageUnitTests.xcodeproj/project.pbxproj +301 -0
- package/ios/RNFBStorageUnitTests/RNFBStorageUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBStorageUnitTests.xcscheme +69 -0
- package/lib/index.ts +1 -1
- package/lib/types/internal.ts +5 -4
- package/lib/version.ts +1 -1
- package/package.json +5 -4
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this library except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import Foundation
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* `FIRStorageErrorCode` raw value → JS error-code / message mapping previously
|
|
21
|
+
* inline in `+[RNFBStorageCommon getErrorCodeMessage:]`.
|
|
22
|
+
*
|
|
23
|
+
* Raw ints from Firebase Storage `StorageErrorCode`
|
|
24
|
+
* (`@objc(FIRStorageErrorCode)` in `StorageError.swift`):
|
|
25
|
+
* - unknown = -13000, objectNotFound = -13010, …
|
|
26
|
+
*
|
|
27
|
+
* Hardcoded so the Storage unit target does not need FirebaseStorage.
|
|
28
|
+
*/
|
|
29
|
+
@objc(RNFBStorageErrorCodeMapper)
|
|
30
|
+
public final class RNFBStorageErrorCodeMapper: NSObject {
|
|
31
|
+
/// `FIRStorageErrorCodeUnknown`
|
|
32
|
+
private static let codeUnknown = -13000
|
|
33
|
+
/// `FIRStorageErrorCodeObjectNotFound`
|
|
34
|
+
private static let codeObjectNotFound = -13010
|
|
35
|
+
/// `FIRStorageErrorCodeBucketNotFound`
|
|
36
|
+
private static let codeBucketNotFound = -13011
|
|
37
|
+
/// `FIRStorageErrorCodeProjectNotFound`
|
|
38
|
+
private static let codeProjectNotFound = -13012
|
|
39
|
+
/// `FIRStorageErrorCodeQuotaExceeded`
|
|
40
|
+
private static let codeQuotaExceeded = -13013
|
|
41
|
+
/// `FIRStorageErrorCodeUnauthenticated`
|
|
42
|
+
private static let codeUnauthenticated = -13020
|
|
43
|
+
/// `FIRStorageErrorCodeUnauthorized`
|
|
44
|
+
private static let codeUnauthorized = -13021
|
|
45
|
+
/// `FIRStorageErrorCodeRetryLimitExceeded`
|
|
46
|
+
private static let codeRetryLimitExceeded = -13030
|
|
47
|
+
/// `FIRStorageErrorCodeNonMatchingChecksum`
|
|
48
|
+
private static let codeNonMatchingChecksum = -13031
|
|
49
|
+
/// `FIRStorageErrorCodeDownloadSizeExceeded`
|
|
50
|
+
private static let codeDownloadSizeExceeded = -13032
|
|
51
|
+
/// `FIRStorageErrorCodeCancelled`
|
|
52
|
+
private static let codeCancelled = -13040
|
|
53
|
+
|
|
54
|
+
/// Exact pre-port string (U+2019 apostrophe in "couldn't").
|
|
55
|
+
private static let permissionDeniedUnderlying =
|
|
56
|
+
"The operation couldn’t be completed. Permission denied"
|
|
57
|
+
|
|
58
|
+
@objc(codeAndMessageForError:)
|
|
59
|
+
public static func codeAndMessage(for error: NSError?) -> [String] {
|
|
60
|
+
var code = "unknown"
|
|
61
|
+
|
|
62
|
+
guard let error else {
|
|
63
|
+
return [code, "An unknown error has occurred."]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
var message = error.localizedDescription
|
|
67
|
+
let userInfo = error.userInfo
|
|
68
|
+
let underlyingError = userInfo[NSUnderlyingErrorKey] as? NSError
|
|
69
|
+
let underlyingErrorDescription = underlyingError?.localizedDescription
|
|
70
|
+
|
|
71
|
+
switch error.code {
|
|
72
|
+
case codeUnknown:
|
|
73
|
+
if underlyingErrorDescription == permissionDeniedUnderlying {
|
|
74
|
+
code = "invalid-device-file-path"
|
|
75
|
+
message = "The specified device file path is invalid or is restricted."
|
|
76
|
+
} else if let responseBody = userInfo["ResponseBody"] {
|
|
77
|
+
message =
|
|
78
|
+
"An unknown error has occurred. (underlying reason '\(responseBody)')"
|
|
79
|
+
} else {
|
|
80
|
+
message = "An unknown error has occurred."
|
|
81
|
+
}
|
|
82
|
+
case codeObjectNotFound:
|
|
83
|
+
code = "object-not-found"
|
|
84
|
+
message = "No object exists at the desired reference."
|
|
85
|
+
case codeBucketNotFound:
|
|
86
|
+
code = "bucket-not-found"
|
|
87
|
+
message = "No bucket is configured for Firebase Storage."
|
|
88
|
+
case codeProjectNotFound:
|
|
89
|
+
code = "project-not-found"
|
|
90
|
+
message = "No project is configured for Firebase Storage."
|
|
91
|
+
case codeQuotaExceeded:
|
|
92
|
+
code = "quota-exceeded"
|
|
93
|
+
message = "Quota on your Firebase Storage bucket has been exceeded."
|
|
94
|
+
case codeUnauthenticated:
|
|
95
|
+
code = "unauthenticated"
|
|
96
|
+
message = "User is unauthenticated. Authenticate and try again."
|
|
97
|
+
case codeUnauthorized:
|
|
98
|
+
code = "unauthorized"
|
|
99
|
+
message = "User is not authorized to perform the desired action."
|
|
100
|
+
case codeRetryLimitExceeded:
|
|
101
|
+
code = "retry-limit-exceeded"
|
|
102
|
+
message =
|
|
103
|
+
"The maximum time limit on an operation (upload, download, delete, etc.) has been "
|
|
104
|
+
+ "exceeded."
|
|
105
|
+
case codeNonMatchingChecksum:
|
|
106
|
+
code = "non-matching-checksum"
|
|
107
|
+
message =
|
|
108
|
+
"File on the client does not match the checksum of the file received by the server."
|
|
109
|
+
case codeDownloadSizeExceeded:
|
|
110
|
+
code = "download-size-exceeded"
|
|
111
|
+
message =
|
|
112
|
+
"Size of the downloaded file exceeds the amount of memory allocated for the download."
|
|
113
|
+
case codeCancelled:
|
|
114
|
+
code = "cancelled"
|
|
115
|
+
message = "User cancelled the operation."
|
|
116
|
+
default:
|
|
117
|
+
break
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return [code, message]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this library except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import Foundation
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Error payload attachment previously inline in
|
|
21
|
+
* `+[RNFBStorageCommon buildErrorSnapshotDict:taskSnapshotDict:]` and
|
|
22
|
+
* `+[RNFBStorageCommon buildErrorSnapshotDictFromCodeAndMessage:taskSnapshotDict:]`.
|
|
23
|
+
*
|
|
24
|
+
* Mutates `taskSnapshotDict` in place and returns the same instance (or nil when
|
|
25
|
+
* the snapshot dict is nil — matching ObjC nil-messaging).
|
|
26
|
+
*/
|
|
27
|
+
@objc(RNFBStorageErrorSnapshotDictBuilder)
|
|
28
|
+
public final class RNFBStorageErrorSnapshotDictBuilder: NSObject {
|
|
29
|
+
@objc(buildErrorSnapshotDict:taskSnapshotDict:)
|
|
30
|
+
public static func buildErrorSnapshotDict(
|
|
31
|
+
_ error: NSError?,
|
|
32
|
+
taskSnapshotDict: NSMutableDictionary?
|
|
33
|
+
) -> NSDictionary? {
|
|
34
|
+
guard let taskSnapshotDict else {
|
|
35
|
+
return nil
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let codeAndMessage = RNFBStorageErrorCodeMapper.codeAndMessage(for: error)
|
|
39
|
+
var errorPayload: [String: Any] = [
|
|
40
|
+
"code": codeAndMessage[0],
|
|
41
|
+
"message": codeAndMessage[1],
|
|
42
|
+
]
|
|
43
|
+
// Pre-port ObjC always set this key from `[error localizedDescription]`.
|
|
44
|
+
if let error {
|
|
45
|
+
errorPayload["nativeErrorMessage"] = error.localizedDescription
|
|
46
|
+
} else {
|
|
47
|
+
errorPayload["nativeErrorMessage"] = NSNull()
|
|
48
|
+
}
|
|
49
|
+
taskSnapshotDict["error"] = errorPayload
|
|
50
|
+
return taskSnapshotDict
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@objc(buildErrorSnapshotDictFromCodeAndMessage:taskSnapshotDict:)
|
|
54
|
+
public static func buildErrorSnapshotDictFromCodeAndMessage(
|
|
55
|
+
_ codeAndMessage: [Any]?,
|
|
56
|
+
taskSnapshotDict: NSMutableDictionary?
|
|
57
|
+
) -> NSDictionary? {
|
|
58
|
+
guard let taskSnapshotDict else {
|
|
59
|
+
return nil
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Pre-port ObjC indexed without bounds checks; callers always pass [code, message].
|
|
63
|
+
let pair = codeAndMessage!
|
|
64
|
+
taskSnapshotDict["error"] = [
|
|
65
|
+
"code": pair[0],
|
|
66
|
+
"message": pair[1],
|
|
67
|
+
]
|
|
68
|
+
return taskSnapshotDict
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
#import "RNFBRCTEventEmitter.h"
|
|
29
29
|
#import "RNFBStorageCommon.h"
|
|
30
30
|
#import "RNFBStorageHelper.h"
|
|
31
|
+
#import "RNFBStorageTaskRegistry.h"
|
|
31
32
|
|
|
32
33
|
static NSString *const RNFB_STORAGE_EVENT = @"storage_event";
|
|
33
34
|
static NSString *const RNFB_STORAGE_STATE_CHANGED = @"state_changed";
|
|
@@ -36,7 +37,7 @@ static NSString *const RNFB_STORAGE_UPLOAD_FAILURE = @"upload_failure";
|
|
|
36
37
|
static NSString *const RNFB_STORAGE_DOWNLOAD_SUCCESS = @"download_success";
|
|
37
38
|
static NSString *const RNFB_STORAGE_DOWNLOAD_FAILURE = @"download_failure";
|
|
38
39
|
|
|
39
|
-
static
|
|
40
|
+
static RNFBStorageTaskRegistry *pendingTasks;
|
|
40
41
|
|
|
41
42
|
// The iOS SDK has a short memory on settings, store these globally and set them in each time
|
|
42
43
|
static NSString *emulatorHost = nil;
|
|
@@ -54,16 +55,14 @@ static NSTimeInterval maxOperationRetryTime = 120;
|
|
|
54
55
|
+ (void)initializeSharedStateOnce {
|
|
55
56
|
static dispatch_once_t onceToken;
|
|
56
57
|
dispatch_once(&onceToken, ^{
|
|
57
|
-
|
|
58
|
+
pendingTasks = [[RNFBStorageTaskRegistry alloc] init];
|
|
58
59
|
emulatorConfigs = [[NSMutableDictionary alloc] init];
|
|
59
60
|
});
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
+ (void)invalidate {
|
|
63
64
|
[self initializeSharedStateOnce];
|
|
64
|
-
|
|
65
|
-
[PENDING_TASKS removeObjectForKey:key];
|
|
66
|
-
}
|
|
65
|
+
[pendingTasks cancelAll];
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
#pragma mark -
|
|
@@ -283,7 +282,10 @@ static NSTimeInterval maxOperationRetryTime = 120;
|
|
|
283
282
|
downloadTask = [storageReference writeToFile:localFile];
|
|
284
283
|
});
|
|
285
284
|
|
|
286
|
-
|
|
285
|
+
if (![pendingTasks putOrDiscard:taskIdNumber value:downloadTask]) {
|
|
286
|
+
reject(@"internal", @"Handle id already registered", nil);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
287
289
|
|
|
288
290
|
[downloadTask
|
|
289
291
|
observeStatus:FIRStorageTaskStatusResume
|
|
@@ -324,7 +326,10 @@ static NSTimeInterval maxOperationRetryTime = 120;
|
|
|
324
326
|
[downloadTask
|
|
325
327
|
observeStatus:FIRStorageTaskStatusSuccess
|
|
326
328
|
handler:^(FIRStorageTaskSnapshot *snapshot) {
|
|
327
|
-
[
|
|
329
|
+
[pendingTasks takeIf:taskIdNumber
|
|
330
|
+
when:^BOOL(id value) {
|
|
331
|
+
return value == downloadTask;
|
|
332
|
+
}];
|
|
328
333
|
|
|
329
334
|
NSDictionary *stateChangedEventBody =
|
|
330
335
|
[RNFBStorageCommon getDownloadTaskAsDictionary:snapshot];
|
|
@@ -349,7 +354,10 @@ static NSTimeInterval maxOperationRetryTime = 120;
|
|
|
349
354
|
[downloadTask
|
|
350
355
|
observeStatus:FIRStorageTaskStatusFailure
|
|
351
356
|
handler:^(FIRStorageTaskSnapshot *snapshot) {
|
|
352
|
-
[
|
|
357
|
+
[pendingTasks takeIf:taskIdNumber
|
|
358
|
+
when:^BOOL(id value) {
|
|
359
|
+
return value == downloadTask;
|
|
360
|
+
}];
|
|
353
361
|
|
|
354
362
|
NSDictionary *stateChangedEventBody =
|
|
355
363
|
[RNFBStorageCommon getDownloadTaskAsDictionary:snapshot];
|
|
@@ -501,7 +509,7 @@ static NSTimeInterval maxOperationRetryTime = 120;
|
|
|
501
509
|
+ (NSNumber *)setTaskStatus:(NSString *)appName taskId:(double)taskId status:(double)status {
|
|
502
510
|
[self initializeSharedStateOnce];
|
|
503
511
|
NSNumber *taskIdNumber = @(taskId);
|
|
504
|
-
id task =
|
|
512
|
+
id task = [pendingTasks get:taskIdNumber];
|
|
505
513
|
if (task == nil) {
|
|
506
514
|
return @NO;
|
|
507
515
|
}
|
|
@@ -546,7 +554,15 @@ static NSTimeInterval maxOperationRetryTime = 120;
|
|
|
546
554
|
(currentStatus == FIRStorageTaskStatusResume ||
|
|
547
555
|
currentStatus == FIRStorageTaskStatusProgress ||
|
|
548
556
|
currentStatus == FIRStorageTaskStatusPause)) {
|
|
549
|
-
|
|
557
|
+
// Identity take then cancel so a replacement at taskId is not stolen.
|
|
558
|
+
// Ordering differs from registry takeAndCancel: (takeIf → cancel) vs Android
|
|
559
|
+
// (get → cancel → takeIf). Both are identity-safe; FIRStorage cancel is void.
|
|
560
|
+
if ([pendingTasks takeIf:taskIdNumber
|
|
561
|
+
when:^BOOL(id value) {
|
|
562
|
+
return value == task;
|
|
563
|
+
}] == nil) {
|
|
564
|
+
return @NO;
|
|
565
|
+
}
|
|
550
566
|
if ([task isKindOfClass:[FIRStorageDownloadTask class]]) {
|
|
551
567
|
[(FIRStorageDownloadTask *)task cancel];
|
|
552
568
|
} else {
|
|
@@ -595,7 +611,10 @@ static NSTimeInterval maxOperationRetryTime = 120;
|
|
|
595
611
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
596
612
|
rejecter:(RCTPromiseRejectBlock)reject {
|
|
597
613
|
[self initializeSharedStateOnce];
|
|
598
|
-
|
|
614
|
+
if (![pendingTasks putOrDiscard:taskId value:uploadTask]) {
|
|
615
|
+
reject(@"internal", @"Handle id already registered", nil);
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
599
618
|
|
|
600
619
|
[uploadTask
|
|
601
620
|
observeStatus:FIRStorageTaskStatusResume
|
|
@@ -635,7 +654,10 @@ static NSTimeInterval maxOperationRetryTime = 120;
|
|
|
635
654
|
|
|
636
655
|
[uploadTask observeStatus:FIRStorageTaskStatusSuccess
|
|
637
656
|
handler:^(FIRStorageTaskSnapshot *snapshot) {
|
|
638
|
-
[
|
|
657
|
+
[pendingTasks takeIf:taskId
|
|
658
|
+
when:^BOOL(id value) {
|
|
659
|
+
return value == uploadTask;
|
|
660
|
+
}];
|
|
639
661
|
|
|
640
662
|
NSDictionary *eventBody =
|
|
641
663
|
[RNFBStorageCommon getUploadTaskAsDictionary:snapshot];
|
|
@@ -661,7 +683,10 @@ static NSTimeInterval maxOperationRetryTime = 120;
|
|
|
661
683
|
[uploadTask
|
|
662
684
|
observeStatus:FIRStorageTaskStatusFailure
|
|
663
685
|
handler:^(FIRStorageTaskSnapshot *snapshot) {
|
|
664
|
-
[
|
|
686
|
+
[pendingTasks takeIf:taskId
|
|
687
|
+
when:^BOOL(id value) {
|
|
688
|
+
return value == uploadTask;
|
|
689
|
+
}];
|
|
665
690
|
|
|
666
691
|
NSMutableDictionary *taskSnapshotDict =
|
|
667
692
|
[RNFBStorageCommon getUploadTaskAsDictionary:snapshot];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this library except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#import <Foundation/Foundation.h>
|
|
19
|
+
|
|
20
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Pending upload/download task map. Unique `put`; callers `take` or `cancelAll` then cancel
|
|
24
|
+
* outside the HandleMap lock. Stored values are expected to respond to `cancel`.
|
|
25
|
+
*/
|
|
26
|
+
@interface RNFBStorageTaskRegistry : NSObject
|
|
27
|
+
|
|
28
|
+
- (BOOL)put:(id)key value:(id)value error:(NSError *_Nullable *_Nullable)error;
|
|
29
|
+
/// Unique put. On collision, `cancel`s the incoming value and leaves the existing mapping.
|
|
30
|
+
- (BOOL)putOrDiscard:(id)key value:(id)value;
|
|
31
|
+
- (nullable id)get:(id)key;
|
|
32
|
+
- (nullable id)take:(id)key;
|
|
33
|
+
/// Identity-gated take; see RNFBHandleMap `takeIf:when:`.
|
|
34
|
+
- (nullable id)takeIf:(id)key when:(BOOL (^)(id value))condition;
|
|
35
|
+
/// get → cancel → identity take (Android shape). FIRStorage cancel is void (no keep-on-false).
|
|
36
|
+
/// Production setTaskStatus cancel uses takeIf then cancel; see RNFBStorageHelper.
|
|
37
|
+
- (BOOL)takeAndCancel:(id)key;
|
|
38
|
+
- (void)cancelAll;
|
|
39
|
+
|
|
40
|
+
@end
|
|
41
|
+
|
|
42
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this library except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#import "RNFBStorageTaskRegistry.h"
|
|
19
|
+
|
|
20
|
+
#if __has_include("RNFBHandleMap.h")
|
|
21
|
+
#import "RNFBHandleMap.h"
|
|
22
|
+
#else
|
|
23
|
+
#import "RNFBApp/RNFBHandleMap.h"
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
#if __has_include(<RNFBStorage/RNFBStorage-Swift.h>)
|
|
27
|
+
#import <RNFBStorage/RNFBStorage-Swift.h>
|
|
28
|
+
#elif __has_include("RNFBStorage-Swift.h")
|
|
29
|
+
#import "RNFBStorage-Swift.h"
|
|
30
|
+
#elif __has_include("RNFBHandleMapStorage-Swift.inc")
|
|
31
|
+
#import "RNFBHandleMapStorage-Swift.inc"
|
|
32
|
+
#else
|
|
33
|
+
#error "RNFBStorageTaskRegistryStorage Swift interface not found"
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
@interface RNFBStorageTaskRegistry ()
|
|
37
|
+
@property(nonatomic, strong) RNFBStorageTaskRegistryStorage *storage;
|
|
38
|
+
@end
|
|
39
|
+
|
|
40
|
+
@implementation RNFBStorageTaskRegistry
|
|
41
|
+
|
|
42
|
+
- (instancetype)init {
|
|
43
|
+
self = [super init];
|
|
44
|
+
if (self) {
|
|
45
|
+
_storage = [[RNFBStorageTaskRegistryStorage alloc] init];
|
|
46
|
+
}
|
|
47
|
+
return self;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
- (BOOL)put:(id)key value:(id)value error:(NSError **)error {
|
|
51
|
+
if (![self.storage putIfAbsent:key value:value]) {
|
|
52
|
+
if (error != nil) {
|
|
53
|
+
NSString *message = [NSString stringWithFormat:@"Handle id already registered: %@", key];
|
|
54
|
+
*error = [NSError errorWithDomain:RNFBHandleMapErrorDomain
|
|
55
|
+
code:RNFBHandleMapErrorCollision
|
|
56
|
+
userInfo:@{NSLocalizedDescriptionKey : message}];
|
|
57
|
+
}
|
|
58
|
+
return NO;
|
|
59
|
+
}
|
|
60
|
+
return YES;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
- (BOOL)putOrDiscard:(id)key value:(id)value {
|
|
64
|
+
return [self.storage putOrDiscard:key value:value];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
- (id)get:(id)key {
|
|
68
|
+
return [self.storage get:key];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
- (id)take:(id)key {
|
|
72
|
+
return [self.storage take:key];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
- (id)takeIf:(id)key when:(BOOL (^)(id))condition {
|
|
76
|
+
return [self.storage takeIf:key when:condition];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
- (BOOL)takeAndCancel:(id)key {
|
|
80
|
+
return [self.storage takeAndCancel:key];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
- (void)cancelAll {
|
|
84
|
+
[self.storage cancelAll];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this library except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import Foundation
|
|
18
|
+
|
|
19
|
+
#if canImport(RNFBApp)
|
|
20
|
+
import RNFBApp
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
/// Pending upload/download task map storage. Composes `RNFBHandleMapStorage`.
|
|
24
|
+
/// `putOrDiscard` is first-wins and calls `cancel` on the incoming value on collision.
|
|
25
|
+
/// Unique `put` collision errors stay on the ObjC façade.
|
|
26
|
+
@objc(RNFBStorageTaskRegistryStorage)
|
|
27
|
+
public final class RNFBStorageTaskRegistryStorage: NSObject {
|
|
28
|
+
private static let cancelSelector = Selector(("cancel"))
|
|
29
|
+
|
|
30
|
+
private let storage = RNFBHandleMapStorage()
|
|
31
|
+
|
|
32
|
+
private func cancelHandle(_ handle: AnyObject?) {
|
|
33
|
+
guard let handle = handle, handle.responds(to: Self.cancelSelector) else {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
_ = handle.perform(Self.cancelSelector)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// First-wins store without discarding the incoming value. Used by façade `put`.
|
|
40
|
+
@objc(putIfAbsent:value:)
|
|
41
|
+
public func putIfAbsent(_ key: AnyObject, value: AnyObject) -> Bool {
|
|
42
|
+
storage.putIfAbsent(key, value: value)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// Unique put. On collision, `cancel`s the incoming value and leaves the existing mapping.
|
|
46
|
+
@objc(putOrDiscard:value:)
|
|
47
|
+
public func putOrDiscard(_ key: AnyObject, value: AnyObject) -> Bool {
|
|
48
|
+
if storage.putIfAbsent(key, value: value) {
|
|
49
|
+
return true
|
|
50
|
+
}
|
|
51
|
+
cancelHandle(value)
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@objc(get:)
|
|
56
|
+
public func get(_ key: AnyObject) -> AnyObject? {
|
|
57
|
+
storage.get(key)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@objc(take:)
|
|
61
|
+
public func take(_ key: AnyObject) -> AnyObject? {
|
|
62
|
+
storage.take(key)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@objc(takeIf:when:)
|
|
66
|
+
public func takeIf(_ key: AnyObject, when condition: (AnyObject) -> Bool) -> AnyObject? {
|
|
67
|
+
storage.takeIf(key, when: condition)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// get → cancel → identity take (Android shape). FIRStorage cancel is void (no keep-on-false).
|
|
71
|
+
@objc(takeAndCancel:)
|
|
72
|
+
public func takeAndCancel(_ key: AnyObject) -> Bool {
|
|
73
|
+
guard let handle = storage.get(key) else {
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
cancelHandle(handle)
|
|
77
|
+
_ = storage.takeIf(key, when: { $0 === handle })
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@objc
|
|
82
|
+
public func cancelAll() {
|
|
83
|
+
for handle in storage.takeAll() {
|
|
84
|
+
cancelHandle(handle)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this library except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import Foundation
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* `FIRStorageTaskStatus` raw value → JS task-state string mapping previously
|
|
21
|
+
* inline in `+[RNFBStorageCommon getTaskStatus:]`.
|
|
22
|
+
*
|
|
23
|
+
* Raw ints from Firebase Storage `StorageTaskStatus`
|
|
24
|
+
* (`@objc(FIRStorageTaskStatus)` in `StorageConstants.swift`):
|
|
25
|
+
* - unknown = 0, resume = 1, progress = 2, pause = 3, success = 4, failure = 5
|
|
26
|
+
*
|
|
27
|
+
* Hardcoded so the Storage unit target does not need FirebaseStorage.
|
|
28
|
+
*/
|
|
29
|
+
@objc(RNFBStorageTaskStatusMapper)
|
|
30
|
+
public final class RNFBStorageTaskStatusMapper: NSObject {
|
|
31
|
+
/// `FIRStorageTaskStatusResume`
|
|
32
|
+
private static let statusResume = 1
|
|
33
|
+
/// `FIRStorageTaskStatusProgress`
|
|
34
|
+
private static let statusProgress = 2
|
|
35
|
+
/// `FIRStorageTaskStatusPause`
|
|
36
|
+
private static let statusPause = 3
|
|
37
|
+
/// `FIRStorageTaskStatusSuccess`
|
|
38
|
+
private static let statusSuccess = 4
|
|
39
|
+
/// `FIRStorageTaskStatusFailure`
|
|
40
|
+
private static let statusFailure = 5
|
|
41
|
+
|
|
42
|
+
@objc(stringForTaskStatus:)
|
|
43
|
+
public static func string(forTaskStatus status: Int) -> String {
|
|
44
|
+
if status == statusResume || status == statusProgress {
|
|
45
|
+
return "running"
|
|
46
|
+
} else if status == statusPause {
|
|
47
|
+
return "paused"
|
|
48
|
+
} else if status == statusSuccess {
|
|
49
|
+
return "success"
|
|
50
|
+
} else if status == statusFailure {
|
|
51
|
+
return "error"
|
|
52
|
+
} else {
|
|
53
|
+
// `FIRStorageTaskStatusUnknown` (0) and any other raw value
|
|
54
|
+
return "unknown"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
27A35B652268E118005BE5A8 /* RNFBStorageDownloadTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A35B642268E118005BE5A8 /* RNFBStorageDownloadTask.m */; };
|
|
13
13
|
27A35B682268E138005BE5A8 /* RNFBStorageUploadTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A35B672268E138005BE5A8 /* RNFBStorageUploadTask.m */; };
|
|
14
14
|
27A35B6B2268E1BE005BE5A8 /* RNFBStorageCommon.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A35B6A2268E1BE005BE5A8 /* RNFBStorageCommon.m */; };
|
|
15
|
+
RNFBSTOR0000000000000001 /* RNFBStorageTaskRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = RNFBSTOR0000000000000002 /* RNFBStorageTaskRegistry.m */; };
|
|
16
|
+
RNFBSTOR0000000000000003 /* RNFBStorageTaskRegistryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBSTOR0000000000000004 /* RNFBStorageTaskRegistryStorage.swift */; };
|
|
17
|
+
RNFBSTOR0000000000000006 /* RNFBStorageTaskStatusMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBSTOR0000000000000007 /* RNFBStorageTaskStatusMapper.swift */; };
|
|
18
|
+
RNFBSTOR0000000000000008 /* RNFBStorageErrorCodeMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBSTOR0000000000000009 /* RNFBStorageErrorCodeMapper.swift */; };
|
|
19
|
+
RNFBSTOR000000000000000A /* RNFBStorageErrorSnapshotDictBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = RNFBSTOR000000000000000B /* RNFBStorageErrorSnapshotDictBuilder.swift */; };
|
|
15
20
|
/* End PBXBuildFile section */
|
|
16
21
|
|
|
17
22
|
/* Begin PBXCopyFilesBuildPhase section */
|
|
@@ -38,6 +43,12 @@
|
|
|
38
43
|
27A35B692268E143005BE5A8 /* RNFBStorageUploadTask.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBStorageUploadTask.h; sourceTree = "<group>"; };
|
|
39
44
|
27A35B6A2268E1BE005BE5A8 /* RNFBStorageCommon.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFBStorageCommon.m; sourceTree = "<group>"; };
|
|
40
45
|
27A35B6C2268E1C8005BE5A8 /* RNFBStorageCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFBStorageCommon.h; sourceTree = "<group>"; };
|
|
46
|
+
RNFBSTOR0000000000000005 /* RNFBStorageTaskRegistry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFBStorageTaskRegistry.h; path = RNFBStorage/RNFBStorageTaskRegistry.h; sourceTree = SOURCE_ROOT; };
|
|
47
|
+
RNFBSTOR0000000000000002 /* RNFBStorageTaskRegistry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFBStorageTaskRegistry.m; path = RNFBStorage/RNFBStorageTaskRegistry.m; sourceTree = SOURCE_ROOT; };
|
|
48
|
+
RNFBSTOR0000000000000004 /* RNFBStorageTaskRegistryStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBStorageTaskRegistryStorage.swift; path = RNFBStorage/RNFBStorageTaskRegistryStorage.swift; sourceTree = SOURCE_ROOT; };
|
|
49
|
+
RNFBSTOR0000000000000007 /* RNFBStorageTaskStatusMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBStorageTaskStatusMapper.swift; path = RNFBStorage/RNFBStorageTaskStatusMapper.swift; sourceTree = SOURCE_ROOT; };
|
|
50
|
+
RNFBSTOR0000000000000009 /* RNFBStorageErrorCodeMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBStorageErrorCodeMapper.swift; path = RNFBStorage/RNFBStorageErrorCodeMapper.swift; sourceTree = SOURCE_ROOT; };
|
|
51
|
+
RNFBSTOR000000000000000B /* RNFBStorageErrorSnapshotDictBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RNFBStorageErrorSnapshotDictBuilder.swift; path = RNFBStorage/RNFBStorageErrorSnapshotDictBuilder.swift; sourceTree = SOURCE_ROOT; };
|
|
41
52
|
/* End PBXFileReference section */
|
|
42
53
|
|
|
43
54
|
/* Begin PBXFrameworksBuildPhase section */
|
|
@@ -64,6 +75,12 @@
|
|
|
64
75
|
children = (
|
|
65
76
|
2744B98421F45429004F8E3F /* RNFBStorageModule.h */,
|
|
66
77
|
2744B98521F45429004F8E3F /* RNFBStorageModule.mm */,
|
|
78
|
+
RNFBSTOR0000000000000005 /* RNFBStorageTaskRegistry.h */,
|
|
79
|
+
RNFBSTOR0000000000000002 /* RNFBStorageTaskRegistry.m */,
|
|
80
|
+
RNFBSTOR0000000000000004 /* RNFBStorageTaskRegistryStorage.swift */,
|
|
81
|
+
RNFBSTOR0000000000000007 /* RNFBStorageTaskStatusMapper.swift */,
|
|
82
|
+
RNFBSTOR0000000000000009 /* RNFBStorageErrorCodeMapper.swift */,
|
|
83
|
+
RNFBSTOR000000000000000B /* RNFBStorageErrorSnapshotDictBuilder.swift */,
|
|
67
84
|
27A35B612268E0AB005BE5A8 /* RNFBStorageTask.m */,
|
|
68
85
|
27A35B632268E0CD005BE5A8 /* RNFBStorageTask.h */,
|
|
69
86
|
27A35B642268E118005BE5A8 /* RNFBStorageDownloadTask.m */,
|
|
@@ -142,6 +159,11 @@
|
|
|
142
159
|
isa = PBXSourcesBuildPhase;
|
|
143
160
|
buildActionMask = 2147483647;
|
|
144
161
|
files = (
|
|
162
|
+
RNFBSTOR0000000000000003 /* RNFBStorageTaskRegistryStorage.swift in Sources */,
|
|
163
|
+
RNFBSTOR0000000000000006 /* RNFBStorageTaskStatusMapper.swift in Sources */,
|
|
164
|
+
RNFBSTOR0000000000000008 /* RNFBStorageErrorCodeMapper.swift in Sources */,
|
|
165
|
+
RNFBSTOR000000000000000A /* RNFBStorageErrorSnapshotDictBuilder.swift in Sources */,
|
|
166
|
+
RNFBSTOR0000000000000001 /* RNFBStorageTaskRegistry.m in Sources */,
|
|
145
167
|
27A35B622268E0AB005BE5A8 /* RNFBStorageTask.m in Sources */,
|
|
146
168
|
27A35B6B2268E1BE005BE5A8 /* RNFBStorageCommon.m in Sources */,
|
|
147
169
|
2744B98621F45429004F8E3F /* RNFBStorageModule.mm in Sources */,
|
|
@@ -172,6 +194,7 @@
|
|
|
172
194
|
CODE_SIGN_STYLE = Automatic;
|
|
173
195
|
COPY_PHASE_STRIP = NO;
|
|
174
196
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
|
197
|
+
DEFINES_MODULE = YES;
|
|
175
198
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
176
199
|
GCC_DYNAMIC_NO_PIC = NO;
|
|
177
200
|
GCC_OPTIMIZATION_LEVEL = 0;
|
|
@@ -188,6 +211,7 @@
|
|
|
188
211
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
189
212
|
SDKROOT = iphoneos;
|
|
190
213
|
SKIP_INSTALL = YES;
|
|
214
|
+
SWIFT_VERSION = 5.10;
|
|
191
215
|
TARGETED_DEVICE_FAMILY = "1,2";
|
|
192
216
|
};
|
|
193
217
|
name = Debug;
|
|
@@ -211,6 +235,7 @@
|
|
|
211
235
|
CODE_SIGN_STYLE = Automatic;
|
|
212
236
|
COPY_PHASE_STRIP = NO;
|
|
213
237
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
238
|
+
DEFINES_MODULE = YES;
|
|
214
239
|
ENABLE_NS_ASSERTIONS = NO;
|
|
215
240
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
216
241
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
@@ -222,6 +247,7 @@
|
|
|
222
247
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
223
248
|
SDKROOT = iphoneos;
|
|
224
249
|
SKIP_INSTALL = YES;
|
|
250
|
+
SWIFT_VERSION = 5.10;
|
|
225
251
|
TARGETED_DEVICE_FAMILY = "1,2";
|
|
226
252
|
VALIDATE_PRODUCT = YES;
|
|
227
253
|
};
|