@onekeyfe/react-native-range-downloader 3.0.81-alpha.0 → 3.0.81-alpha.10
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/ReactNativeRangeDownloader.podspec +1 -1
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveRules.kt +12 -5
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactOrphanSweep.kt +111 -0
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactStore.kt +185 -189
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/ReactNativeRangeDownloader.kt +16 -20
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveRulesTest.kt +39 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactDeadlineTest.kt +26 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactOrphanSweepTest.kt +107 -0
- package/ios/FirmwareArtifactStore.swift +662 -408
- package/ios/RangeDownloadLogic.swift +297 -0
- package/ios/ReactNativeRangeDownloader.swift +42 -471
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts +3 -7
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializeParams.hpp +7 -6
- package/nitrogen/generated/android/c++/JFirmwareArtifactDownloadParams.hpp +7 -7
- package/nitrogen/generated/android/c++/JHybridReactNativeRangeDownloaderSpec.cpp +0 -19
- package/nitrogen/generated/android/c++/JHybridReactNativeRangeDownloaderSpec.hpp +0 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializeParams.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactDownloadParams.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/HybridReactNativeRangeDownloaderSpec.kt +0 -4
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Bridge.hpp +15 -0
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Umbrella.hpp +0 -3
- package/nitrogen/generated/ios/c++/HybridReactNativeRangeDownloaderSpecSwift.hpp +0 -11
- package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializeParams.swift +32 -13
- package/nitrogen/generated/ios/swift/FirmwareArtifactDownloadParams.swift +39 -8
- package/nitrogen/generated/ios/swift/HybridReactNativeRangeDownloaderSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridReactNativeRangeDownloaderSpec_cxx.swift +0 -19
- package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializeParams.hpp +6 -5
- package/nitrogen/generated/shared/c++/FirmwareArtifactDownloadParams.hpp +9 -9
- package/nitrogen/generated/shared/c++/HybridReactNativeRangeDownloaderSpec.cpp +0 -1
- package/nitrogen/generated/shared/c++/HybridReactNativeRangeDownloaderSpec.hpp +0 -4
- package/package.json +2 -2
- package/src/ReactNativeRangeDownloader.nitro.ts +4 -11
- package/ios/FirmwareBackgroundSessionEventRouter.swift +0 -17
- package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseReconcileParams.hpp +0 -76
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseReconcileParams.kt +0 -38
- package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseReconcileParams.swift +0 -48
- package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseReconcileParams.hpp +0 -76
|
@@ -2,6 +2,16 @@ import Foundation
|
|
|
2
2
|
import NitroModules
|
|
3
3
|
import ReactNativeNativeLogger
|
|
4
4
|
|
|
5
|
+
private func settledFirmwareArtifactPromise<T>(
|
|
6
|
+
_ operation: () throws -> T
|
|
7
|
+
) -> Promise<T> {
|
|
8
|
+
do {
|
|
9
|
+
return Promise.resolved(withResult: try operation())
|
|
10
|
+
} catch {
|
|
11
|
+
return Promise.rejected(withError: error)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
5
15
|
// MARK: - Nitro HybridObject entry point
|
|
6
16
|
//
|
|
7
17
|
// Thin Nitro shim over `RangeDownloader.shared`. The heavy lifting — concurrent
|
|
@@ -98,7 +108,7 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
98
108
|
|
|
99
109
|
func getFirmwareArtifactCapabilities() throws -> FirmwareArtifactCapabilities {
|
|
100
110
|
FirmwareArtifactCapabilities(
|
|
101
|
-
firmwareArtifactProtocolVersion:
|
|
111
|
+
firmwareArtifactProtocolVersion: 3,
|
|
102
112
|
supportedRouteTypes: ["domain", "pinnedIp"],
|
|
103
113
|
supportsArchiveMaterialization: true,
|
|
104
114
|
maxReadBytes: Double(FirmwareArtifactStore.maxReadBytes)
|
|
@@ -108,7 +118,20 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
108
118
|
func downloadFirmwareArtifact(
|
|
109
119
|
params: FirmwareArtifactDownloadParams
|
|
110
120
|
) throws -> Promise<FirmwareArtifactReceipt> {
|
|
111
|
-
|
|
121
|
+
do {
|
|
122
|
+
if let artifact = try FirmwareArtifactStore.shared.cachedArtifact(params) {
|
|
123
|
+
return Promise.resolved(
|
|
124
|
+
withResult: FirmwareArtifactReceipt(
|
|
125
|
+
artifactRef: artifact.artifactRef,
|
|
126
|
+
size: Double(artifact.size),
|
|
127
|
+
sha256: artifact.sha256
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
return Promise.rejected(withError: error)
|
|
133
|
+
}
|
|
134
|
+
return Promise.async {
|
|
112
135
|
let artifact = try await FirmwareArtifactStore.shared.download(params)
|
|
113
136
|
return FirmwareArtifactReceipt(
|
|
114
137
|
artifactRef: artifact.artifactRef,
|
|
@@ -121,7 +144,14 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
121
144
|
func cancelFirmwareArtifactDownloads(
|
|
122
145
|
params: FirmwareArtifactCancelParams
|
|
123
146
|
) throws -> Promise<Void> {
|
|
124
|
-
|
|
147
|
+
guard FirmwareArtifactStore.isSafeIdentifier(params.transactionId) else {
|
|
148
|
+
return Promise.rejected(
|
|
149
|
+
withError: FirmwareArtifactStoreError.invalidInput(
|
|
150
|
+
"Invalid firmware transactionId"
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
return Promise.async {
|
|
125
155
|
try await FirmwareArtifactStore.shared.cancelDownloads(
|
|
126
156
|
transactionId: params.transactionId
|
|
127
157
|
)
|
|
@@ -131,7 +161,7 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
131
161
|
func discardFirmwareArtifact(
|
|
132
162
|
params: FirmwareArtifactRefParams
|
|
133
163
|
) throws -> Promise<Void> {
|
|
134
|
-
|
|
164
|
+
settledFirmwareArtifactPromise {
|
|
135
165
|
try FirmwareArtifactStore.shared.discard(artifactRef: params.artifactRef)
|
|
136
166
|
}
|
|
137
167
|
}
|
|
@@ -139,7 +169,7 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
139
169
|
func openFirmwareArtifact(
|
|
140
170
|
params: FirmwareArtifactRefParams
|
|
141
171
|
) throws -> Promise<FirmwareArtifactReaderInfo> {
|
|
142
|
-
|
|
172
|
+
settledFirmwareArtifactPromise {
|
|
143
173
|
let reader = try FirmwareArtifactStore.shared.open(
|
|
144
174
|
artifactRef: params.artifactRef
|
|
145
175
|
)
|
|
@@ -153,7 +183,7 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
153
183
|
func readFirmwareArtifact(
|
|
154
184
|
params: FirmwareArtifactReaderReadParams
|
|
155
185
|
) throws -> Promise<ArrayBuffer> {
|
|
156
|
-
|
|
186
|
+
settledFirmwareArtifactPromise {
|
|
157
187
|
guard
|
|
158
188
|
params.offset.isFinite,
|
|
159
189
|
params.offset >= 0,
|
|
@@ -180,7 +210,7 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
180
210
|
func closeFirmwareArtifact(
|
|
181
211
|
params: FirmwareArtifactReaderCloseParams
|
|
182
212
|
) throws -> Promise<Void> {
|
|
183
|
-
|
|
213
|
+
settledFirmwareArtifactPromise {
|
|
184
214
|
try FirmwareArtifactStore.shared.close(readerId: params.readerId)
|
|
185
215
|
}
|
|
186
216
|
}
|
|
@@ -188,7 +218,7 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
188
218
|
func materializeFirmwareArchive(
|
|
189
219
|
params: FirmwareArchiveMaterializeParams
|
|
190
220
|
) throws -> Promise<FirmwareArchiveMaterializeResult> {
|
|
191
|
-
|
|
221
|
+
settledFirmwareArtifactPromise {
|
|
192
222
|
let entries = try FirmwareArtifactStore.shared.materializeArchive(
|
|
193
223
|
leaseRef: params.leaseRef,
|
|
194
224
|
artifactRef: params.archiveArtifactRef,
|
|
@@ -212,7 +242,7 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
212
242
|
func createFirmwareArtifactLease(
|
|
213
243
|
params: FirmwareArtifactLeaseCreateParams
|
|
214
244
|
) throws -> Promise<FirmwareArtifactLease> {
|
|
215
|
-
|
|
245
|
+
settledFirmwareArtifactPromise {
|
|
216
246
|
FirmwareArtifactLease(
|
|
217
247
|
leaseRef: try FirmwareArtifactStore.shared.createLease(
|
|
218
248
|
transactionId: params.transactionId
|
|
@@ -224,7 +254,7 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
224
254
|
func retainFirmwareArtifact(
|
|
225
255
|
params: FirmwareArtifactLeaseRetainParams
|
|
226
256
|
) throws -> Promise<Void> {
|
|
227
|
-
|
|
257
|
+
settledFirmwareArtifactPromise {
|
|
228
258
|
try FirmwareArtifactStore.shared.retain(
|
|
229
259
|
leaseRef: params.leaseRef,
|
|
230
260
|
artifactRef: params.artifactRef
|
|
@@ -235,7 +265,7 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
235
265
|
func releaseFirmwareArtifactLease(
|
|
236
266
|
params: FirmwareArtifactLeaseReleaseParams
|
|
237
267
|
) throws -> Promise<Void> {
|
|
238
|
-
|
|
268
|
+
settledFirmwareArtifactPromise {
|
|
239
269
|
try FirmwareArtifactStore.shared.releaseLease(
|
|
240
270
|
leaseRef: params.leaseRef,
|
|
241
271
|
disposition: params.disposition
|
|
@@ -243,18 +273,8 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
243
273
|
}
|
|
244
274
|
}
|
|
245
275
|
|
|
246
|
-
func reconcileFirmwareArtifactLeases(
|
|
247
|
-
params: FirmwareArtifactLeaseReconcileParams
|
|
248
|
-
) throws -> Promise<Void> {
|
|
249
|
-
Promise.async {
|
|
250
|
-
try FirmwareArtifactStore.shared.reconcileLeases(
|
|
251
|
-
activeLeaseRefs: params.activeLeaseRefs
|
|
252
|
-
)
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
276
|
func sweepFirmwareArtifactOrphans() throws -> Promise<FirmwareArtifactSweepResult> {
|
|
257
|
-
|
|
277
|
+
settledFirmwareArtifactPromise {
|
|
258
278
|
let result = try FirmwareArtifactStore.shared.sweepOrphans()
|
|
259
279
|
return FirmwareArtifactSweepResult(
|
|
260
280
|
deletedFiles: Double(result.deletedFiles),
|
|
@@ -323,79 +343,10 @@ extension RangeFallbackClass {
|
|
|
323
343
|
}
|
|
324
344
|
}
|
|
325
345
|
|
|
326
|
-
private struct FirmwareBackgroundTaskDescriptor: Codable, Equatable {
|
|
327
|
-
let schemaVersion: Int
|
|
328
|
-
let taskId: String
|
|
329
|
-
let transactionId: String
|
|
330
|
-
let leaseRef: String
|
|
331
|
-
let expectedSize: Int64
|
|
332
|
-
let expectedSha256: String
|
|
333
|
-
let hostname: String
|
|
334
|
-
let deadlineAt: TimeInterval
|
|
335
|
-
|
|
336
|
-
var key: String {
|
|
337
|
-
"\(leaseRef)|\(taskId)|\(expectedSha256)"
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
func hasSameArtifactIdentity(
|
|
341
|
-
as other: FirmwareBackgroundTaskDescriptor
|
|
342
|
-
) -> Bool {
|
|
343
|
-
taskId == other.taskId &&
|
|
344
|
-
transactionId == other.transactionId &&
|
|
345
|
-
leaseRef == other.leaseRef &&
|
|
346
|
-
expectedSize == other.expectedSize &&
|
|
347
|
-
expectedSha256 == other.expectedSha256 &&
|
|
348
|
-
hostname == other.hostname
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
private enum FirmwareBackgroundDownloadError: LocalizedError {
|
|
353
|
-
case cancelled
|
|
354
|
-
case invalidTask
|
|
355
|
-
case deadlineExceeded
|
|
356
|
-
case redirectRejected
|
|
357
|
-
case responseRejected
|
|
358
|
-
case sizeRejected
|
|
359
|
-
case transferFailed
|
|
360
|
-
|
|
361
|
-
var errorDescription: String? {
|
|
362
|
-
switch self {
|
|
363
|
-
case .cancelled:
|
|
364
|
-
return "ARTIFACT_CANCELLED: firmware background download was cancelled"
|
|
365
|
-
case .invalidTask:
|
|
366
|
-
return "ARTIFACT_PROTOCOL_INVALID: firmware background task is invalid"
|
|
367
|
-
case .deadlineExceeded:
|
|
368
|
-
return "ARTIFACT_DEADLINE_EXCEEDED: firmware download exceeded its deadline"
|
|
369
|
-
case .redirectRejected:
|
|
370
|
-
return "ARTIFACT_REDIRECT_REJECTED: firmware redirect changed canonical identity"
|
|
371
|
-
case .responseRejected:
|
|
372
|
-
return "ARTIFACT_PROTOCOL_INVALID: firmware response is invalid"
|
|
373
|
-
case .sizeRejected:
|
|
374
|
-
return "ARTIFACT_PROTOCOL_INVALID: firmware artifact size is invalid"
|
|
375
|
-
case .transferFailed:
|
|
376
|
-
return "ARTIFACT_NETWORK_FAILED: firmware background transfer failed"
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
346
|
public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
382
347
|
|
|
383
348
|
public static let shared = RangeDownloader()
|
|
384
349
|
|
|
385
|
-
public static func routeFirmwareBackgroundEvents(
|
|
386
|
-
identifier: String,
|
|
387
|
-
completionHandler: @escaping () -> Void
|
|
388
|
-
) -> Bool {
|
|
389
|
-
guard identifier == sessionIdentifier(for: .firmware) else {
|
|
390
|
-
return false
|
|
391
|
-
}
|
|
392
|
-
shared.attachBackgroundEvents(
|
|
393
|
-
identifier: identifier,
|
|
394
|
-
completionHandler: completionHandler
|
|
395
|
-
)
|
|
396
|
-
return true
|
|
397
|
-
}
|
|
398
|
-
|
|
399
350
|
/// Posted by the AppDelegate from
|
|
400
351
|
/// application(_:handleEventsForBackgroundURLSession:completionHandler:).
|
|
401
352
|
/// userInfo: ["identifier": String, "completionHandler": () -> Void].
|
|
@@ -432,11 +383,6 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
432
383
|
/// notification), keyed by session identifier, so we can call each back once
|
|
433
384
|
/// all its queued background events have been delivered.
|
|
434
385
|
private var backgroundCompletionHandlers: [String: () -> Void] = [:]
|
|
435
|
-
private var firmwareWaiters: [
|
|
436
|
-
String: [CheckedContinuation<StoredFirmwareArtifact, Error>]
|
|
437
|
-
] = [:]
|
|
438
|
-
private var firmwareTaskErrors: [Int: Error] = [:]
|
|
439
|
-
private var completedFirmwareTasks: Set<Int> = []
|
|
440
386
|
|
|
441
387
|
// Per-run mutable state.
|
|
442
388
|
private final class RunState {
|
|
@@ -694,240 +640,6 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
694
640
|
return (r, decoded.segIndex)
|
|
695
641
|
}
|
|
696
642
|
|
|
697
|
-
private static let firmwareTaskDescriptionPrefix = "firmware-v1:"
|
|
698
|
-
|
|
699
|
-
private static func encodeFirmwareTaskDescription(
|
|
700
|
-
_ descriptor: FirmwareBackgroundTaskDescriptor
|
|
701
|
-
) throws -> String {
|
|
702
|
-
let data = try JSONEncoder().encode(descriptor)
|
|
703
|
-
return firmwareTaskDescriptionPrefix + data.base64EncodedString()
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
private static func decodeFirmwareTaskDescription(
|
|
707
|
-
_ description: String?
|
|
708
|
-
) -> FirmwareBackgroundTaskDescriptor? {
|
|
709
|
-
guard
|
|
710
|
-
let description,
|
|
711
|
-
description.hasPrefix(firmwareTaskDescriptionPrefix),
|
|
712
|
-
let data = Data(
|
|
713
|
-
base64Encoded: String(
|
|
714
|
-
description.dropFirst(firmwareTaskDescriptionPrefix.count)
|
|
715
|
-
)
|
|
716
|
-
),
|
|
717
|
-
data.count <= 2048,
|
|
718
|
-
let descriptor = try? JSONDecoder().decode(
|
|
719
|
-
FirmwareBackgroundTaskDescriptor.self,
|
|
720
|
-
from: data
|
|
721
|
-
),
|
|
722
|
-
descriptor.schemaVersion == 1,
|
|
723
|
-
descriptor.taskId.range(
|
|
724
|
-
of: "^[A-Za-z0-9._-]{1,100}$",
|
|
725
|
-
options: .regularExpression
|
|
726
|
-
) != nil,
|
|
727
|
-
descriptor.transactionId.range(
|
|
728
|
-
of: "^[A-Za-z0-9._:-]{1,160}$",
|
|
729
|
-
options: .regularExpression
|
|
730
|
-
) != nil,
|
|
731
|
-
descriptor.leaseRef.range(
|
|
732
|
-
of: "^fwlease:[a-f0-9-]{36}$",
|
|
733
|
-
options: .regularExpression
|
|
734
|
-
) != nil,
|
|
735
|
-
descriptor.expectedSize > 0,
|
|
736
|
-
descriptor.expectedSize <= 512 * 1024 * 1024,
|
|
737
|
-
descriptor.expectedSha256.range(
|
|
738
|
-
of: "^[a-f0-9]{64}$",
|
|
739
|
-
options: .regularExpression
|
|
740
|
-
) != nil,
|
|
741
|
-
!descriptor.hostname.isEmpty,
|
|
742
|
-
descriptor.hostname.count <= 253,
|
|
743
|
-
descriptor.deadlineAt.isFinite,
|
|
744
|
-
descriptor.deadlineAt > 0
|
|
745
|
-
else {
|
|
746
|
-
return nil
|
|
747
|
-
}
|
|
748
|
-
return descriptor
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
func downloadFirmwareArtifact(
|
|
752
|
-
params: FirmwareArtifactDownloadParams
|
|
753
|
-
) async throws -> StoredFirmwareArtifact {
|
|
754
|
-
guard
|
|
755
|
-
params.routeType == "domain",
|
|
756
|
-
let url = URL(string: params.url),
|
|
757
|
-
let hostname = url.host?.lowercased()
|
|
758
|
-
else {
|
|
759
|
-
throw FirmwareBackgroundDownloadError.invalidTask
|
|
760
|
-
}
|
|
761
|
-
let deadlineSeconds = params.overallDeadlineSeconds ?? 180
|
|
762
|
-
guard
|
|
763
|
-
deadlineSeconds.isFinite,
|
|
764
|
-
deadlineSeconds > 0,
|
|
765
|
-
deadlineSeconds <= 24 * 60 * 60
|
|
766
|
-
else {
|
|
767
|
-
throw FirmwareBackgroundDownloadError.invalidTask
|
|
768
|
-
}
|
|
769
|
-
let descriptor = FirmwareBackgroundTaskDescriptor(
|
|
770
|
-
schemaVersion: 1,
|
|
771
|
-
taskId: params.taskId,
|
|
772
|
-
transactionId: params.transactionId,
|
|
773
|
-
leaseRef: params.leaseRef,
|
|
774
|
-
expectedSize: Int64(params.expectedSize),
|
|
775
|
-
expectedSha256: params.expectedSha256.lowercased(),
|
|
776
|
-
hostname: hostname,
|
|
777
|
-
deadlineAt: Date().timeIntervalSince1970 + deadlineSeconds
|
|
778
|
-
)
|
|
779
|
-
guard !FirmwareArtifactStore.shared.isTransactionCancelled(
|
|
780
|
-
descriptor.transactionId
|
|
781
|
-
) else {
|
|
782
|
-
throw FirmwareBackgroundDownloadError.cancelled
|
|
783
|
-
}
|
|
784
|
-
if let stored = try FirmwareArtifactStore.shared.storedArtifact(
|
|
785
|
-
expectedSize: descriptor.expectedSize,
|
|
786
|
-
expectedSha256: descriptor.expectedSha256
|
|
787
|
-
) {
|
|
788
|
-
return stored
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
return try await withCheckedThrowingContinuation { continuation in
|
|
792
|
-
lock.withLockValue {
|
|
793
|
-
firmwareWaiters[descriptor.key, default: []].append(continuation)
|
|
794
|
-
}
|
|
795
|
-
Task { [weak self] in
|
|
796
|
-
await self?.reconcileOrStartFirmwareTask(
|
|
797
|
-
descriptor: descriptor,
|
|
798
|
-
url: url
|
|
799
|
-
)
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
func cancelFirmwareArtifactDownloads(
|
|
805
|
-
transactionId: String
|
|
806
|
-
) async throws {
|
|
807
|
-
guard transactionId.range(
|
|
808
|
-
of: "^[A-Za-z0-9._:-]{1,160}$",
|
|
809
|
-
options: .regularExpression
|
|
810
|
-
) != nil else {
|
|
811
|
-
throw FirmwareBackgroundDownloadError.invalidTask
|
|
812
|
-
}
|
|
813
|
-
let session = session(forChannel: .firmware, segmentCount: 1)
|
|
814
|
-
let tasks = await allTasks(in: session)
|
|
815
|
-
for task in tasks {
|
|
816
|
-
guard
|
|
817
|
-
let descriptor = Self.decodeFirmwareTaskDescription(
|
|
818
|
-
task.taskDescription
|
|
819
|
-
),
|
|
820
|
-
descriptor.transactionId == transactionId
|
|
821
|
-
else {
|
|
822
|
-
continue
|
|
823
|
-
}
|
|
824
|
-
recordFirmwareTaskError(
|
|
825
|
-
taskIdentifier: task.taskIdentifier,
|
|
826
|
-
error: FirmwareBackgroundDownloadError.cancelled
|
|
827
|
-
)
|
|
828
|
-
task.cancel()
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
private func reconcileOrStartFirmwareTask(
|
|
833
|
-
descriptor: FirmwareBackgroundTaskDescriptor,
|
|
834
|
-
url: URL
|
|
835
|
-
) async {
|
|
836
|
-
guard !FirmwareArtifactStore.shared.isTransactionCancelled(
|
|
837
|
-
descriptor.transactionId
|
|
838
|
-
) else {
|
|
839
|
-
finishFirmwareTask(
|
|
840
|
-
key: descriptor.key,
|
|
841
|
-
result: .failure(FirmwareBackgroundDownloadError.cancelled)
|
|
842
|
-
)
|
|
843
|
-
return
|
|
844
|
-
}
|
|
845
|
-
let session = session(forChannel: .firmware, segmentCount: 1)
|
|
846
|
-
let tasks = await allTasks(in: session)
|
|
847
|
-
var matchingTaskFound = false
|
|
848
|
-
for task in tasks {
|
|
849
|
-
guard
|
|
850
|
-
let candidate = Self.decodeFirmwareTaskDescription(
|
|
851
|
-
task.taskDescription
|
|
852
|
-
)
|
|
853
|
-
else {
|
|
854
|
-
continue
|
|
855
|
-
}
|
|
856
|
-
if candidate.hasSameArtifactIdentity(as: descriptor) {
|
|
857
|
-
matchingTaskFound = true
|
|
858
|
-
} else if candidate.taskId == descriptor.taskId {
|
|
859
|
-
task.cancel()
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
if matchingTaskFound {
|
|
863
|
-
return
|
|
864
|
-
}
|
|
865
|
-
do {
|
|
866
|
-
if let stored = try FirmwareArtifactStore.shared.storedArtifact(
|
|
867
|
-
expectedSize: descriptor.expectedSize,
|
|
868
|
-
expectedSha256: descriptor.expectedSha256
|
|
869
|
-
) {
|
|
870
|
-
finishFirmwareTask(
|
|
871
|
-
key: descriptor.key,
|
|
872
|
-
result: .success(stored)
|
|
873
|
-
)
|
|
874
|
-
return
|
|
875
|
-
}
|
|
876
|
-
guard Date().timeIntervalSince1970 < descriptor.deadlineAt else {
|
|
877
|
-
throw FirmwareBackgroundDownloadError.deadlineExceeded
|
|
878
|
-
}
|
|
879
|
-
guard !FirmwareArtifactStore.shared.isTransactionCancelled(
|
|
880
|
-
descriptor.transactionId
|
|
881
|
-
) else {
|
|
882
|
-
throw FirmwareBackgroundDownloadError.cancelled
|
|
883
|
-
}
|
|
884
|
-
var request = URLRequest(url: url)
|
|
885
|
-
request.cachePolicy = .reloadIgnoringLocalCacheData
|
|
886
|
-
request.timeoutInterval = max(
|
|
887
|
-
1,
|
|
888
|
-
descriptor.deadlineAt - Date().timeIntervalSince1970
|
|
889
|
-
)
|
|
890
|
-
request.setValue("identity", forHTTPHeaderField: "Accept-Encoding")
|
|
891
|
-
let task = session.downloadTask(with: request)
|
|
892
|
-
task.taskDescription = try Self.encodeFirmwareTaskDescription(
|
|
893
|
-
descriptor
|
|
894
|
-
)
|
|
895
|
-
task.resume()
|
|
896
|
-
} catch {
|
|
897
|
-
finishFirmwareTask(
|
|
898
|
-
key: descriptor.key,
|
|
899
|
-
result: .failure(error)
|
|
900
|
-
)
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
private func allTasks(in session: URLSession) async -> [URLSessionTask] {
|
|
905
|
-
await withCheckedContinuation { continuation in
|
|
906
|
-
session.getAllTasks { tasks in
|
|
907
|
-
continuation.resume(returning: tasks)
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
private func finishFirmwareTask(
|
|
913
|
-
key: String,
|
|
914
|
-
result: Result<StoredFirmwareArtifact, Error>
|
|
915
|
-
) {
|
|
916
|
-
let continuations: [
|
|
917
|
-
CheckedContinuation<StoredFirmwareArtifact, Error>
|
|
918
|
-
] = lock.withLockValue {
|
|
919
|
-
firmwareWaiters.removeValue(forKey: key) ?? []
|
|
920
|
-
}
|
|
921
|
-
for continuation in continuations {
|
|
922
|
-
switch result {
|
|
923
|
-
case let .success(artifact):
|
|
924
|
-
continuation.resume(returning: artifact)
|
|
925
|
-
case let .failure(error):
|
|
926
|
-
continuation.resume(throwing: error)
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
|
|
931
643
|
// MARK: - Public entry
|
|
932
644
|
|
|
933
645
|
/// Downloads [urlString] into [filePath] using concurrent background ranges.
|
|
@@ -1463,28 +1175,6 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
1463
1175
|
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
|
|
1464
1176
|
didWriteData bytesWritten: Int64, totalBytesWritten: Int64,
|
|
1465
1177
|
totalBytesExpectedToWrite: Int64) {
|
|
1466
|
-
if let descriptor = Self.decodeFirmwareTaskDescription(
|
|
1467
|
-
downloadTask.taskDescription
|
|
1468
|
-
) {
|
|
1469
|
-
let exceedsBound =
|
|
1470
|
-
totalBytesWritten > descriptor.expectedSize ||
|
|
1471
|
-
(
|
|
1472
|
-
totalBytesExpectedToWrite != NSURLSessionTransferSizeUnknown &&
|
|
1473
|
-
totalBytesExpectedToWrite != descriptor.expectedSize
|
|
1474
|
-
)
|
|
1475
|
-
let expired =
|
|
1476
|
-
Date().timeIntervalSince1970 >= descriptor.deadlineAt
|
|
1477
|
-
if exceedsBound || expired {
|
|
1478
|
-
recordFirmwareTaskError(
|
|
1479
|
-
taskIdentifier: downloadTask.taskIdentifier,
|
|
1480
|
-
error: exceedsBound
|
|
1481
|
-
? FirmwareBackgroundDownloadError.sizeRejected
|
|
1482
|
-
: FirmwareBackgroundDownloadError.deadlineExceeded
|
|
1483
|
-
)
|
|
1484
|
-
downloadTask.cancel()
|
|
1485
|
-
}
|
|
1486
|
-
return
|
|
1487
|
-
}
|
|
1488
1178
|
guard let desc = downloadTask.taskDescription,
|
|
1489
1179
|
let (state, idx) = run(for: desc) else { return }
|
|
1490
1180
|
lock.lock()
|
|
@@ -1515,53 +1205,6 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
1515
1205
|
|
|
1516
1206
|
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
|
|
1517
1207
|
didFinishDownloadingTo location: URL) {
|
|
1518
|
-
if let descriptor = Self.decodeFirmwareTaskDescription(
|
|
1519
|
-
downloadTask.taskDescription
|
|
1520
|
-
) {
|
|
1521
|
-
guard firmwareTaskError(
|
|
1522
|
-
taskIdentifier: downloadTask.taskIdentifier
|
|
1523
|
-
) == nil else {
|
|
1524
|
-
return
|
|
1525
|
-
}
|
|
1526
|
-
do {
|
|
1527
|
-
guard
|
|
1528
|
-
!FirmwareArtifactStore.shared.isTransactionCancelled(
|
|
1529
|
-
descriptor.transactionId
|
|
1530
|
-
),
|
|
1531
|
-
Date().timeIntervalSince1970 < descriptor.deadlineAt,
|
|
1532
|
-
let response = downloadTask.response as? HTTPURLResponse,
|
|
1533
|
-
response.statusCode == 200,
|
|
1534
|
-
response.url?.scheme?.lowercased() == "https",
|
|
1535
|
-
response.url?.host?.lowercased() == descriptor.hostname,
|
|
1536
|
-
response.url?.port == nil || response.url?.port == 443
|
|
1537
|
-
else {
|
|
1538
|
-
throw FirmwareBackgroundDownloadError.responseRejected
|
|
1539
|
-
}
|
|
1540
|
-
let artifact = try FirmwareArtifactStore.shared.acceptBackgroundDownload(
|
|
1541
|
-
temporaryURL: location,
|
|
1542
|
-
leaseRef: descriptor.leaseRef,
|
|
1543
|
-
transactionId: descriptor.transactionId,
|
|
1544
|
-
expectedSize: descriptor.expectedSize,
|
|
1545
|
-
expectedSha256: descriptor.expectedSha256
|
|
1546
|
-
)
|
|
1547
|
-
lock.withLockValue {
|
|
1548
|
-
firmwareTaskErrors.removeValue(
|
|
1549
|
-
forKey: downloadTask.taskIdentifier
|
|
1550
|
-
)
|
|
1551
|
-
completedFirmwareTasks.insert(downloadTask.taskIdentifier)
|
|
1552
|
-
}
|
|
1553
|
-
finishFirmwareTask(
|
|
1554
|
-
key: descriptor.key,
|
|
1555
|
-
result: .success(artifact)
|
|
1556
|
-
)
|
|
1557
|
-
} catch {
|
|
1558
|
-
recordFirmwareTaskError(
|
|
1559
|
-
taskIdentifier: downloadTask.taskIdentifier,
|
|
1560
|
-
error: error
|
|
1561
|
-
)
|
|
1562
|
-
}
|
|
1563
|
-
return
|
|
1564
|
-
}
|
|
1565
1208
|
guard let desc = downloadTask.taskDescription,
|
|
1566
1209
|
let (state, idx) = run(for: desc) else { return }
|
|
1567
1210
|
let ranges = lock.withLockValue { state.ranges }
|
|
@@ -1660,39 +1303,6 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
1660
1303
|
}
|
|
1661
1304
|
|
|
1662
1305
|
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
|
|
1663
|
-
if let descriptor = Self.decodeFirmwareTaskDescription(
|
|
1664
|
-
task.taskDescription
|
|
1665
|
-
) {
|
|
1666
|
-
let completion: (completed: Bool, error: Error?) =
|
|
1667
|
-
lock.withLockValue {
|
|
1668
|
-
let completed = completedFirmwareTasks.remove(
|
|
1669
|
-
task.taskIdentifier
|
|
1670
|
-
) != nil
|
|
1671
|
-
let recordedError = firmwareTaskErrors.removeValue(
|
|
1672
|
-
forKey: task.taskIdentifier
|
|
1673
|
-
)
|
|
1674
|
-
return (completed, recordedError)
|
|
1675
|
-
}
|
|
1676
|
-
if completion.completed {
|
|
1677
|
-
return
|
|
1678
|
-
}
|
|
1679
|
-
finishFirmwareTask(
|
|
1680
|
-
key: descriptor.key,
|
|
1681
|
-
result: .failure(
|
|
1682
|
-
completion.error ??
|
|
1683
|
-
(
|
|
1684
|
-
FirmwareArtifactStore.shared.isTransactionCancelled(
|
|
1685
|
-
descriptor.transactionId
|
|
1686
|
-
)
|
|
1687
|
-
? FirmwareBackgroundDownloadError.cancelled
|
|
1688
|
-
: nil
|
|
1689
|
-
) ??
|
|
1690
|
-
error ??
|
|
1691
|
-
FirmwareBackgroundDownloadError.transferFailed
|
|
1692
|
-
)
|
|
1693
|
-
)
|
|
1694
|
-
return
|
|
1695
|
-
}
|
|
1696
1306
|
guard let desc = task.taskDescription,
|
|
1697
1307
|
let (state, idx) = run(for: desc) else { return }
|
|
1698
1308
|
let ranges = lock.withLockValue { state.ranges }
|
|
@@ -1868,26 +1478,6 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
1868
1478
|
willPerformHTTPRedirection response: HTTPURLResponse,
|
|
1869
1479
|
newRequest request: URLRequest,
|
|
1870
1480
|
completionHandler: @escaping (URLRequest?) -> Void) {
|
|
1871
|
-
if let descriptor = Self.decodeFirmwareTaskDescription(
|
|
1872
|
-
task.taskDescription
|
|
1873
|
-
) {
|
|
1874
|
-
guard
|
|
1875
|
-
request.url?.scheme?.lowercased() == "https",
|
|
1876
|
-
request.url?.host?.lowercased() == descriptor.hostname,
|
|
1877
|
-
request.url?.port == nil || request.url?.port == 443,
|
|
1878
|
-
request.url?.user == nil,
|
|
1879
|
-
request.url?.password == nil
|
|
1880
|
-
else {
|
|
1881
|
-
recordFirmwareTaskError(
|
|
1882
|
-
taskIdentifier: task.taskIdentifier,
|
|
1883
|
-
error: FirmwareBackgroundDownloadError.redirectRejected
|
|
1884
|
-
)
|
|
1885
|
-
completionHandler(nil)
|
|
1886
|
-
return
|
|
1887
|
-
}
|
|
1888
|
-
completionHandler(request)
|
|
1889
|
-
return
|
|
1890
|
-
}
|
|
1891
1481
|
if request.url?.scheme?.lowercased() != "https" {
|
|
1892
1482
|
OneKeyLog.error("RangeDownloader", "blocked redirect to non-HTTPS URL")
|
|
1893
1483
|
if let desc = task.taskDescription, let (state, _) = run(for: desc) {
|
|
@@ -1899,25 +1489,6 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
1899
1489
|
}
|
|
1900
1490
|
}
|
|
1901
1491
|
|
|
1902
|
-
private func recordFirmwareTaskError(
|
|
1903
|
-
taskIdentifier: Int,
|
|
1904
|
-
error: Error
|
|
1905
|
-
) {
|
|
1906
|
-
lock.withLockValue {
|
|
1907
|
-
if firmwareTaskErrors[taskIdentifier] == nil {
|
|
1908
|
-
firmwareTaskErrors[taskIdentifier] = error
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1913
|
-
private func firmwareTaskError(
|
|
1914
|
-
taskIdentifier: Int
|
|
1915
|
-
) -> Error? {
|
|
1916
|
-
lock.withLockValue {
|
|
1917
|
-
firmwareTaskErrors[taskIdentifier]
|
|
1918
|
-
}
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
1492
|
/// Called on the session delegate queue when all background events for this
|
|
1922
1493
|
/// session have been delivered after a background relaunch.
|
|
1923
1494
|
public func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
|
|
@@ -36,8 +36,8 @@ export interface FirmwareArtifactDownloadParams {
|
|
|
36
36
|
url: string;
|
|
37
37
|
routeType: string;
|
|
38
38
|
resolvedIp?: string;
|
|
39
|
-
expectedSize
|
|
40
|
-
expectedSha256
|
|
39
|
+
expectedSize?: number;
|
|
40
|
+
expectedSha256?: string;
|
|
41
41
|
maxBytes: number;
|
|
42
42
|
overallDeadlineSeconds?: number;
|
|
43
43
|
}
|
|
@@ -73,7 +73,7 @@ export interface FirmwareArtifactReaderCloseParams {
|
|
|
73
73
|
export interface FirmwareArchiveMaterializeParams {
|
|
74
74
|
leaseRef: string;
|
|
75
75
|
archiveArtifactRef: string;
|
|
76
|
-
expectedEntries
|
|
76
|
+
expectedEntries?: FirmwareArchiveExpectedEntry[];
|
|
77
77
|
}
|
|
78
78
|
export interface FirmwareArchiveExpectedEntry {
|
|
79
79
|
artifactId: string;
|
|
@@ -102,9 +102,6 @@ export interface FirmwareArtifactLeaseReleaseParams {
|
|
|
102
102
|
leaseRef: string;
|
|
103
103
|
disposition: string;
|
|
104
104
|
}
|
|
105
|
-
export interface FirmwareArtifactLeaseReconcileParams {
|
|
106
|
-
activeLeaseRefs: string[];
|
|
107
|
-
}
|
|
108
105
|
export interface FirmwareArtifactSweepResult {
|
|
109
106
|
deletedFiles: number;
|
|
110
107
|
deletedBytes: number;
|
|
@@ -130,7 +127,6 @@ export interface ReactNativeRangeDownloader extends HybridObject<{
|
|
|
130
127
|
createFirmwareArtifactLease(params: FirmwareArtifactLeaseCreateParams): Promise<FirmwareArtifactLease>;
|
|
131
128
|
retainFirmwareArtifact(params: FirmwareArtifactLeaseRetainParams): Promise<void>;
|
|
132
129
|
releaseFirmwareArtifactLease(params: FirmwareArtifactLeaseReleaseParams): Promise<void>;
|
|
133
|
-
reconcileFirmwareArtifactLeases(params: FirmwareArtifactLeaseReconcileParams): Promise<void>;
|
|
134
130
|
sweepFirmwareArtifactOrphans(): Promise<FirmwareArtifactSweepResult>;
|
|
135
131
|
}
|
|
136
132
|
//# sourceMappingURL=ReactNativeRangeDownloader.nitro.d.ts.map
|