chore: review-cleanup fleet (audit + fix + hardening) (#5158)

This commit is contained in:
James Rich 2026-04-16 19:02:59 -05:00 committed by GitHub
parent 872c566ef1
commit 17e69c6d4c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
68 changed files with 784 additions and 459 deletions

View file

@ -19,19 +19,31 @@ package org.meshtastic.core.prefs
import kotlinx.atomicfu.AtomicRef
import kotlinx.collections.immutable.PersistentMap
internal inline fun <K, V> cachedFlow(cache: AtomicRef<PersistentMap<K, V>>, key: K, build: () -> V): V {
var resolved = cache.value[key]
if (resolved == null) {
val newValue = build()
while (resolved == null) {
val current = cache.value
val currentValue = current[key]
if (currentValue != null) {
resolved = currentValue
} else if (cache.compareAndSet(current, current.put(key, newValue))) {
resolved = newValue
}
/**
* Look up [key] in [cache]; if absent, construct a value via [build] and insert it atomically.
*
* [build] is wrapped in a [Lazy] before being published to [cache], so concurrent first-access of the same key never
* invokes [build] more than once only the winner of the CAS has its [Lazy] evaluated, and all readers share that same
* result. This matters when [build] eagerly launches a coroutine (e.g. `Flow.stateIn(scope, Eagerly, )`): the naive
* approach would leak the losing coroutine into a never-cancelled scope.
*/
@Suppress("ReturnCount")
internal inline fun <K, V> cachedFlow(
cache: AtomicRef<PersistentMap<K, Lazy<V>>>,
key: K,
crossinline build: () -> V,
): V {
cache.value[key]?.let {
return it.value
}
val newLazy = lazy(LazyThreadSafetyMode.SYNCHRONIZED) { build() }
while (true) {
val current = cache.value
current[key]?.let {
return it.value
}
if (cache.compareAndSet(current, current.put(key, newLazy))) {
return newLazy.value
}
}
return checkNotNull(resolved)
}

View file

@ -42,7 +42,7 @@ class MapConsentPrefsImpl(
) : MapConsentPrefs {
private val scope = CoroutineScope(SupervisorJob() + dispatchers.default)
private val consentFlows = atomic(persistentMapOf<Int?, StateFlow<Boolean>>())
private val consentFlows = atomic(persistentMapOf<Int?, Lazy<StateFlow<Boolean>>>())
override fun shouldReportLocation(nodeNum: Int?): StateFlow<Boolean> = cachedFlow(consentFlows, nodeNum) {
val key = booleanPreferencesKey(nodeNum.toString())

View file

@ -18,7 +18,6 @@ package org.meshtastic.core.prefs.mesh
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
@ -45,8 +44,7 @@ class MeshPrefsImpl(
) : MeshPrefs {
private val scope = CoroutineScope(SupervisorJob() + dispatchers.default)
private val locationFlows = atomic(persistentMapOf<Int?, StateFlow<Boolean>>())
private val storeForwardFlows = atomic(persistentMapOf<String?, StateFlow<Int>>())
private val storeForwardFlows = atomic(persistentMapOf<String?, Lazy<StateFlow<Int>>>())
override val deviceAddress: StateFlow<String?> =
dataStore.data
@ -65,15 +63,6 @@ class MeshPrefsImpl(
}
}
override fun shouldProvideNodeLocation(nodeNum: Int?): StateFlow<Boolean> = cachedFlow(locationFlows, nodeNum) {
val key = booleanPreferencesKey(provideLocationKey(nodeNum))
dataStore.data.map { it[key] ?: false }.stateIn(scope, SharingStarted.Eagerly, false)
}
override fun setShouldProvideNodeLocation(nodeNum: Int?, provide: Boolean) {
scope.launch { dataStore.edit { prefs -> prefs[booleanPreferencesKey(provideLocationKey(nodeNum))] = provide } }
}
override fun getStoreForwardLastRequest(address: String?): StateFlow<Int> = cachedFlow(storeForwardFlows, address) {
val key = intPreferencesKey(storeForwardKey(address))
dataStore.data.map { it[key] ?: 0 }.stateIn(scope, SharingStarted.Eagerly, 0)
@ -92,8 +81,6 @@ class MeshPrefsImpl(
}
}
private fun provideLocationKey(nodeNum: Int?) = "provide-location-$nodeNum"
private fun storeForwardKey(address: String?): String = "store-forward-last-request-${normalizeAddress(address)}"
companion object {

View file

@ -46,7 +46,7 @@ class UiPrefsImpl(
private val scope = CoroutineScope(SupervisorJob() + dispatchers.default)
// Maps nodeNum to a flow for the for the "provide-location-nodeNum" pref
private val provideNodeLocationFlows = atomic(persistentMapOf<Int, StateFlow<Boolean>>())
private val provideNodeLocationFlows = atomic(persistentMapOf<Int, Lazy<StateFlow<Boolean>>>())
override val appIntroCompleted: StateFlow<Boolean> =
dataStore.data.map { it[KEY_APP_INTRO_COMPLETED] ?: false }.stateIn(scope, SharingStarted.Eagerly, false)