Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion native-modules/native-logger/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-native-logger",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-native-logger",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-aes-crypto/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-aes-crypto",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-aes-crypto",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
5 changes: 5 additions & 0 deletions native-modules/react-native-app-update/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ dependencies {
// own GPG public key + BouncyCastle verify implementation.
implementation project(":onekeyfe_react-native-bundle-crypto")

// Shared 8-range concurrent downloader (segment-file model). app-update no
// longer carries its own copy of ConcurrentRangeDownloader — it consumes the
// single shared implementation here, same as react-native-bundle-update.
implementation project(":onekeyfe_react-native-range-downloader")

implementation "com.squareup.okhttp3:okhttp:4.12.0"
implementation "com.squareup.okio:okio:3.9.0"
implementation "androidx.core:core-ktx:1.15.0"
Expand Down

This file was deleted.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- Primary APK download location (filesDir/apks). MUST match getApkDownloadDir(). -->
<files-path name="apks_files" path="apks/" />
<!-- Legacy location: an APK already downloaded into cacheDir/apks by an older
build can still be exposed to the installer during the transition. -->
<cache-path name="apks" path="apks/" />
</paths>
2 changes: 1 addition & 1 deletion native-modules/react-native-app-update/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-app-update",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-app-update",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-async-storage/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-async-storage",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-async-storage",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-background-thread/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-background-thread",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-background-thread",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-bundle-crypto/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-bundle-crypto",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-bundle-crypto",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
Expand Down Expand Up @@ -1083,6 +1084,12 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {

companion object {
private const val PREFS_NAME = "BundleUpdatePrefs"

// Number of concurrent segment files (`<partial>.seg0..seg{N-1}`) the
// ConcurrentRangeDownloader produces. MUST equal the segmentCount passed
// to ConcurrentRangeDownloader (currently the default 8). Every place
// that cleans up `.segN` files must iterate `0 until CONCURRENT_SEGMENT_COUNT`.
private const val CONCURRENT_SEGMENT_COUNT = 8
}

private val listeners = CopyOnWriteArrayList<BundleListener>()
Expand Down Expand Up @@ -1234,9 +1241,12 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
if (verifyBundleSHA256(filePath, sha256)) {
OneKeyLog.info("BundleUpdate", "downloadBundle: existing file SHA256 valid, skipping download")
// Final file is authoritative — drop any stale concurrent
// partial/manifest left by an earlier interrupted attempt.
// partial + segment files left by an earlier interrupted
// attempt. (".progress" is a legacy manifest from the old
// pre-allocated model; deleting it is a harmless no-op now.)
if (partialFile.exists()) partialFile.delete()
File("$partialFilePath.progress").delete()
for (i in 0 until CONCURRENT_SEGMENT_COUNT) File("$partialFilePath.seg$i").delete()
// Keep isDownloading held across the skip delay below. Clearing
// it before the sleep opens a ~1s window where a second
// downloadBundle could pass the getAndSet guard and run
Expand All @@ -1248,8 +1258,11 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
} else {
OneKeyLog.warn("BundleUpdate", "downloadBundle: existing file SHA256 mismatch, re-downloading")
downloadedFile.delete()
// Stale completed file invalidates any partial too.
// Stale completed file invalidates any partial too — including
// the concurrent segment files, otherwise the next resume would
// pick up bytes belonging to the rejected build.
if (partialFile.exists()) partialFile.delete()
for (i in 0 until CONCURRENT_SEGMENT_COUNT) File("$partialFilePath.seg$i").delete()
}
}

Expand All @@ -1261,16 +1274,22 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
// downloader keeps its partial + manifest for resume).
sendEvent("update/start")
run {
var concurrentProgress = -1
// onProgress is invoked concurrently by all 8 worker threads, so
// a plain `var` read-compare-write races (duplicate/out-of-order
// progress events). Use AtomicInteger + CAS: only the thread that
// wins the compareAndSet to a strictly higher value emits, which
// also keeps progress monotonic. (Worst case a race only affects
// progress eventing, never file bytes.)
val concurrentProgress = AtomicInteger(-1)
val concurrentOutcome = ConcurrentRangeDownloader(
httpClient = httpClient,
log = { msg -> OneKeyLog.info("BundleUpdate", msg) },
).download(downloadUrl, partialFilePath) { transferred, total ->
if (total > 0) {
val p = ((transferred * 100) / total).toInt().coerceIn(0, 100)
if (p != concurrentProgress) {
val prev = concurrentProgress.get()
if (p > prev && concurrentProgress.compareAndSet(prev, p)) {
sendEvent("update/downloading", progress = p)
concurrentProgress = p
}
}
}
Expand Down Expand Up @@ -1304,7 +1323,14 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
// before discarding so we save a full re-download.
val expectedSize = if (params.fileSize > 0) params.fileSize.toLong() else 0L
var partialBytes = 0L
if (partialFile.exists()) {
// If any concurrent `.segN` files survive, the `.partial` here is the
// concurrent committed cursor, not a single-stream partial. Defer to
// the concurrent downloader (which already ran above and may resume on
// a later attempt) and skip size-based promote/discard, which would
// otherwise misjudge a bare `.partial` when the concurrent path
// returned FALLBACK but left `.segN` residue. Mirrors app-update.
val hasConcurrentSegments = (0 until CONCURRENT_SEGMENT_COUNT).any { File("$partialFilePath.seg$it").exists() }
if (partialFile.exists() && !hasConcurrentSegments) {
val partialSize = partialFile.length()
when {
expectedSize > 0 && partialSize == expectedSize -> {
Expand All @@ -1325,6 +1351,7 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
expectedSize > 0 && partialSize > expectedSize -> {
OneKeyLog.warn("BundleUpdate", "downloadBundle: stale partial (>expected), discarding: $partialSize/$expectedSize")
partialFile.delete()
for (i in 0 until CONCURRENT_SEGMENT_COUNT) File("$partialFilePath.seg$i").delete()
}
partialSize > 0 -> {
partialBytes = partialSize
Expand Down Expand Up @@ -1369,14 +1396,15 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
}
OneKeyLog.warn("BundleUpdate", "downloadBundle: HTTP 416 (range not satisfiable), discarding partial and failing this attempt")
if (partialFile.exists()) partialFile.delete()
for (i in 0 until CONCURRENT_SEGMENT_COUNT) File("$partialFilePath.seg$i").delete()
// Don't pre-emit update/error here; the outer catch is the
// single source of error events. sanitizeErrorMessageForEvent
// recognizes "HTTP " prefix and forwards this string verbatim.
throw Exception("HTTP 416 (range not satisfiable)")
}

val expectsResume = partialBytes > 0
val isPartialResponse = response.code == 206
var isPartialResponse = response.code == 206

if (!response.isSuccessful || (response.code != 200 && response.code != 206)) {
OneKeyLog.error("BundleUpdate", "downloadBundle: HTTP error, statusCode=${response.code}")
Expand All @@ -1390,9 +1418,36 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
if (expectsResume && !isPartialResponse) {
OneKeyLog.warn("BundleUpdate", "downloadBundle: requested Range but server returned 200, restarting from scratch")
if (partialFile.exists()) partialFile.delete()
for (i in 0 until CONCURRENT_SEGMENT_COUNT) File("$partialFilePath.seg$i").delete()
partialBytes = 0L
}

// On a 206 the server's `Content-Range` start MUST equal the offset
// we asked to resume from (`partialBytes`). A misconfigured server or
// proxy can return a 206 whose range starts somewhere else; appending
// that slice onto our `.partial` would splice mismatched bytes and the
// final SHA256 would fail only after a full download. Guard here: if
// the start is missing or != partialBytes, drop the partial+segments
// and abort this attempt. We must NOT reuse this body as a 200-style
// full rewrite: a mismatched 206 body is still a range slice, not the
// whole file, so writing it would produce a corrupt bundle. Close the
// response and throw a retryable error — with partial+segN already
// gone, the next attempt naturally restarts from 0.
if (isPartialResponse && partialBytes > 0) {
val contentRangeStart = response.header("Content-Range")
?.let { Regex("""bytes\s+(\d+)-\d+/\d+""").find(it)?.groupValues?.getOrNull(1)?.toLongOrNull() }
if (contentRangeStart == null || contentRangeStart != partialBytes) {
OneKeyLog.warn(
"BundleUpdate",
"downloadBundle: 206 Content-Range start=$contentRangeStart != partialBytes=$partialBytes, discarding partial and aborting attempt"
)
if (partialFile.exists()) partialFile.delete()
for (i in 0 until CONCURRENT_SEGMENT_COUNT) File("$partialFilePath.seg$i").delete()
response.close()
throw java.io.IOException("206 Content-Range start mismatch (got=$contentRangeStart, want=$partialBytes); discarded partial, retry from scratch")
}
}

// Close the response before throwing on a null body — OkHttp
// holds connection resources on the response wrapper itself,
// and `throw` here exits the function before any byteStream()
Expand Down Expand Up @@ -1844,8 +1899,12 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
downloadDir.listFiles()?.forEach { file ->
val name = file.name
// Strip the trailing extension chain to recover the
// "{appV}-{bV}" stem (e.g. "6.3.0-123.zip.partial").
// "{appV}-{bV}" stem (e.g. "6.3.0-123.zip.partial", or a
// concurrent segment file "6.3.0-123.zip.partial.seg3").
var stem = name
// Concurrent segment files end in ".segN" — peel that off
// first so the rest of the chain strips as usual.
stem = stem.replace(Regex("""\.seg\d+$"""), "")
for (suffix in listOf(".resume", ".progress", ".partial", ".zip")) {
if (stem.endsWith(suffix)) {
stem = stem.substring(0, stem.length - suffix.length)
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-bundle-update/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-bundle-update",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-bundle-update",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-check-biometric-auth-changed",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-check-biometric-auth-changed",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-cloud-fs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-cloud-fs",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-cloud-fs TurboModule for OneKey",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-cloud-kit-module/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-cloud-kit-module",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-cloud-kit-module",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-device-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-device-utils",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-device-utils",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-dns-lookup/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-dns-lookup",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-dns-lookup",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-get-random-values/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-get-random-values",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-get-random-values",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-keychain-module/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-keychain-module",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-keychain-module",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-lite-card/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-lite-card",
"version": "3.0.65",
"version": "3.0.66",
"description": "lite card",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-network-info/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-network-info",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-network-info",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-pbkdf2/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-pbkdf2",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-pbkdf2",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-perf-memory/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-perf-memory",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-perf-memory",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-perf-stats/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-perf-stats",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-perf-stats",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion native-modules/react-native-ping/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onekeyfe/react-native-ping",
"version": "3.0.65",
"version": "3.0.66",
"description": "react-native-ping TurboModule for OneKey",
"main": "./lib/module/index.js",
"types": "./lib/typescript/src/index.d.ts",
Expand Down
Loading