@onekeyfe/react-native-range-downloader 3.0.67 → 3.0.69
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/README.md +15 -0
- package/android/build.gradle +3 -0
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/ConcurrentRangeDownloader.kt +179 -11
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/RangeDownloadLogic.kt +98 -0
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/ReactNativeRangeDownloader.kt +24 -25
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/ConcurrentRangeDownloaderOcdsTest.kt +554 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/FaultServer.kt +282 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/IsPermanentHttpStatusTest.kt +63 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/MonotonicProgressGateTest.kt +368 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/Ocds416ResumeTest.kt +272 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/OcdsBadTotalRejectTest.kt +147 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/OcdsMultipartRejectTest.kt +114 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/OcdsReadOnlyFsTest.kt +250 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/OcdsTransient5xxTest.kt +275 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/RangeDownloadLogicTest.kt +124 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/RunRegistrySingleFlightTest.kt +217 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/SegmentArtifactSweepTest.kt +350 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/SmokeTest.kt +65 -0
- package/ios/RangeDownloadLogic.swift +187 -0
- package/ios/ReactNativeRangeDownloader.swift +669 -133
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts +7 -1
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JHybridReactNativeRangeDownloaderSpec.cpp +4 -0
- package/nitrogen/generated/android/c++/JRangeDownloadOutcome.hpp +6 -0
- package/nitrogen/generated/android/c++/JRangeDownloadParams.hpp +19 -3
- package/nitrogen/generated/android/c++/JRangeDownloadResult.hpp +9 -3
- package/nitrogen/generated/android/c++/JRangeFallbackKind.hpp +83 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/RangeDownloadOutcome.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/RangeDownloadParams.kt +15 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/RangeDownloadResult.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/RangeFallbackKind.kt +29 -0
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Bridge.hpp +18 -0
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Umbrella.hpp +3 -0
- package/nitrogen/generated/ios/c++/HybridReactNativeRangeDownloaderSpecSwift.hpp +3 -0
- package/nitrogen/generated/ios/swift/RangeDownloadOutcome.swift +8 -0
- package/nitrogen/generated/ios/swift/RangeDownloadParams.swift +93 -1
- package/nitrogen/generated/ios/swift/RangeDownloadResult.swift +24 -1
- package/nitrogen/generated/ios/swift/RangeFallbackKind.swift +72 -0
- package/nitrogen/generated/shared/c++/RangeDownloadOutcome.hpp +9 -1
- package/nitrogen/generated/shared/c++/RangeDownloadParams.hpp +18 -2
- package/nitrogen/generated/shared/c++/RangeDownloadResult.hpp +9 -2
- package/nitrogen/generated/shared/c++/RangeFallbackKind.hpp +108 -0
- package/package.json +1 -1
- package/src/ReactNativeRangeDownloader.nitro.ts +36 -2
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// RangeFallbackKind.swift
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents the JS union `RangeFallbackKind`, backed by a C++ enum.
|
|
10
|
+
*/
|
|
11
|
+
public typealias RangeFallbackKind = margelo.nitro.reactnativerangedownloader.RangeFallbackKind
|
|
12
|
+
|
|
13
|
+
public extension RangeFallbackKind {
|
|
14
|
+
/**
|
|
15
|
+
* Get a RangeFallbackKind for the given String value, or
|
|
16
|
+
* return `nil` if the given value was invalid/unknown.
|
|
17
|
+
*/
|
|
18
|
+
init?(fromString string: String) {
|
|
19
|
+
switch string {
|
|
20
|
+
case "serverIgnoredRange":
|
|
21
|
+
self = .serverignoredrange
|
|
22
|
+
case "rangeUnsupported":
|
|
23
|
+
self = .rangeunsupported
|
|
24
|
+
case "authExpired":
|
|
25
|
+
self = .authexpired
|
|
26
|
+
case "notFound":
|
|
27
|
+
self = .notfound
|
|
28
|
+
case "redirectRejected":
|
|
29
|
+
self = .redirectrejected
|
|
30
|
+
case "checksumMismatch":
|
|
31
|
+
self = .checksummismatch
|
|
32
|
+
case "multipartOrBadTotal":
|
|
33
|
+
self = .multipartorbadtotal
|
|
34
|
+
case "transientNetwork":
|
|
35
|
+
self = .transientnetwork
|
|
36
|
+
case "throttled":
|
|
37
|
+
self = .throttled
|
|
38
|
+
case "budgetExhausted":
|
|
39
|
+
self = .budgetexhausted
|
|
40
|
+
default:
|
|
41
|
+
return nil
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the String value this RangeFallbackKind represents.
|
|
47
|
+
*/
|
|
48
|
+
var stringValue: String {
|
|
49
|
+
switch self {
|
|
50
|
+
case .serverignoredrange:
|
|
51
|
+
return "serverIgnoredRange"
|
|
52
|
+
case .rangeunsupported:
|
|
53
|
+
return "rangeUnsupported"
|
|
54
|
+
case .authexpired:
|
|
55
|
+
return "authExpired"
|
|
56
|
+
case .notfound:
|
|
57
|
+
return "notFound"
|
|
58
|
+
case .redirectrejected:
|
|
59
|
+
return "redirectRejected"
|
|
60
|
+
case .checksummismatch:
|
|
61
|
+
return "checksumMismatch"
|
|
62
|
+
case .multipartorbadtotal:
|
|
63
|
+
return "multipartOrBadTotal"
|
|
64
|
+
case .transientnetwork:
|
|
65
|
+
return "transientNetwork"
|
|
66
|
+
case .throttled:
|
|
67
|
+
return "throttled"
|
|
68
|
+
case .budgetexhausted:
|
|
69
|
+
return "budgetExhausted"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -30,7 +30,9 @@ namespace margelo::nitro::reactnativerangedownloader {
|
|
|
30
30
|
*/
|
|
31
31
|
enum class RangeDownloadOutcome {
|
|
32
32
|
COMPLETED SWIFT_NAME(completed) = 0,
|
|
33
|
-
|
|
33
|
+
FALLBACKTRANSIENT SWIFT_NAME(fallbacktransient) = 1,
|
|
34
|
+
FALLBACKPERMANENT SWIFT_NAME(fallbackpermanent) = 2,
|
|
35
|
+
FALLBACK SWIFT_NAME(fallback) = 3,
|
|
34
36
|
} CLOSED_ENUM;
|
|
35
37
|
|
|
36
38
|
} // namespace margelo::nitro::reactnativerangedownloader
|
|
@@ -44,6 +46,8 @@ namespace margelo::nitro {
|
|
|
44
46
|
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
|
|
45
47
|
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
|
46
48
|
case hashString("completed"): return margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome::COMPLETED;
|
|
49
|
+
case hashString("fallbackTransient"): return margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome::FALLBACKTRANSIENT;
|
|
50
|
+
case hashString("fallbackPermanent"): return margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome::FALLBACKPERMANENT;
|
|
47
51
|
case hashString("fallback"): return margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome::FALLBACK;
|
|
48
52
|
default: [[unlikely]]
|
|
49
53
|
throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum RangeDownloadOutcome - invalid value!");
|
|
@@ -52,6 +56,8 @@ namespace margelo::nitro {
|
|
|
52
56
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome arg) {
|
|
53
57
|
switch (arg) {
|
|
54
58
|
case margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome::COMPLETED: return JSIConverter<std::string>::toJSI(runtime, "completed");
|
|
59
|
+
case margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome::FALLBACKTRANSIENT: return JSIConverter<std::string>::toJSI(runtime, "fallbackTransient");
|
|
60
|
+
case margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome::FALLBACKPERMANENT: return JSIConverter<std::string>::toJSI(runtime, "fallbackPermanent");
|
|
55
61
|
case margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome::FALLBACK: return JSIConverter<std::string>::toJSI(runtime, "fallback");
|
|
56
62
|
default: [[unlikely]]
|
|
57
63
|
throw std::invalid_argument("Cannot convert RangeDownloadOutcome to JS - invalid value: "
|
|
@@ -65,6 +71,8 @@ namespace margelo::nitro {
|
|
|
65
71
|
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
|
|
66
72
|
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
|
67
73
|
case hashString("completed"):
|
|
74
|
+
case hashString("fallbackTransient"):
|
|
75
|
+
case hashString("fallbackPermanent"):
|
|
68
76
|
case hashString("fallback"):
|
|
69
77
|
return true;
|
|
70
78
|
default:
|
|
@@ -44,10 +44,14 @@ namespace margelo::nitro::reactnativerangedownloader {
|
|
|
44
44
|
std::optional<std::string> expectedSha256 SWIFT_PRIVATE;
|
|
45
45
|
std::optional<double> segmentCount SWIFT_PRIVATE;
|
|
46
46
|
std::optional<double> minConcurrentBytes SWIFT_PRIVATE;
|
|
47
|
+
std::optional<double> maxSegmentAttempts SWIFT_PRIVATE;
|
|
48
|
+
std::optional<double> requestTimeoutSeconds SWIFT_PRIVATE;
|
|
49
|
+
std::optional<double> stallTimeoutSeconds SWIFT_PRIVATE;
|
|
50
|
+
std::optional<double> overallDeadlineSeconds SWIFT_PRIVATE;
|
|
47
51
|
|
|
48
52
|
public:
|
|
49
53
|
RangeDownloadParams() = default;
|
|
50
|
-
explicit RangeDownloadParams(DownloadChannel channel, std::string taskId, std::string url, std::string destFilePath, std::optional<std::string> expectedSha256, std::optional<double> segmentCount, std::optional<double> minConcurrentBytes): channel(channel), taskId(taskId), url(url), destFilePath(destFilePath), expectedSha256(expectedSha256), segmentCount(segmentCount), minConcurrentBytes(minConcurrentBytes) {}
|
|
54
|
+
explicit RangeDownloadParams(DownloadChannel channel, std::string taskId, std::string url, std::string destFilePath, std::optional<std::string> expectedSha256, std::optional<double> segmentCount, std::optional<double> minConcurrentBytes, std::optional<double> maxSegmentAttempts, std::optional<double> requestTimeoutSeconds, std::optional<double> stallTimeoutSeconds, std::optional<double> overallDeadlineSeconds): channel(channel), taskId(taskId), url(url), destFilePath(destFilePath), expectedSha256(expectedSha256), segmentCount(segmentCount), minConcurrentBytes(minConcurrentBytes), maxSegmentAttempts(maxSegmentAttempts), requestTimeoutSeconds(requestTimeoutSeconds), stallTimeoutSeconds(stallTimeoutSeconds), overallDeadlineSeconds(overallDeadlineSeconds) {}
|
|
51
55
|
};
|
|
52
56
|
|
|
53
57
|
} // namespace margelo::nitro::reactnativerangedownloader
|
|
@@ -66,7 +70,11 @@ namespace margelo::nitro {
|
|
|
66
70
|
JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, "destFilePath")),
|
|
67
71
|
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "expectedSha256")),
|
|
68
72
|
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, "segmentCount")),
|
|
69
|
-
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, "minConcurrentBytes"))
|
|
73
|
+
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, "minConcurrentBytes")),
|
|
74
|
+
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, "maxSegmentAttempts")),
|
|
75
|
+
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, "requestTimeoutSeconds")),
|
|
76
|
+
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, "stallTimeoutSeconds")),
|
|
77
|
+
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, "overallDeadlineSeconds"))
|
|
70
78
|
);
|
|
71
79
|
}
|
|
72
80
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::reactnativerangedownloader::RangeDownloadParams& arg) {
|
|
@@ -78,6 +86,10 @@ namespace margelo::nitro {
|
|
|
78
86
|
obj.setProperty(runtime, "expectedSha256", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.expectedSha256));
|
|
79
87
|
obj.setProperty(runtime, "segmentCount", JSIConverter<std::optional<double>>::toJSI(runtime, arg.segmentCount));
|
|
80
88
|
obj.setProperty(runtime, "minConcurrentBytes", JSIConverter<std::optional<double>>::toJSI(runtime, arg.minConcurrentBytes));
|
|
89
|
+
obj.setProperty(runtime, "maxSegmentAttempts", JSIConverter<std::optional<double>>::toJSI(runtime, arg.maxSegmentAttempts));
|
|
90
|
+
obj.setProperty(runtime, "requestTimeoutSeconds", JSIConverter<std::optional<double>>::toJSI(runtime, arg.requestTimeoutSeconds));
|
|
91
|
+
obj.setProperty(runtime, "stallTimeoutSeconds", JSIConverter<std::optional<double>>::toJSI(runtime, arg.stallTimeoutSeconds));
|
|
92
|
+
obj.setProperty(runtime, "overallDeadlineSeconds", JSIConverter<std::optional<double>>::toJSI(runtime, arg.overallDeadlineSeconds));
|
|
81
93
|
return obj;
|
|
82
94
|
}
|
|
83
95
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
@@ -95,6 +107,10 @@ namespace margelo::nitro {
|
|
|
95
107
|
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "expectedSha256"))) return false;
|
|
96
108
|
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, "segmentCount"))) return false;
|
|
97
109
|
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, "minConcurrentBytes"))) return false;
|
|
110
|
+
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, "maxSegmentAttempts"))) return false;
|
|
111
|
+
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, "requestTimeoutSeconds"))) return false;
|
|
112
|
+
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, "stallTimeoutSeconds"))) return false;
|
|
113
|
+
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, "overallDeadlineSeconds"))) return false;
|
|
98
114
|
return true;
|
|
99
115
|
}
|
|
100
116
|
};
|
|
@@ -25,10 +25,13 @@
|
|
|
25
25
|
|
|
26
26
|
// Forward declaration of `RangeDownloadOutcome` to properly resolve imports.
|
|
27
27
|
namespace margelo::nitro::reactnativerangedownloader { enum class RangeDownloadOutcome; }
|
|
28
|
+
// Forward declaration of `RangeFallbackKind` to properly resolve imports.
|
|
29
|
+
namespace margelo::nitro::reactnativerangedownloader { enum class RangeFallbackKind; }
|
|
28
30
|
|
|
29
31
|
#include "RangeDownloadOutcome.hpp"
|
|
30
32
|
#include <string>
|
|
31
33
|
#include <optional>
|
|
34
|
+
#include "RangeFallbackKind.hpp"
|
|
32
35
|
|
|
33
36
|
namespace margelo::nitro::reactnativerangedownloader {
|
|
34
37
|
|
|
@@ -40,10 +43,11 @@ namespace margelo::nitro::reactnativerangedownloader {
|
|
|
40
43
|
RangeDownloadOutcome outcome SWIFT_PRIVATE;
|
|
41
44
|
std::string filePath SWIFT_PRIVATE;
|
|
42
45
|
std::optional<std::string> fallbackReason SWIFT_PRIVATE;
|
|
46
|
+
std::optional<RangeFallbackKind> fallbackKind SWIFT_PRIVATE;
|
|
43
47
|
|
|
44
48
|
public:
|
|
45
49
|
RangeDownloadResult() = default;
|
|
46
|
-
explicit RangeDownloadResult(RangeDownloadOutcome outcome, std::string filePath, std::optional<std::string> fallbackReason): outcome(outcome), filePath(filePath), fallbackReason(fallbackReason) {}
|
|
50
|
+
explicit RangeDownloadResult(RangeDownloadOutcome outcome, std::string filePath, std::optional<std::string> fallbackReason, std::optional<RangeFallbackKind> fallbackKind): outcome(outcome), filePath(filePath), fallbackReason(fallbackReason), fallbackKind(fallbackKind) {}
|
|
47
51
|
};
|
|
48
52
|
|
|
49
53
|
} // namespace margelo::nitro::reactnativerangedownloader
|
|
@@ -58,7 +62,8 @@ namespace margelo::nitro {
|
|
|
58
62
|
return margelo::nitro::reactnativerangedownloader::RangeDownloadResult(
|
|
59
63
|
JSIConverter<margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome>::fromJSI(runtime, obj.getProperty(runtime, "outcome")),
|
|
60
64
|
JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, "filePath")),
|
|
61
|
-
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "fallbackReason"))
|
|
65
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "fallbackReason")),
|
|
66
|
+
JSIConverter<std::optional<margelo::nitro::reactnativerangedownloader::RangeFallbackKind>>::fromJSI(runtime, obj.getProperty(runtime, "fallbackKind"))
|
|
62
67
|
);
|
|
63
68
|
}
|
|
64
69
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::reactnativerangedownloader::RangeDownloadResult& arg) {
|
|
@@ -66,6 +71,7 @@ namespace margelo::nitro {
|
|
|
66
71
|
obj.setProperty(runtime, "outcome", JSIConverter<margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome>::toJSI(runtime, arg.outcome));
|
|
67
72
|
obj.setProperty(runtime, "filePath", JSIConverter<std::string>::toJSI(runtime, arg.filePath));
|
|
68
73
|
obj.setProperty(runtime, "fallbackReason", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.fallbackReason));
|
|
74
|
+
obj.setProperty(runtime, "fallbackKind", JSIConverter<std::optional<margelo::nitro::reactnativerangedownloader::RangeFallbackKind>>::toJSI(runtime, arg.fallbackKind));
|
|
69
75
|
return obj;
|
|
70
76
|
}
|
|
71
77
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
@@ -79,6 +85,7 @@ namespace margelo::nitro {
|
|
|
79
85
|
if (!JSIConverter<margelo::nitro::reactnativerangedownloader::RangeDownloadOutcome>::canConvert(runtime, obj.getProperty(runtime, "outcome"))) return false;
|
|
80
86
|
if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, "filePath"))) return false;
|
|
81
87
|
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "fallbackReason"))) return false;
|
|
88
|
+
if (!JSIConverter<std::optional<margelo::nitro::reactnativerangedownloader::RangeFallbackKind>>::canConvert(runtime, obj.getProperty(runtime, "fallbackKind"))) return false;
|
|
82
89
|
return true;
|
|
83
90
|
}
|
|
84
91
|
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// RangeFallbackKind.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#if __has_include(<NitroModules/NitroHash.hpp>)
|
|
11
|
+
#include <NitroModules/NitroHash.hpp>
|
|
12
|
+
#else
|
|
13
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
14
|
+
#endif
|
|
15
|
+
#if __has_include(<NitroModules/JSIConverter.hpp>)
|
|
16
|
+
#include <NitroModules/JSIConverter.hpp>
|
|
17
|
+
#else
|
|
18
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
19
|
+
#endif
|
|
20
|
+
#if __has_include(<NitroModules/NitroDefines.hpp>)
|
|
21
|
+
#include <NitroModules/NitroDefines.hpp>
|
|
22
|
+
#else
|
|
23
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
namespace margelo::nitro::reactnativerangedownloader {
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* An enum which can be represented as a JavaScript union (RangeFallbackKind).
|
|
30
|
+
*/
|
|
31
|
+
enum class RangeFallbackKind {
|
|
32
|
+
SERVERIGNOREDRANGE SWIFT_NAME(serverignoredrange) = 0,
|
|
33
|
+
RANGEUNSUPPORTED SWIFT_NAME(rangeunsupported) = 1,
|
|
34
|
+
AUTHEXPIRED SWIFT_NAME(authexpired) = 2,
|
|
35
|
+
NOTFOUND SWIFT_NAME(notfound) = 3,
|
|
36
|
+
REDIRECTREJECTED SWIFT_NAME(redirectrejected) = 4,
|
|
37
|
+
CHECKSUMMISMATCH SWIFT_NAME(checksummismatch) = 5,
|
|
38
|
+
MULTIPARTORBADTOTAL SWIFT_NAME(multipartorbadtotal) = 6,
|
|
39
|
+
TRANSIENTNETWORK SWIFT_NAME(transientnetwork) = 7,
|
|
40
|
+
THROTTLED SWIFT_NAME(throttled) = 8,
|
|
41
|
+
BUDGETEXHAUSTED SWIFT_NAME(budgetexhausted) = 9,
|
|
42
|
+
} CLOSED_ENUM;
|
|
43
|
+
|
|
44
|
+
} // namespace margelo::nitro::reactnativerangedownloader
|
|
45
|
+
|
|
46
|
+
namespace margelo::nitro {
|
|
47
|
+
|
|
48
|
+
// C++ RangeFallbackKind <> JS RangeFallbackKind (union)
|
|
49
|
+
template <>
|
|
50
|
+
struct JSIConverter<margelo::nitro::reactnativerangedownloader::RangeFallbackKind> final {
|
|
51
|
+
static inline margelo::nitro::reactnativerangedownloader::RangeFallbackKind fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
52
|
+
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
|
|
53
|
+
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
|
54
|
+
case hashString("serverIgnoredRange"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::SERVERIGNOREDRANGE;
|
|
55
|
+
case hashString("rangeUnsupported"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::RANGEUNSUPPORTED;
|
|
56
|
+
case hashString("authExpired"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::AUTHEXPIRED;
|
|
57
|
+
case hashString("notFound"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::NOTFOUND;
|
|
58
|
+
case hashString("redirectRejected"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::REDIRECTREJECTED;
|
|
59
|
+
case hashString("checksumMismatch"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::CHECKSUMMISMATCH;
|
|
60
|
+
case hashString("multipartOrBadTotal"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::MULTIPARTORBADTOTAL;
|
|
61
|
+
case hashString("transientNetwork"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::TRANSIENTNETWORK;
|
|
62
|
+
case hashString("throttled"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::THROTTLED;
|
|
63
|
+
case hashString("budgetExhausted"): return margelo::nitro::reactnativerangedownloader::RangeFallbackKind::BUDGETEXHAUSTED;
|
|
64
|
+
default: [[unlikely]]
|
|
65
|
+
throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum RangeFallbackKind - invalid value!");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::reactnativerangedownloader::RangeFallbackKind arg) {
|
|
69
|
+
switch (arg) {
|
|
70
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::SERVERIGNOREDRANGE: return JSIConverter<std::string>::toJSI(runtime, "serverIgnoredRange");
|
|
71
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::RANGEUNSUPPORTED: return JSIConverter<std::string>::toJSI(runtime, "rangeUnsupported");
|
|
72
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::AUTHEXPIRED: return JSIConverter<std::string>::toJSI(runtime, "authExpired");
|
|
73
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::NOTFOUND: return JSIConverter<std::string>::toJSI(runtime, "notFound");
|
|
74
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::REDIRECTREJECTED: return JSIConverter<std::string>::toJSI(runtime, "redirectRejected");
|
|
75
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::CHECKSUMMISMATCH: return JSIConverter<std::string>::toJSI(runtime, "checksumMismatch");
|
|
76
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::MULTIPARTORBADTOTAL: return JSIConverter<std::string>::toJSI(runtime, "multipartOrBadTotal");
|
|
77
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::TRANSIENTNETWORK: return JSIConverter<std::string>::toJSI(runtime, "transientNetwork");
|
|
78
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::THROTTLED: return JSIConverter<std::string>::toJSI(runtime, "throttled");
|
|
79
|
+
case margelo::nitro::reactnativerangedownloader::RangeFallbackKind::BUDGETEXHAUSTED: return JSIConverter<std::string>::toJSI(runtime, "budgetExhausted");
|
|
80
|
+
default: [[unlikely]]
|
|
81
|
+
throw std::invalid_argument("Cannot convert RangeFallbackKind to JS - invalid value: "
|
|
82
|
+
+ std::to_string(static_cast<int>(arg)) + "!");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
86
|
+
if (!value.isString()) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
|
|
90
|
+
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
|
91
|
+
case hashString("serverIgnoredRange"):
|
|
92
|
+
case hashString("rangeUnsupported"):
|
|
93
|
+
case hashString("authExpired"):
|
|
94
|
+
case hashString("notFound"):
|
|
95
|
+
case hashString("redirectRejected"):
|
|
96
|
+
case hashString("checksumMismatch"):
|
|
97
|
+
case hashString("multipartOrBadTotal"):
|
|
98
|
+
case hashString("transientNetwork"):
|
|
99
|
+
case hashString("throttled"):
|
|
100
|
+
case hashString("budgetExhausted"):
|
|
101
|
+
return true;
|
|
102
|
+
default:
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
} // namespace margelo::nitro
|
package/package.json
CHANGED
|
@@ -14,16 +14,50 @@ export interface RangeDownloadParams {
|
|
|
14
14
|
expectedSha256?: string; // optional: in-module post-download self-check; else caller verifies later
|
|
15
15
|
segmentCount?: number; // default 8 (mirrors current behavior)
|
|
16
16
|
minConcurrentBytes?: number; // default 2MB (below this falls straight back to single stream)
|
|
17
|
+
// OCDS §5.4: caller-tunable retry/backoff/deadline knobs. Defaults are platform
|
|
18
|
+
// configuration (filled in by the native module when omitted), not part of the
|
|
19
|
+
// standard. These let the OTA / APK / asset callers tune behavior per channel.
|
|
20
|
+
maxSegmentAttempts?: number; // per-segment transient retry budget within a single run (default 4)
|
|
21
|
+
requestTimeoutSeconds?: number; // connection/request timeout per segment task (default 60)
|
|
22
|
+
stallTimeoutSeconds?: number; // bytes-stalled (no-progress) watchdog window (default 30)
|
|
23
|
+
overallDeadlineSeconds?: number; // single-run wall-clock bound before giving up (default 0 = none)
|
|
17
24
|
}
|
|
18
25
|
|
|
26
|
+
// OCDS §4: the failure class is an EXPLICIT, typed outcome of the operation, never
|
|
27
|
+
// inferred from incidental on-disk side effects (e.g. whether `.segN` survives).
|
|
28
|
+
// - `completed` — destFilePath fully on disk (and expectedSha256, if passed, has passed)
|
|
29
|
+
// - `fallbackTransient` — concurrent path interrupted but RESUMABLE; segments kept; caller
|
|
30
|
+
// should retry the concurrent path / keep its progress floor
|
|
31
|
+
// - `fallbackPermanent` — concurrency fundamentally unusable for this object; segments are
|
|
32
|
+
// unsalvageable and have been discarded; caller restarts single-stream
|
|
33
|
+
// - `fallback` — DEPRECATED legacy alias kept for wire/back-compat during the
|
|
34
|
+
// transition; new callers consume the two typed classes above
|
|
19
35
|
export type RangeDownloadOutcome =
|
|
20
|
-
| 'completed'
|
|
21
|
-
| '
|
|
36
|
+
| 'completed'
|
|
37
|
+
| 'fallbackTransient'
|
|
38
|
+
| 'fallbackPermanent'
|
|
39
|
+
| 'fallback';
|
|
40
|
+
|
|
41
|
+
// OCDS §4: optional sub-classification of a fallback, so the caller (and analytics)
|
|
42
|
+
// can distinguish WHY the concurrent path was abandoned without parsing the reason
|
|
43
|
+
// string. Present only when outcome is a fallback class.
|
|
44
|
+
export type RangeFallbackKind =
|
|
45
|
+
| 'serverIgnoredRange' // server answered 200 to a Range request (Permanent)
|
|
46
|
+
| 'rangeUnsupported' // probe inconclusive / range not supported (Permanent)
|
|
47
|
+
| 'authExpired' // 401/403: signed URL dead; caller must fetch a fresh URL (Permanent)
|
|
48
|
+
| 'notFound' // 404/410: object gone (Permanent)
|
|
49
|
+
| 'redirectRejected' // non-HTTPS redirect rejected per §5.9 (Permanent)
|
|
50
|
+
| 'checksumMismatch' // whole-file checksum mismatch after assembly (Permanent)
|
|
51
|
+
| 'multipartOrBadTotal' // multipart/byteranges or Content-Range total disagrees (Permanent)
|
|
52
|
+
| 'transientNetwork' // connection lost / timeout / DNS / TLS / stall (Transient)
|
|
53
|
+
| 'throttled' // 429 / 5xx (except 501/505) (Transient)
|
|
54
|
+
| 'budgetExhausted'; // per-segment attempts / deadline exhausted while still resumable (Transient)
|
|
22
55
|
|
|
23
56
|
export interface RangeDownloadResult {
|
|
24
57
|
outcome: RangeDownloadOutcome;
|
|
25
58
|
filePath: string;
|
|
26
59
|
fallbackReason?: string; // filled when outcome=fallback (range unsupported / 200 / too small ...)
|
|
60
|
+
fallbackKind?: RangeFallbackKind; // typed sub-class of the fallback (see §4); omitted on completed
|
|
27
61
|
}
|
|
28
62
|
|
|
29
63
|
export interface RangeDownloadEvent {
|