@onekeyfe/react-native-range-downloader 3.0.79 → 3.0.81-alpha.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/ReactNativeRangeDownloader.podspec +8 -0
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveRules.kt +284 -0
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactStore.kt +842 -0
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/ReactNativeRangeDownloader.kt +148 -0
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveRulesTest.kt +75 -0
- package/ios/FirmwareArchiveMinizipBridge.h +33 -0
- package/ios/FirmwareArchiveMinizipBridge.mm +213 -0
- package/ios/FirmwareArtifactStore.swift +1276 -0
- package/ios/FirmwareBackgroundSessionEventRouter.swift +17 -0
- package/ios/ReactNativeRangeDownloader.swift +638 -6
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts +95 -1
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JDownloadChannel.hpp +3 -0
- package/nitrogen/generated/android/c++/JFirmwareArchiveExpectedEntry.hpp +69 -0
- package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializeParams.hpp +86 -0
- package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializeResult.hpp +80 -0
- package/nitrogen/generated/android/c++/JFirmwareArchiveMaterializedArtifact.hpp +63 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactCancelParams.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactCapabilities.hpp +88 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactDownloadParams.hpp +98 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLease.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseCreateParams.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseReconcileParams.hpp +76 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseReleaseParams.hpp +61 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactLeaseRetainParams.hpp +61 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactReaderCloseParams.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactReaderInfo.hpp +61 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactReaderReadParams.hpp +65 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactReceipt.hpp +65 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactRefParams.hpp +57 -0
- package/nitrogen/generated/android/c++/JFirmwareArtifactSweepResult.hpp +61 -0
- package/nitrogen/generated/android/c++/JHybridReactNativeRangeDownloaderSpec.cpp +267 -0
- package/nitrogen/generated/android/c++/JHybridReactNativeRangeDownloaderSpec.hpp +13 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/DownloadChannel.kt +2 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveExpectedEntry.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializeParams.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializeResult.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArchiveMaterializedArtifact.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactCancelParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactCapabilities.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactDownloadParams.kt +68 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLease.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseCreateParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseReconcileParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseReleaseParams.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactLeaseRetainParams.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReaderCloseParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReaderInfo.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReaderReadParams.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactReceipt.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactRefParams.kt +38 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactSweepResult.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativerangedownloader/HybridReactNativeRangeDownloaderSpec.kt +53 -0
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Bridge.cpp +48 -0
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Bridge.hpp +329 -0
- package/nitrogen/generated/ios/ReactNativeRangeDownloader-Swift-Cxx-Umbrella.hpp +56 -0
- package/nitrogen/generated/ios/c++/HybridReactNativeRangeDownloaderSpecSwift.hpp +163 -0
- package/nitrogen/generated/ios/swift/DownloadChannel.swift +4 -0
- package/nitrogen/generated/ios/swift/FirmwareArchiveExpectedEntry.swift +69 -0
- package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializeParams.swift +70 -0
- package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializeResult.swift +48 -0
- package/nitrogen/generated/ios/swift/FirmwareArchiveMaterializedArtifact.swift +47 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactCancelParams.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactCapabilities.swift +81 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactDownloadParams.swift +177 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLease.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseCreateParams.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseReconcileParams.swift +48 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseReleaseParams.swift +47 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactLeaseRetainParams.swift +47 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactReaderCloseParams.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactReaderInfo.swift +47 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactReaderReadParams.swift +58 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactReceipt.swift +58 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactRefParams.swift +36 -0
- package/nitrogen/generated/ios/swift/FirmwareArtifactSweepResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArchiveMaterializeResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactLease.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactReaderInfo.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactReceipt.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_FirmwareArtifactSweepResult.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_ArrayBuffer_.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridReactNativeRangeDownloaderSpec.swift +13 -0
- package/nitrogen/generated/ios/swift/HybridReactNativeRangeDownloaderSpec_cxx.swift +240 -0
- package/nitrogen/generated/shared/c++/DownloadChannel.hpp +4 -0
- package/nitrogen/generated/shared/c++/FirmwareArchiveExpectedEntry.hpp +87 -0
- package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializeParams.hpp +86 -0
- package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializeResult.hpp +77 -0
- package/nitrogen/generated/shared/c++/FirmwareArchiveMaterializedArtifact.hpp +81 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactCancelParams.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactCapabilities.hpp +88 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactDownloadParams.hpp +116 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLease.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseCreateParams.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseReconcileParams.hpp +76 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseReleaseParams.hpp +79 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactLeaseRetainParams.hpp +79 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactReaderCloseParams.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactReaderInfo.hpp +79 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactReaderReadParams.hpp +83 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactReceipt.hpp +83 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactRefParams.hpp +75 -0
- package/nitrogen/generated/shared/c++/FirmwareArtifactSweepResult.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridReactNativeRangeDownloaderSpec.cpp +13 -0
- package/nitrogen/generated/shared/c++/HybridReactNativeRangeDownloaderSpec.hpp +62 -0
- package/package.json +4 -2
- package/src/ReactNativeRangeDownloader.nitro.ts +134 -1
- package/src/index.tsx +3 -1
|
@@ -95,6 +95,173 @@ class ReactNativeRangeDownloader: HybridReactNativeRangeDownloaderSpec {
|
|
|
95
95
|
}
|
|
96
96
|
return NSTemporaryDirectory()
|
|
97
97
|
}
|
|
98
|
+
|
|
99
|
+
func getFirmwareArtifactCapabilities() throws -> FirmwareArtifactCapabilities {
|
|
100
|
+
FirmwareArtifactCapabilities(
|
|
101
|
+
firmwareArtifactProtocolVersion: 1,
|
|
102
|
+
supportedRouteTypes: ["domain", "pinnedIp"],
|
|
103
|
+
supportsArchiveMaterialization: true,
|
|
104
|
+
maxReadBytes: Double(FirmwareArtifactStore.maxReadBytes)
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
func downloadFirmwareArtifact(
|
|
109
|
+
params: FirmwareArtifactDownloadParams
|
|
110
|
+
) throws -> Promise<FirmwareArtifactReceipt> {
|
|
111
|
+
Promise.async {
|
|
112
|
+
let artifact = try await FirmwareArtifactStore.shared.download(params)
|
|
113
|
+
return FirmwareArtifactReceipt(
|
|
114
|
+
artifactRef: artifact.artifactRef,
|
|
115
|
+
size: Double(artifact.size),
|
|
116
|
+
sha256: artifact.sha256
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func cancelFirmwareArtifactDownloads(
|
|
122
|
+
params: FirmwareArtifactCancelParams
|
|
123
|
+
) throws -> Promise<Void> {
|
|
124
|
+
Promise.async {
|
|
125
|
+
try await FirmwareArtifactStore.shared.cancelDownloads(
|
|
126
|
+
transactionId: params.transactionId
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
func discardFirmwareArtifact(
|
|
132
|
+
params: FirmwareArtifactRefParams
|
|
133
|
+
) throws -> Promise<Void> {
|
|
134
|
+
Promise.async {
|
|
135
|
+
try FirmwareArtifactStore.shared.discard(artifactRef: params.artifactRef)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
func openFirmwareArtifact(
|
|
140
|
+
params: FirmwareArtifactRefParams
|
|
141
|
+
) throws -> Promise<FirmwareArtifactReaderInfo> {
|
|
142
|
+
Promise.async {
|
|
143
|
+
let reader = try FirmwareArtifactStore.shared.open(
|
|
144
|
+
artifactRef: params.artifactRef
|
|
145
|
+
)
|
|
146
|
+
return FirmwareArtifactReaderInfo(
|
|
147
|
+
readerId: reader.readerId,
|
|
148
|
+
size: Double(reader.size)
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
func readFirmwareArtifact(
|
|
154
|
+
params: FirmwareArtifactReaderReadParams
|
|
155
|
+
) throws -> Promise<ArrayBuffer> {
|
|
156
|
+
Promise.async {
|
|
157
|
+
guard
|
|
158
|
+
params.offset.isFinite,
|
|
159
|
+
params.offset >= 0,
|
|
160
|
+
params.offset <= Double(Int64.max),
|
|
161
|
+
params.offset.rounded() == params.offset,
|
|
162
|
+
params.length.isFinite,
|
|
163
|
+
params.length > 0,
|
|
164
|
+
params.length <= Double(Int.max),
|
|
165
|
+
params.length.rounded() == params.length
|
|
166
|
+
else {
|
|
167
|
+
throw FirmwareArtifactStoreError.readerInvalid(
|
|
168
|
+
"Invalid firmware artifact read"
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
let data = try FirmwareArtifactStore.shared.read(
|
|
172
|
+
readerId: params.readerId,
|
|
173
|
+
offset: Int64(params.offset),
|
|
174
|
+
length: Int(params.length)
|
|
175
|
+
)
|
|
176
|
+
return try ArrayBuffer.copy(data: data)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
func closeFirmwareArtifact(
|
|
181
|
+
params: FirmwareArtifactReaderCloseParams
|
|
182
|
+
) throws -> Promise<Void> {
|
|
183
|
+
Promise.async {
|
|
184
|
+
try FirmwareArtifactStore.shared.close(readerId: params.readerId)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
func materializeFirmwareArchive(
|
|
189
|
+
params: FirmwareArchiveMaterializeParams
|
|
190
|
+
) throws -> Promise<FirmwareArchiveMaterializeResult> {
|
|
191
|
+
Promise.async {
|
|
192
|
+
let entries = try FirmwareArtifactStore.shared.materializeArchive(
|
|
193
|
+
leaseRef: params.leaseRef,
|
|
194
|
+
artifactRef: params.archiveArtifactRef,
|
|
195
|
+
expectedEntries: params.expectedEntries
|
|
196
|
+
)
|
|
197
|
+
return FirmwareArchiveMaterializeResult(
|
|
198
|
+
artifacts: entries.map { entry in
|
|
199
|
+
FirmwareArchiveMaterializedArtifact(
|
|
200
|
+
entryName: entry.entryName,
|
|
201
|
+
receipt: FirmwareArtifactReceipt(
|
|
202
|
+
artifactRef: entry.artifact.artifactRef,
|
|
203
|
+
size: Double(entry.artifact.size),
|
|
204
|
+
sha256: entry.artifact.sha256
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
func createFirmwareArtifactLease(
|
|
213
|
+
params: FirmwareArtifactLeaseCreateParams
|
|
214
|
+
) throws -> Promise<FirmwareArtifactLease> {
|
|
215
|
+
Promise.async {
|
|
216
|
+
FirmwareArtifactLease(
|
|
217
|
+
leaseRef: try FirmwareArtifactStore.shared.createLease(
|
|
218
|
+
transactionId: params.transactionId
|
|
219
|
+
)
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
func retainFirmwareArtifact(
|
|
225
|
+
params: FirmwareArtifactLeaseRetainParams
|
|
226
|
+
) throws -> Promise<Void> {
|
|
227
|
+
Promise.async {
|
|
228
|
+
try FirmwareArtifactStore.shared.retain(
|
|
229
|
+
leaseRef: params.leaseRef,
|
|
230
|
+
artifactRef: params.artifactRef
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
func releaseFirmwareArtifactLease(
|
|
236
|
+
params: FirmwareArtifactLeaseReleaseParams
|
|
237
|
+
) throws -> Promise<Void> {
|
|
238
|
+
Promise.async {
|
|
239
|
+
try FirmwareArtifactStore.shared.releaseLease(
|
|
240
|
+
leaseRef: params.leaseRef,
|
|
241
|
+
disposition: params.disposition
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
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
|
+
func sweepFirmwareArtifactOrphans() throws -> Promise<FirmwareArtifactSweepResult> {
|
|
257
|
+
Promise.async {
|
|
258
|
+
let result = try FirmwareArtifactStore.shared.sweepOrphans()
|
|
259
|
+
return FirmwareArtifactSweepResult(
|
|
260
|
+
deletedFiles: Double(result.deletedFiles),
|
|
261
|
+
deletedBytes: Double(result.deletedBytes)
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
}
|
|
98
265
|
}
|
|
99
266
|
|
|
100
267
|
// MARK: - RangeDownloader (migrated core)
|
|
@@ -156,10 +323,79 @@ extension RangeFallbackClass {
|
|
|
156
323
|
}
|
|
157
324
|
}
|
|
158
325
|
|
|
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
|
+
|
|
159
381
|
public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
160
382
|
|
|
161
383
|
public static let shared = RangeDownloader()
|
|
162
384
|
|
|
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
|
+
|
|
163
399
|
/// Posted by the AppDelegate from
|
|
164
400
|
/// application(_:handleEventsForBackgroundURLSession:completionHandler:).
|
|
165
401
|
/// userInfo: ["identifier": String, "completionHandler": () -> Void].
|
|
@@ -196,6 +432,11 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
196
432
|
/// notification), keyed by session identifier, so we can call each back once
|
|
197
433
|
/// all its queued background events have been delivered.
|
|
198
434
|
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> = []
|
|
199
440
|
|
|
200
441
|
// Per-run mutable state.
|
|
201
442
|
private final class RunState {
|
|
@@ -326,14 +567,30 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
326
567
|
@objc private func handleBackgroundEventsNotification(_ note: Notification) {
|
|
327
568
|
guard let identifier = note.userInfo?["identifier"] as? String,
|
|
328
569
|
Self.channel(forIdentifier: identifier) != nil else { return }
|
|
329
|
-
// Re-create the session with this delegate so queued completion events are
|
|
330
|
-
// delivered here on a background relaunch.
|
|
331
|
-
_ = session(forIdentifier: identifier)
|
|
332
570
|
if let handler = note.userInfo?["completionHandler"] as? () -> Void {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
571
|
+
attachBackgroundEvents(
|
|
572
|
+
identifier: identifier,
|
|
573
|
+
completionHandler: handler
|
|
574
|
+
)
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
private func attachBackgroundEvents(
|
|
579
|
+
identifier: String,
|
|
580
|
+
completionHandler: @escaping () -> Void
|
|
581
|
+
) {
|
|
582
|
+
let replacedHandler: (() -> Void)? = lock.withLockValue {
|
|
583
|
+
backgroundCompletionHandlers.updateValue(
|
|
584
|
+
completionHandler,
|
|
585
|
+
forKey: identifier
|
|
586
|
+
)
|
|
336
587
|
}
|
|
588
|
+
// UIKit should provide one live handler per session. Complete an older
|
|
589
|
+
// handler instead of leaking it if the callback is unexpectedly repeated.
|
|
590
|
+
replacedHandler?()
|
|
591
|
+
// Store the handler before creating the session. Delegate delivery can
|
|
592
|
+
// begin immediately when a background relaunch reattaches this identifier.
|
|
593
|
+
_ = session(forIdentifier: identifier)
|
|
337
594
|
}
|
|
338
595
|
|
|
339
596
|
// MARK: - Session cache
|
|
@@ -437,6 +694,240 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
437
694
|
return (r, decoded.segIndex)
|
|
438
695
|
}
|
|
439
696
|
|
|
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
|
+
|
|
440
931
|
// MARK: - Public entry
|
|
441
932
|
|
|
442
933
|
/// Downloads [urlString] into [filePath] using concurrent background ranges.
|
|
@@ -972,6 +1463,28 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
972
1463
|
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
|
|
973
1464
|
didWriteData bytesWritten: Int64, totalBytesWritten: Int64,
|
|
974
1465
|
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
|
+
}
|
|
975
1488
|
guard let desc = downloadTask.taskDescription,
|
|
976
1489
|
let (state, idx) = run(for: desc) else { return }
|
|
977
1490
|
lock.lock()
|
|
@@ -1002,6 +1515,53 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
1002
1515
|
|
|
1003
1516
|
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask,
|
|
1004
1517
|
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
|
+
}
|
|
1005
1565
|
guard let desc = downloadTask.taskDescription,
|
|
1006
1566
|
let (state, idx) = run(for: desc) else { return }
|
|
1007
1567
|
let ranges = lock.withLockValue { state.ranges }
|
|
@@ -1100,6 +1660,39 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
1100
1660
|
}
|
|
1101
1661
|
|
|
1102
1662
|
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
|
+
}
|
|
1103
1696
|
guard let desc = task.taskDescription,
|
|
1104
1697
|
let (state, idx) = run(for: desc) else { return }
|
|
1105
1698
|
let ranges = lock.withLockValue { state.ranges }
|
|
@@ -1275,6 +1868,26 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
1275
1868
|
willPerformHTTPRedirection response: HTTPURLResponse,
|
|
1276
1869
|
newRequest request: URLRequest,
|
|
1277
1870
|
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
|
+
}
|
|
1278
1891
|
if request.url?.scheme?.lowercased() != "https" {
|
|
1279
1892
|
OneKeyLog.error("RangeDownloader", "blocked redirect to non-HTTPS URL")
|
|
1280
1893
|
if let desc = task.taskDescription, let (state, _) = run(for: desc) {
|
|
@@ -1286,6 +1899,25 @@ public final class RangeDownloader: NSObject, URLSessionDownloadDelegate {
|
|
|
1286
1899
|
}
|
|
1287
1900
|
}
|
|
1288
1901
|
|
|
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
|
+
|
|
1289
1921
|
/// Called on the session delegate queue when all background events for this
|
|
1290
1922
|
/// session have been delivered after a background relaunch.
|
|
1291
1923
|
public func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
|