pulse-updates 1.0.5 → 1.0.6
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.
|
@@ -99,6 +99,10 @@ class PulseController private constructor() {
|
|
|
99
99
|
private var embeddedManifest: EmbeddedManifest? = null
|
|
100
100
|
private val executor = Executors.newSingleThreadExecutor()
|
|
101
101
|
|
|
102
|
+
// Cached manifest from last check (to avoid duplicate requests in fetch)
|
|
103
|
+
// Only valid for the immediate check->fetch sequence, cleared on use or new check
|
|
104
|
+
private var lastCheckManifest: ManifestModel? = null
|
|
105
|
+
|
|
102
106
|
// Embedded asset hashes set for download optimization
|
|
103
107
|
internal val embeddedAssetHashes: Set<String>
|
|
104
108
|
get() = embeddedManifest?.assets
|
|
@@ -526,11 +530,26 @@ class PulseController private constructor() {
|
|
|
526
530
|
}
|
|
527
531
|
|
|
528
532
|
executor.execute {
|
|
529
|
-
|
|
533
|
+
// Clear any previous cached manifest before new check
|
|
534
|
+
lastCheckManifest = null
|
|
535
|
+
|
|
536
|
+
PulseRemoteLoader.checkForUpdate(cfg, launchedUpdate?.updateId) { result ->
|
|
537
|
+
// Cache the manifest if update is available (for use by fetchUpdate)
|
|
538
|
+
result.fold(
|
|
539
|
+
onSuccess = { checkResult ->
|
|
540
|
+
if (checkResult.isAvailable && checkResult.manifest != null) {
|
|
541
|
+
lastCheckManifest = checkResult.manifest
|
|
542
|
+
pulseLog(TAG, "checkForUpdate: cached manifest for fetch")
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
onFailure = { }
|
|
546
|
+
)
|
|
547
|
+
callback(result)
|
|
548
|
+
}
|
|
530
549
|
}
|
|
531
550
|
}
|
|
532
551
|
|
|
533
|
-
fun fetchUpdate(callback: (Result<FetchResult>) -> Unit) {
|
|
552
|
+
fun fetchUpdate(cachedManifest: ManifestModel? = null, callback: (Result<FetchResult>) -> Unit) {
|
|
534
553
|
val cfg = config
|
|
535
554
|
val ctx = context
|
|
536
555
|
val dir = directory
|
|
@@ -545,8 +564,18 @@ class PulseController private constructor() {
|
|
|
545
564
|
return
|
|
546
565
|
}
|
|
547
566
|
|
|
567
|
+
// Use cached manifest from recent check if available
|
|
568
|
+
var manifestToUse = cachedManifest
|
|
569
|
+
if (manifestToUse == null && lastCheckManifest != null) {
|
|
570
|
+
pulseLog(TAG, "fetchUpdate: using cached manifest from recent check")
|
|
571
|
+
manifestToUse = lastCheckManifest
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Clear the cache after using it
|
|
575
|
+
lastCheckManifest = null
|
|
576
|
+
|
|
548
577
|
executor.execute {
|
|
549
|
-
PulseRemoteLoader.fetchUpdate(cfg, database, dir, callback)
|
|
578
|
+
PulseRemoteLoader.fetchUpdate(cfg, database, dir, manifestToUse, callback)
|
|
550
579
|
}
|
|
551
580
|
}
|
|
552
581
|
|
|
@@ -1141,8 +1170,22 @@ object PulseRemoteLoader {
|
|
|
1141
1170
|
config: PulseUpdatesConfig,
|
|
1142
1171
|
database: PulseDatabase?,
|
|
1143
1172
|
directory: File,
|
|
1173
|
+
cachedManifest: ManifestModel? = null,
|
|
1144
1174
|
callback: (Result<FetchResult>) -> Unit
|
|
1145
1175
|
) {
|
|
1176
|
+
// If we already have a manifest from a previous check, use it directly
|
|
1177
|
+
if (cachedManifest != null) {
|
|
1178
|
+
pulseLog(TAG, "fetchUpdate: using cached manifest, skipping check")
|
|
1179
|
+
downloadUpdate(cachedManifest, config, database, directory) { downloadResult ->
|
|
1180
|
+
downloadResult.fold(
|
|
1181
|
+
onSuccess = { callback(Result.success(FetchResult(isNew = true, manifest = cachedManifest))) },
|
|
1182
|
+
onFailure = { callback(Result.failure(it)) }
|
|
1183
|
+
)
|
|
1184
|
+
}
|
|
1185
|
+
return
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// No cached manifest, need to check first
|
|
1146
1189
|
checkForUpdate(config, PulseController.getInstance().launchedUpdate?.updateId) { result ->
|
|
1147
1190
|
result.fold(
|
|
1148
1191
|
onSuccess = { checkResult ->
|
|
@@ -1265,6 +1308,10 @@ object PulseRemoteLoader {
|
|
|
1265
1308
|
|
|
1266
1309
|
// Download assets and link them to the update
|
|
1267
1310
|
val embeddedHashes = PulseController.getInstance().embeddedAssetHashes
|
|
1311
|
+
pulseLog(TAG, "downloadUpdate: embeddedHashes count=${embeddedHashes.size}")
|
|
1312
|
+
if (embeddedHashes.isNotEmpty()) {
|
|
1313
|
+
pulseLog(TAG, "downloadUpdate: first few embedded hashes: ${embeddedHashes.take(3).map { it.take(16) }}")
|
|
1314
|
+
}
|
|
1268
1315
|
|
|
1269
1316
|
for (asset in manifest.assets) {
|
|
1270
1317
|
val assetHash = asset.hash.lowercase()
|
|
@@ -473,8 +473,8 @@ struct PulseEmbeddedAsset {
|
|
|
473
473
|
self.hash = hash
|
|
474
474
|
self.key = json["key"] as? String
|
|
475
475
|
self.type = json["type"] as? String ?? json["contentType"] as? String
|
|
476
|
-
self.nsBundleDir = json["nsBundleDir"] as? String
|
|
477
|
-
self.nsBundleFilename = json["nsBundleFilename"] as? String
|
|
476
|
+
self.nsBundleDir = json["mainBundleDir"] as? String ?? json["nsBundleDir"] as? String
|
|
477
|
+
self.nsBundleFilename = json["mainBundleFilename"] as? String ?? json["nsBundleFilename"] as? String
|
|
478
478
|
}
|
|
479
479
|
}
|
|
480
480
|
|
|
@@ -66,6 +66,10 @@ public final class PulseController {
|
|
|
66
66
|
internal var embeddedAssetHashes: [String: URL] = [:]
|
|
67
67
|
private var embeddedBundleHash: String?
|
|
68
68
|
|
|
69
|
+
// Cached manifest from last check (to avoid duplicate requests in fetch)
|
|
70
|
+
// Only valid for the immediate check->fetch sequence, cleared on use or new check
|
|
71
|
+
private var lastCheckManifest: PulseManifest?
|
|
72
|
+
|
|
69
73
|
// MARK: - Native Config (from Info.plist, like expo-updates)
|
|
70
74
|
|
|
71
75
|
/// Load config from Info.plist (called before JS starts)
|
|
@@ -475,15 +479,24 @@ public final class PulseController {
|
|
|
475
479
|
return
|
|
476
480
|
}
|
|
477
481
|
|
|
482
|
+
// Clear any previous cached manifest before new check
|
|
483
|
+
lastCheckManifest = nil
|
|
484
|
+
|
|
478
485
|
PulseRemoteLoader.checkForUpdate(
|
|
479
486
|
config: config,
|
|
480
|
-
currentUpdateId: launchedUpdate?.updateId
|
|
481
|
-
|
|
482
|
-
|
|
487
|
+
currentUpdateId: launchedUpdate?.updateId
|
|
488
|
+
) { [weak self] result in
|
|
489
|
+
// Cache the manifest for subsequent fetchUpdate call
|
|
490
|
+
if case .success(let checkResult) = result, checkResult.isAvailable {
|
|
491
|
+
self?.lastCheckManifest = checkResult.manifest
|
|
492
|
+
}
|
|
493
|
+
completion(result)
|
|
494
|
+
}
|
|
483
495
|
}
|
|
484
496
|
|
|
485
497
|
/// Fetch and download an update
|
|
486
|
-
|
|
498
|
+
/// - Parameter cachedManifest: Optional manifest from a previous checkForUpdate call to avoid duplicate request
|
|
499
|
+
public func fetchUpdate(cachedManifest: PulseManifest? = nil, completion: @escaping (Result<PulseFetchResult, Error>) -> Void) {
|
|
487
500
|
guard let config = config else {
|
|
488
501
|
completion(.failure(PulseUpdatesError.notConfigured))
|
|
489
502
|
return
|
|
@@ -494,10 +507,21 @@ public final class PulseController {
|
|
|
494
507
|
return
|
|
495
508
|
}
|
|
496
509
|
|
|
510
|
+
// Use cached manifest from recent checkForUpdate if available
|
|
511
|
+
var manifestToUse = cachedManifest
|
|
512
|
+
if manifestToUse == nil, let cached = lastCheckManifest {
|
|
513
|
+
pulseLog("fetchUpdate: using cached manifest from recent check")
|
|
514
|
+
manifestToUse = cached
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Clear cache after use
|
|
518
|
+
lastCheckManifest = nil
|
|
519
|
+
|
|
497
520
|
PulseRemoteLoader.fetchUpdate(
|
|
498
521
|
config: config,
|
|
499
522
|
database: database,
|
|
500
523
|
directory: directory,
|
|
524
|
+
cachedManifest: manifestToUse,
|
|
501
525
|
completion: completion
|
|
502
526
|
)
|
|
503
527
|
}
|
|
@@ -594,7 +618,7 @@ public final class PulseController {
|
|
|
594
618
|
}
|
|
595
619
|
}
|
|
596
620
|
|
|
597
|
-
pulseLog("Loaded embedded manifest: \(embeddedManifest?.updateId ?? "unknown")")
|
|
621
|
+
pulseLog("Loaded embedded manifest: \(embeddedManifest?.updateId ?? "unknown"), embeddedAssetHashes count: \(embeddedAssetHashes.count)")
|
|
598
622
|
}
|
|
599
623
|
|
|
600
624
|
private func seedEmbeddedUpdateIfNeeded() {
|
|
@@ -931,9 +955,24 @@ final class PulseRemoteLoader {
|
|
|
931
955
|
config: PulseUpdatesConfig,
|
|
932
956
|
database: PulseDatabase?,
|
|
933
957
|
directory: URL,
|
|
958
|
+
cachedManifest: PulseManifest? = nil,
|
|
934
959
|
completion: @escaping (Result<PulseFetchResult, Error>) -> Void
|
|
935
960
|
) {
|
|
936
|
-
//
|
|
961
|
+
// If we already have a manifest from a previous check, use it directly
|
|
962
|
+
if let manifest = cachedManifest {
|
|
963
|
+
pulseLog("fetchUpdate: using cached manifest, skipping check")
|
|
964
|
+
downloadUpdate(manifest: manifest, config: config, database: database, directory: directory) { downloadResult in
|
|
965
|
+
switch downloadResult {
|
|
966
|
+
case .failure(let error):
|
|
967
|
+
completion(.failure(error))
|
|
968
|
+
case .success:
|
|
969
|
+
completion(.success(PulseFetchResult(isNew: true, manifest: manifest)))
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
return
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// No cached manifest, need to check first
|
|
937
976
|
checkForUpdate(config: config, currentUpdateId: PulseController.shared.launchedUpdate?.updateId) { result in
|
|
938
977
|
switch result {
|
|
939
978
|
case .failure(let error):
|
|
@@ -1123,6 +1162,12 @@ final class PulseRemoteLoader {
|
|
|
1123
1162
|
let group = DispatchGroup()
|
|
1124
1163
|
var downloadError: Error?
|
|
1125
1164
|
|
|
1165
|
+
let embeddedHashes = PulseController.shared.embeddedAssetHashes
|
|
1166
|
+
pulseLog("downloadAssets: embeddedAssetHashes count=\(embeddedHashes.count)")
|
|
1167
|
+
if !embeddedHashes.isEmpty {
|
|
1168
|
+
pulseLog("downloadAssets: first few embedded hashes: \(Array(embeddedHashes.keys.prefix(3)).map { String($0.prefix(16)) })")
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1126
1171
|
for asset in assets {
|
|
1127
1172
|
group.enter()
|
|
1128
1173
|
|