@onekeyfe/react-native-range-downloader 3.0.81-alpha.1 → 3.0.81-alpha.3
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/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactStore.kt +59 -127
- package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/ReactNativeRangeDownloader.kt +16 -20
- package/android/src/test/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactDeadlineTest.kt +26 -0
- package/ios/FirmwareArtifactStore.swift +125 -170
- package/ios/RangeDownloadLogic.swift +71 -0
- package/ios/ReactNativeRangeDownloader.swift +22 -60
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts +0 -4
- package/lib/typescript/src/ReactNativeRangeDownloader.nitro.d.ts.map +1 -1
- 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/HybridReactNativeRangeDownloaderSpec.kt +0 -4
- 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/HybridReactNativeRangeDownloaderSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridReactNativeRangeDownloaderSpec_cxx.swift +0 -19
- 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 +1 -8
- 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
package/android/src/main/java/com/margelo/nitro/reactnativerangedownloader/FirmwareArtifactStore.kt
CHANGED
|
@@ -6,7 +6,6 @@ import com.sniconnect.SniPinnedTransport
|
|
|
6
6
|
import java.io.BufferedInputStream
|
|
7
7
|
import java.io.File
|
|
8
8
|
import java.io.FileInputStream
|
|
9
|
-
import java.io.FileOutputStream
|
|
10
9
|
import java.io.IOException
|
|
11
10
|
import java.io.RandomAccessFile
|
|
12
11
|
import java.security.MessageDigest
|
|
@@ -14,14 +13,29 @@ import java.util.UUID
|
|
|
14
13
|
import java.util.concurrent.ConcurrentHashMap
|
|
15
14
|
import java.util.concurrent.TimeUnit
|
|
16
15
|
import java.util.zip.ZipInputStream
|
|
16
|
+
import javax.net.ssl.SSLException
|
|
17
|
+
import kotlin.math.ceil
|
|
17
18
|
import okhttp3.Call
|
|
18
19
|
import okhttp3.OkHttpClient
|
|
19
20
|
import okhttp3.Protocol
|
|
20
21
|
import okhttp3.Request
|
|
21
22
|
import okhttp3.Response
|
|
22
23
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
private const val DEFAULT_FIRMWARE_DOWNLOAD_DEADLINE_SECONDS = 180.0
|
|
26
|
+
private const val MAX_FIRMWARE_DOWNLOAD_DEADLINE_SECONDS = 24.0 * 60 * 60
|
|
27
|
+
|
|
28
|
+
internal fun validateFirmwareDownloadDeadlineSeconds(value: Double?): Double {
|
|
29
|
+
val deadline = value ?: DEFAULT_FIRMWARE_DOWNLOAD_DEADLINE_SECONDS
|
|
30
|
+
require(
|
|
31
|
+
deadline.isFinite() &&
|
|
32
|
+
deadline > 0 &&
|
|
33
|
+
deadline <= MAX_FIRMWARE_DOWNLOAD_DEADLINE_SECONDS
|
|
34
|
+
) {
|
|
35
|
+
"Invalid firmware download deadline"
|
|
36
|
+
}
|
|
37
|
+
return deadline
|
|
38
|
+
}
|
|
25
39
|
|
|
26
40
|
internal data class StoredFirmwareArtifact(
|
|
27
41
|
val artifactRef: String,
|
|
@@ -43,23 +57,26 @@ private data class StagedFirmwareArchiveEntry(
|
|
|
43
57
|
)
|
|
44
58
|
|
|
45
59
|
private data class FirmwareDownloadKey(
|
|
46
|
-
val transactionId: String,
|
|
47
60
|
val expectedSha256: String,
|
|
48
61
|
)
|
|
49
62
|
|
|
63
|
+
private class FirmwareDownloadLock {
|
|
64
|
+
val monitor = Any()
|
|
65
|
+
var references = 0
|
|
66
|
+
}
|
|
67
|
+
|
|
50
68
|
internal object FirmwareArtifactStore {
|
|
51
69
|
const val MAX_READ_BYTES = 256 * 1024
|
|
52
70
|
|
|
53
71
|
private const val MAX_ARTIFACT_BYTES = 512L * 1024 * 1024
|
|
54
|
-
private const val MAX_LEASE_METADATA_BYTES = 1024L * 1024
|
|
55
|
-
private const val MAX_TOTAL_LEASE_REFS = 8192
|
|
56
72
|
private const val FINAL_ARTIFACT_GRACE_MS = 24L * 60 * 60 * 1000
|
|
57
73
|
private const val PARTIAL_ARTIFACT_GRACE_MS = 7L * 24 * 60 * 60 * 1000
|
|
58
74
|
private val sha256Pattern = Regex("^[a-fA-F0-9]{64}$")
|
|
59
75
|
private val artifactRefPattern = Regex("^fw:[a-f0-9]{64}$")
|
|
60
76
|
private val leaseRefPattern = Regex("^fwlease:[a-f0-9-]{36}$")
|
|
61
77
|
private val identifierPattern = Regex("^[A-Za-z0-9._:-]{1,160}$")
|
|
62
|
-
private val downloadLocks =
|
|
78
|
+
private val downloadLocks =
|
|
79
|
+
ConcurrentHashMap<FirmwareDownloadKey, FirmwareDownloadLock>()
|
|
63
80
|
private val activeCalls =
|
|
64
81
|
ConcurrentHashMap<String, MutableSet<Call>>()
|
|
65
82
|
private val cancelledTransactions =
|
|
@@ -69,6 +86,7 @@ internal object FirmwareArtifactStore {
|
|
|
69
86
|
private val leaseLock = Any()
|
|
70
87
|
private val readerLock = Any()
|
|
71
88
|
private val readers = mutableMapOf<String, OpenReader>()
|
|
89
|
+
private val leases = mutableMapOf<String, LeaseState>()
|
|
72
90
|
|
|
73
91
|
private data class LeaseState(
|
|
74
92
|
val transactionId: String,
|
|
@@ -102,14 +120,15 @@ internal object FirmwareArtifactStore {
|
|
|
102
120
|
transactionId = params.transactionId,
|
|
103
121
|
artifactRef = "fw:${validated.expectedSha256}",
|
|
104
122
|
)
|
|
105
|
-
val lockKey = FirmwareDownloadKey(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
123
|
+
val lockKey = FirmwareDownloadKey(validated.expectedSha256)
|
|
124
|
+
val downloadLock = downloadLocks.compute(lockKey) { _, current ->
|
|
125
|
+
(current ?: FirmwareDownloadLock()).also {
|
|
126
|
+
it.references += 1
|
|
127
|
+
}
|
|
128
|
+
} ?: error("Firmware artifact lock is unavailable")
|
|
110
129
|
markDownloadActive(validated.expectedSha256, 1)
|
|
111
130
|
try {
|
|
112
|
-
return synchronized(
|
|
131
|
+
return synchronized(downloadLock.monitor) {
|
|
113
132
|
check(!cancelledTransactions.contains(params.transactionId)) {
|
|
114
133
|
"ARTIFACT_CANCELLED: firmware artifact download was cancelled"
|
|
115
134
|
}
|
|
@@ -117,6 +136,14 @@ internal object FirmwareArtifactStore {
|
|
|
117
136
|
}
|
|
118
137
|
} finally {
|
|
119
138
|
markDownloadActive(validated.expectedSha256, -1)
|
|
139
|
+
downloadLocks.compute(lockKey) { _, current ->
|
|
140
|
+
if (current !== downloadLock) {
|
|
141
|
+
current
|
|
142
|
+
} else {
|
|
143
|
+
current.references -= 1
|
|
144
|
+
current.takeIf { it.references > 0 }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
120
147
|
}
|
|
121
148
|
}
|
|
122
149
|
|
|
@@ -133,7 +160,7 @@ internal object FirmwareArtifactStore {
|
|
|
133
160
|
fun discard(artifactRef: String) {
|
|
134
161
|
val file = resolveArtifactFile(artifactRef)
|
|
135
162
|
synchronized(leaseLock) {
|
|
136
|
-
require(
|
|
163
|
+
require(leases.values.none { artifactRef in it.artifactRefs }) {
|
|
137
164
|
"ARTIFACT_LEASED: firmware artifact is retained"
|
|
138
165
|
}
|
|
139
166
|
}
|
|
@@ -284,6 +311,7 @@ internal object FirmwareArtifactStore {
|
|
|
284
311
|
val maxBytes: Long,
|
|
285
312
|
val expectedSha256: String,
|
|
286
313
|
val hostname: String,
|
|
314
|
+
val overallDeadlineSeconds: Double,
|
|
287
315
|
)
|
|
288
316
|
|
|
289
317
|
private fun validateDownloadParams(
|
|
@@ -324,6 +352,8 @@ internal object FirmwareArtifactStore {
|
|
|
324
352
|
require(sha256Pattern.matches(params.expectedSha256)) {
|
|
325
353
|
"Invalid firmware artifact SHA-256"
|
|
326
354
|
}
|
|
355
|
+
val overallDeadlineSeconds =
|
|
356
|
+
validateFirmwareDownloadDeadlineSeconds(params.overallDeadlineSeconds)
|
|
327
357
|
require(params.routeType == "domain" || params.routeType == "pinnedIp") {
|
|
328
358
|
"Invalid firmware route type"
|
|
329
359
|
}
|
|
@@ -341,6 +371,7 @@ internal object FirmwareArtifactStore {
|
|
|
341
371
|
maxBytes = maxBytes,
|
|
342
372
|
expectedSha256 = params.expectedSha256.lowercase(),
|
|
343
373
|
hostname = url.host,
|
|
374
|
+
overallDeadlineSeconds = overallDeadlineSeconds,
|
|
344
375
|
)
|
|
345
376
|
}
|
|
346
377
|
|
|
@@ -400,12 +431,10 @@ internal object FirmwareArtifactStore {
|
|
|
400
431
|
.build()
|
|
401
432
|
}
|
|
402
433
|
val call = client.newCall(requestBuilder.build())
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
call.timeout().timeout(deadline.toLong().coerceAtLeast(1), TimeUnit.SECONDS)
|
|
408
|
-
}
|
|
434
|
+
call.timeout().timeout(
|
|
435
|
+
ceil(validated.overallDeadlineSeconds * 1000).toLong(),
|
|
436
|
+
TimeUnit.MILLISECONDS,
|
|
437
|
+
)
|
|
409
438
|
|
|
410
439
|
registerCall(params.transactionId, call)
|
|
411
440
|
try {
|
|
@@ -428,6 +457,12 @@ internal object FirmwareArtifactStore {
|
|
|
428
457
|
error,
|
|
429
458
|
)
|
|
430
459
|
}
|
|
460
|
+
if (generateSequence<Throwable>(error) { it.cause }.any { it is SSLException }) {
|
|
461
|
+
throw IllegalStateException(
|
|
462
|
+
"ARTIFACT_TLS_FAILED: firmware TLS validation failed",
|
|
463
|
+
error,
|
|
464
|
+
)
|
|
465
|
+
}
|
|
431
466
|
throw IllegalStateException(
|
|
432
467
|
"ARTIFACT_NETWORK_FAILED: firmware request failed",
|
|
433
468
|
error,
|
|
@@ -563,13 +598,11 @@ internal object FirmwareArtifactStore {
|
|
|
563
598
|
"Invalid firmware transactionId"
|
|
564
599
|
}
|
|
565
600
|
return synchronized(leaseLock) {
|
|
566
|
-
val leases = loadLeasesLocked()
|
|
567
601
|
require(leases.size < 32) {
|
|
568
602
|
"Too many firmware artifact leases"
|
|
569
603
|
}
|
|
570
604
|
val leaseRef = "fwlease:${UUID.randomUUID()}"
|
|
571
605
|
leases[leaseRef] = LeaseState(transactionId, mutableSetOf())
|
|
572
|
-
saveLeasesLocked(leases)
|
|
573
606
|
leaseRef
|
|
574
607
|
}
|
|
575
608
|
}
|
|
@@ -592,41 +625,18 @@ internal object FirmwareArtifactStore {
|
|
|
592
625
|
"Invalid firmware lease disposition"
|
|
593
626
|
}
|
|
594
627
|
val transactionId = synchronized(leaseLock) {
|
|
595
|
-
val leases = loadLeasesLocked()
|
|
596
628
|
val removed = leases.remove(validateLeaseRef(leaseRef))
|
|
597
629
|
require(removed != null) {
|
|
598
630
|
"Firmware artifact lease is unavailable"
|
|
599
631
|
}
|
|
600
|
-
saveLeasesLocked(leases)
|
|
601
632
|
removed.transactionId
|
|
602
633
|
}
|
|
603
634
|
cancelledTransactions.remove(transactionId)
|
|
604
|
-
downloadLocks.keys.removeIf { it.transactionId == transactionId }
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
fun reconcileLeases(activeLeaseRefs: Array<String>) {
|
|
608
|
-
require(activeLeaseRefs.size <= 32) {
|
|
609
|
-
"Too many active firmware artifact leases"
|
|
610
|
-
}
|
|
611
|
-
val active = activeLeaseRefs.mapTo(mutableSetOf()) {
|
|
612
|
-
validateLeaseRef(it)
|
|
613
|
-
}
|
|
614
|
-
require(active.size == activeLeaseRefs.size) {
|
|
615
|
-
"Duplicate active firmware artifact lease"
|
|
616
|
-
}
|
|
617
|
-
synchronized(leaseLock) {
|
|
618
|
-
val leases = loadLeasesLocked()
|
|
619
|
-
require(active.all { leases.containsKey(it) }) {
|
|
620
|
-
"Firmware artifact lease reconciliation is incomplete"
|
|
621
|
-
}
|
|
622
|
-
leases.keys.retainAll(active)
|
|
623
|
-
saveLeasesLocked(leases)
|
|
624
|
-
}
|
|
625
635
|
}
|
|
626
636
|
|
|
627
637
|
fun sweepOrphans(): Pair<Int, Long> {
|
|
628
638
|
val retainedSha256 = synchronized(leaseLock) {
|
|
629
|
-
|
|
639
|
+
leases.values
|
|
630
640
|
.flatMap { it.artifactRefs }
|
|
631
641
|
.mapTo(mutableSetOf()) { it.removePrefix("fw:") }
|
|
632
642
|
}
|
|
@@ -640,7 +650,7 @@ internal object FirmwareArtifactStore {
|
|
|
640
650
|
var deletedFiles = 0
|
|
641
651
|
var deletedBytes = 0L
|
|
642
652
|
root.listFiles()?.forEach { file ->
|
|
643
|
-
if (!file.isFile
|
|
653
|
+
if (!file.isFile) return@forEach
|
|
644
654
|
val sha256 = file.name.take(64)
|
|
645
655
|
if (
|
|
646
656
|
!sha256Pattern.matches(sha256) ||
|
|
@@ -669,7 +679,7 @@ internal object FirmwareArtifactStore {
|
|
|
669
679
|
|
|
670
680
|
private fun requireLease(leaseRef: String) {
|
|
671
681
|
synchronized(leaseLock) {
|
|
672
|
-
require(
|
|
682
|
+
require(leases.containsKey(validateLeaseRef(leaseRef))) {
|
|
673
683
|
"Firmware artifact lease is unavailable"
|
|
674
684
|
}
|
|
675
685
|
}
|
|
@@ -684,7 +694,6 @@ internal object FirmwareArtifactStore {
|
|
|
684
694
|
"Invalid firmware artifactRef"
|
|
685
695
|
}
|
|
686
696
|
synchronized(leaseLock) {
|
|
687
|
-
val leases = loadLeasesLocked()
|
|
688
697
|
val lease = leases[validateLeaseRef(leaseRef)]
|
|
689
698
|
?: error("Firmware artifact lease is unavailable")
|
|
690
699
|
if (transactionId != null) {
|
|
@@ -692,9 +701,7 @@ internal object FirmwareArtifactStore {
|
|
|
692
701
|
"Firmware artifact lease transaction mismatch"
|
|
693
702
|
}
|
|
694
703
|
}
|
|
695
|
-
|
|
696
|
-
saveLeasesLocked(leases)
|
|
697
|
-
}
|
|
704
|
+
lease.artifactRefs.add(artifactRef)
|
|
698
705
|
}
|
|
699
706
|
}
|
|
700
707
|
|
|
@@ -705,81 +712,6 @@ internal object FirmwareArtifactStore {
|
|
|
705
712
|
return leaseRef
|
|
706
713
|
}
|
|
707
714
|
|
|
708
|
-
private fun loadLeasesLocked(): MutableMap<String, LeaseState> {
|
|
709
|
-
val file = File(root, "leases.json")
|
|
710
|
-
if (!file.exists()) return mutableMapOf()
|
|
711
|
-
require(file.length() in 1..MAX_LEASE_METADATA_BYTES) {
|
|
712
|
-
"Firmware lease metadata is too large"
|
|
713
|
-
}
|
|
714
|
-
val envelope = JSONObject(file.readText(Charsets.UTF_8))
|
|
715
|
-
require(envelope.optInt("schemaVersion") == 1) {
|
|
716
|
-
"Unsupported firmware lease schema"
|
|
717
|
-
}
|
|
718
|
-
val result = mutableMapOf<String, LeaseState>()
|
|
719
|
-
val jsonLeases = envelope.getJSONObject("leases")
|
|
720
|
-
val keys = jsonLeases.keys()
|
|
721
|
-
while (keys.hasNext()) {
|
|
722
|
-
val leaseRef = validateLeaseRef(keys.next())
|
|
723
|
-
val jsonLease = jsonLeases.getJSONObject(leaseRef)
|
|
724
|
-
val transactionId = jsonLease.getString("transactionId")
|
|
725
|
-
require(identifierPattern.matches(transactionId)) {
|
|
726
|
-
"Invalid persisted firmware transactionId"
|
|
727
|
-
}
|
|
728
|
-
val jsonRefs = jsonLease.getJSONArray("artifactRefs")
|
|
729
|
-
require(jsonRefs.length() <= 4096) {
|
|
730
|
-
"Too many persisted firmware artifact refs"
|
|
731
|
-
}
|
|
732
|
-
val refs = mutableSetOf<String>()
|
|
733
|
-
for (index in 0 until jsonRefs.length()) {
|
|
734
|
-
val artifactRef = jsonRefs.getString(index)
|
|
735
|
-
require(artifactRefPattern.matches(artifactRef) && refs.add(artifactRef)) {
|
|
736
|
-
"Invalid persisted firmware artifact ref"
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
result[leaseRef] = LeaseState(transactionId, refs)
|
|
740
|
-
}
|
|
741
|
-
require(result.size <= 32) {
|
|
742
|
-
"Too many persisted firmware artifact leases"
|
|
743
|
-
}
|
|
744
|
-
require(result.values.sumOf { it.artifactRefs.size } <= MAX_TOTAL_LEASE_REFS) {
|
|
745
|
-
"Too many persisted firmware artifact refs"
|
|
746
|
-
}
|
|
747
|
-
return result
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
private fun saveLeasesLocked(leases: Map<String, LeaseState>) {
|
|
751
|
-
require(
|
|
752
|
-
leases.size <= 32 &&
|
|
753
|
-
leases.values.sumOf { it.artifactRefs.size } <= MAX_TOTAL_LEASE_REFS
|
|
754
|
-
) {
|
|
755
|
-
"Firmware lease metadata is too large"
|
|
756
|
-
}
|
|
757
|
-
val jsonLeases = JSONObject()
|
|
758
|
-
leases.toSortedMap().forEach { (leaseRef, lease) ->
|
|
759
|
-
jsonLeases.put(
|
|
760
|
-
leaseRef,
|
|
761
|
-
JSONObject()
|
|
762
|
-
.put("transactionId", lease.transactionId)
|
|
763
|
-
.put("artifactRefs", JSONArray(lease.artifactRefs.sorted())),
|
|
764
|
-
)
|
|
765
|
-
}
|
|
766
|
-
val bytes = JSONObject()
|
|
767
|
-
.put("schemaVersion", 1)
|
|
768
|
-
.put("leases", jsonLeases)
|
|
769
|
-
.toString()
|
|
770
|
-
.toByteArray(Charsets.UTF_8)
|
|
771
|
-
require(bytes.size.toLong() <= MAX_LEASE_METADATA_BYTES) {
|
|
772
|
-
"Firmware lease metadata is too large"
|
|
773
|
-
}
|
|
774
|
-
val destination = File(root, "leases.json")
|
|
775
|
-
val temporary = File(root, ".leases-${UUID.randomUUID()}.tmp")
|
|
776
|
-
FileOutputStream(temporary).use { output ->
|
|
777
|
-
output.write(bytes)
|
|
778
|
-
output.fd.sync()
|
|
779
|
-
}
|
|
780
|
-
Os.rename(temporary.absolutePath, destination.absolutePath)
|
|
781
|
-
}
|
|
782
|
-
|
|
783
715
|
private fun markDownloadActive(sha256: String, delta: Int) {
|
|
784
716
|
synchronized(activeDownloadLock) {
|
|
785
717
|
val count = (activeDownloadCounts[sha256] ?: 0) + delta
|
|
@@ -9,6 +9,9 @@ import java.io.File
|
|
|
9
9
|
import java.security.MessageDigest
|
|
10
10
|
import java.util.concurrent.CopyOnWriteArrayList
|
|
11
11
|
import java.util.concurrent.atomic.AtomicLong
|
|
12
|
+
import kotlinx.coroutines.CoroutineScope
|
|
13
|
+
import kotlinx.coroutines.Dispatchers
|
|
14
|
+
import kotlinx.coroutines.SupervisorJob
|
|
12
15
|
|
|
13
16
|
// P1: Nitro adapter for the Android concurrent multi-range downloader.
|
|
14
17
|
//
|
|
@@ -34,6 +37,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
34
37
|
|
|
35
38
|
private val listeners = CopyOnWriteArrayList<Listener>()
|
|
36
39
|
private val nextListenerId = AtomicLong(1)
|
|
40
|
+
private val firmwareArtifactScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
|
37
41
|
|
|
38
42
|
// Active downloads keyed by "channel|taskId" so cancel/discardArtifacts can
|
|
39
43
|
// flip the abort flag + stop the worker pool BEFORE deleting files, instead of
|
|
@@ -268,7 +272,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
268
272
|
|
|
269
273
|
override fun getFirmwareArtifactCapabilities(): FirmwareArtifactCapabilities {
|
|
270
274
|
return FirmwareArtifactCapabilities(
|
|
271
|
-
firmwareArtifactProtocolVersion =
|
|
275
|
+
firmwareArtifactProtocolVersion = 2.0,
|
|
272
276
|
supportedRouteTypes = arrayOf("domain", "pinnedIp"),
|
|
273
277
|
supportsArchiveMaterialization = true,
|
|
274
278
|
maxReadBytes = FirmwareArtifactStore.MAX_READ_BYTES.toDouble(),
|
|
@@ -278,7 +282,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
278
282
|
override fun downloadFirmwareArtifact(
|
|
279
283
|
params: FirmwareArtifactDownloadParams,
|
|
280
284
|
): Promise<FirmwareArtifactReceipt> {
|
|
281
|
-
return Promise.async {
|
|
285
|
+
return Promise.async(firmwareArtifactScope) {
|
|
282
286
|
val artifact = FirmwareArtifactStore.download(params)
|
|
283
287
|
FirmwareArtifactReceipt(
|
|
284
288
|
artifactRef = artifact.artifactRef,
|
|
@@ -291,7 +295,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
291
295
|
override fun cancelFirmwareArtifactDownloads(
|
|
292
296
|
params: FirmwareArtifactCancelParams,
|
|
293
297
|
): Promise<Unit> {
|
|
294
|
-
return Promise.async {
|
|
298
|
+
return Promise.async(firmwareArtifactScope) {
|
|
295
299
|
FirmwareArtifactStore.cancelDownloads(params.transactionId)
|
|
296
300
|
}
|
|
297
301
|
}
|
|
@@ -299,7 +303,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
299
303
|
override fun discardFirmwareArtifact(
|
|
300
304
|
params: FirmwareArtifactRefParams,
|
|
301
305
|
): Promise<Unit> {
|
|
302
|
-
return Promise.async {
|
|
306
|
+
return Promise.async(firmwareArtifactScope) {
|
|
303
307
|
FirmwareArtifactStore.discard(params.artifactRef)
|
|
304
308
|
}
|
|
305
309
|
}
|
|
@@ -307,7 +311,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
307
311
|
override fun openFirmwareArtifact(
|
|
308
312
|
params: FirmwareArtifactRefParams,
|
|
309
313
|
): Promise<FirmwareArtifactReaderInfo> {
|
|
310
|
-
return Promise.async {
|
|
314
|
+
return Promise.async(firmwareArtifactScope) {
|
|
311
315
|
val (readerId, size) = FirmwareArtifactStore.open(params.artifactRef)
|
|
312
316
|
FirmwareArtifactReaderInfo(readerId = readerId, size = size.toDouble())
|
|
313
317
|
}
|
|
@@ -316,7 +320,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
316
320
|
override fun readFirmwareArtifact(
|
|
317
321
|
params: FirmwareArtifactReaderReadParams,
|
|
318
322
|
): Promise<ArrayBuffer> {
|
|
319
|
-
return Promise.async {
|
|
323
|
+
return Promise.async(firmwareArtifactScope) {
|
|
320
324
|
require(
|
|
321
325
|
params.offset.isFinite() &&
|
|
322
326
|
params.offset >= 0 &&
|
|
@@ -340,7 +344,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
340
344
|
override fun closeFirmwareArtifact(
|
|
341
345
|
params: FirmwareArtifactReaderCloseParams,
|
|
342
346
|
): Promise<Unit> {
|
|
343
|
-
return Promise.async {
|
|
347
|
+
return Promise.async(firmwareArtifactScope) {
|
|
344
348
|
FirmwareArtifactStore.close(params.readerId)
|
|
345
349
|
}
|
|
346
350
|
}
|
|
@@ -348,7 +352,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
348
352
|
override fun materializeFirmwareArchive(
|
|
349
353
|
params: FirmwareArchiveMaterializeParams,
|
|
350
354
|
): Promise<FirmwareArchiveMaterializeResult> {
|
|
351
|
-
return Promise.async {
|
|
355
|
+
return Promise.async(firmwareArtifactScope) {
|
|
352
356
|
val artifacts = FirmwareArtifactStore.materializeArchive(
|
|
353
357
|
params.leaseRef,
|
|
354
358
|
params.archiveArtifactRef,
|
|
@@ -372,7 +376,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
372
376
|
override fun createFirmwareArtifactLease(
|
|
373
377
|
params: FirmwareArtifactLeaseCreateParams,
|
|
374
378
|
): Promise<FirmwareArtifactLease> {
|
|
375
|
-
return Promise.async {
|
|
379
|
+
return Promise.async(firmwareArtifactScope) {
|
|
376
380
|
FirmwareArtifactLease(
|
|
377
381
|
leaseRef = FirmwareArtifactStore.createLease(params.transactionId),
|
|
378
382
|
)
|
|
@@ -382,7 +386,7 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
382
386
|
override fun retainFirmwareArtifact(
|
|
383
387
|
params: FirmwareArtifactLeaseRetainParams,
|
|
384
388
|
): Promise<Unit> {
|
|
385
|
-
return Promise.async {
|
|
389
|
+
return Promise.async(firmwareArtifactScope) {
|
|
386
390
|
FirmwareArtifactStore.retain(params.leaseRef, params.artifactRef)
|
|
387
391
|
}
|
|
388
392
|
}
|
|
@@ -390,21 +394,13 @@ class ReactNativeRangeDownloader : HybridReactNativeRangeDownloaderSpec() {
|
|
|
390
394
|
override fun releaseFirmwareArtifactLease(
|
|
391
395
|
params: FirmwareArtifactLeaseReleaseParams,
|
|
392
396
|
): Promise<Unit> {
|
|
393
|
-
return Promise.async {
|
|
397
|
+
return Promise.async(firmwareArtifactScope) {
|
|
394
398
|
FirmwareArtifactStore.releaseLease(params.leaseRef, params.disposition)
|
|
395
399
|
}
|
|
396
400
|
}
|
|
397
401
|
|
|
398
|
-
override fun reconcileFirmwareArtifactLeases(
|
|
399
|
-
params: FirmwareArtifactLeaseReconcileParams,
|
|
400
|
-
): Promise<Unit> {
|
|
401
|
-
return Promise.async {
|
|
402
|
-
FirmwareArtifactStore.reconcileLeases(params.activeLeaseRefs)
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
402
|
override fun sweepFirmwareArtifactOrphans(): Promise<FirmwareArtifactSweepResult> {
|
|
407
|
-
return Promise.async {
|
|
403
|
+
return Promise.async(firmwareArtifactScope) {
|
|
408
404
|
val (deletedFiles, deletedBytes) = FirmwareArtifactStore.sweepOrphans()
|
|
409
405
|
FirmwareArtifactSweepResult(
|
|
410
406
|
deletedFiles = deletedFiles.toDouble(),
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package com.margelo.nitro.reactnativerangedownloader
|
|
2
|
+
|
|
3
|
+
import org.junit.Assert.assertEquals
|
|
4
|
+
import org.junit.Assert.assertThrows
|
|
5
|
+
import org.junit.Test
|
|
6
|
+
|
|
7
|
+
class FirmwareArtifactDeadlineTest {
|
|
8
|
+
@Test
|
|
9
|
+
fun defaultsToABoundedThreeMinuteDeadline() {
|
|
10
|
+
assertEquals(180.0, validateFirmwareDownloadDeadlineSeconds(null), 0.0)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@Test
|
|
14
|
+
fun preservesFractionalDeadlines() {
|
|
15
|
+
assertEquals(2.75, validateFirmwareDownloadDeadlineSeconds(2.75), 0.0)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@Test
|
|
19
|
+
fun rejectsUnboundedOrInvalidDeadlines() {
|
|
20
|
+
listOf(0.0, -1.0, Double.NaN, Double.POSITIVE_INFINITY, 86_400.1).forEach {
|
|
21
|
+
assertThrows(IllegalArgumentException::class.java) {
|
|
22
|
+
validateFirmwareDownloadDeadlineSeconds(it)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|