refactor: lazy-load Namecoin services on Desktop (not kept in memory from start)
Move Namecoin service initialization from App-level (eager, on every startup) to inside the LoggedIn branch (only created when user logs in and screens that use Namecoin are reachable). Matches the Android lazy pattern in AppModules. Also deduplicate NamecoinSettings: Android module now uses a typealias to the commons module version, matching the original PR intent.
This commit is contained in:
+1
-78
@@ -20,81 +20,4 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.service.namecoin
|
package com.vitorpamplona.amethyst.service.namecoin
|
||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
typealias NamecoinSettings = com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.namecoin.NamecoinSettings
|
||||||
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.ElectrumxServer
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Immutable data class representing the current Namecoin resolution config.
|
|
||||||
*
|
|
||||||
* When custom servers are configured, they are used EXCLUSIVELY and the
|
|
||||||
* hardcoded defaults are ignored. This gives privacy-conscious users full
|
|
||||||
* control over which ElectrumX servers observe their name lookups.
|
|
||||||
*/
|
|
||||||
@Serializable
|
|
||||||
@Stable
|
|
||||||
data class NamecoinSettings(
|
|
||||||
/** Whether Namecoin resolution is enabled at all. */
|
|
||||||
val enabled: Boolean = true,
|
|
||||||
/**
|
|
||||||
* Custom ElectrumX servers. When non-empty, these replace the defaults.
|
|
||||||
*
|
|
||||||
* Each entry is `host:port` (TLS) or `host:port:tcp` (plaintext).
|
|
||||||
*/
|
|
||||||
val customServers: List<String> = emptyList(),
|
|
||||||
) {
|
|
||||||
/** True when the user has configured at least one custom server. */
|
|
||||||
val hasCustomServers: Boolean get() = customServers.isNotEmpty()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert to [ElectrumxServer] instances used by the resolver.
|
|
||||||
* Returns `null` when no valid custom servers are configured (use defaults).
|
|
||||||
*/
|
|
||||||
fun toElectrumxServers(): List<ElectrumxServer>? {
|
|
||||||
if (customServers.isEmpty()) return null
|
|
||||||
return customServers
|
|
||||||
.mapNotNull { parseServerString(it) }
|
|
||||||
.ifEmpty { null }
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val DEFAULT = NamecoinSettings()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse `host:port` or `host:port:tcp` into an [ElectrumxServer].
|
|
||||||
*
|
|
||||||
* TLS is the default protocol. Append `:tcp` for plaintext
|
|
||||||
* (useful for `.onion` addresses and local servers).
|
|
||||||
*
|
|
||||||
* `.onion` addresses automatically get `usePinnedTrustStore = true`
|
|
||||||
* since certificate verification is meaningless over Tor.
|
|
||||||
*/
|
|
||||||
fun parseServerString(s: String): ElectrumxServer? {
|
|
||||||
val parts = s.trim().split(":")
|
|
||||||
if (parts.size < 2) return null
|
|
||||||
val host = parts[0].trim()
|
|
||||||
val port = parts[1].trim().toIntOrNull() ?: return null
|
|
||||||
if (host.isEmpty() || port <= 0 || port > 65535) return null
|
|
||||||
val useSsl = parts.getOrNull(2)?.trim()?.lowercase() != "tcp"
|
|
||||||
val isOnion = host.endsWith(".onion")
|
|
||||||
// All custom servers use the pinned trust store. ElectrumX
|
|
||||||
// servers almost universally use self-signed certs, so we
|
|
||||||
// route them through our pinned SSLSocketFactory (hardcoded
|
|
||||||
// defaults + TOFU-pinned certs + system CAs).
|
|
||||||
return ElectrumxServer(
|
|
||||||
host = host,
|
|
||||||
port = port,
|
|
||||||
useSsl = useSsl,
|
|
||||||
usePinnedTrustStore = true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format an [ElectrumxServer] back to the `host:port[:tcp]` string form.
|
|
||||||
*/
|
|
||||||
fun formatServerString(server: ElectrumxServer): String {
|
|
||||||
val base = "${server.host}:${server.port}"
|
|
||||||
return if (server.useSsl) base else "$base:tcp"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -719,10 +719,6 @@ fun App(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val localCache = remember { DesktopLocalCache() }
|
val localCache = remember { DesktopLocalCache() }
|
||||||
val namecoinPreferences = remember { DesktopNamecoinPreferences() }
|
|
||||||
val namecoinService = remember {
|
|
||||||
DesktopNamecoinNameService(preferencesProvider = { namecoinPreferences.current })
|
|
||||||
}
|
|
||||||
val accountState by accountManager.accountState.collectAsState()
|
val accountState by accountManager.accountState.collectAsState()
|
||||||
val scope = remember { CoroutineScope(SupervisorJob() + Dispatchers.Main) }
|
val scope = remember { CoroutineScope(SupervisorJob() + Dispatchers.Main) }
|
||||||
|
|
||||||
@@ -900,10 +896,6 @@ fun App(
|
|||||||
ProvideMaterialSymbols(
|
ProvideMaterialSymbols(
|
||||||
weight = com.vitorpamplona.amethyst.desktop.platform.PlatformIconWeight.current,
|
weight = com.vitorpamplona.amethyst.desktop.platform.PlatformIconWeight.current,
|
||||||
) {
|
) {
|
||||||
CompositionLocalProvider(
|
|
||||||
LocalNamecoinPreferences provides namecoinPreferences,
|
|
||||||
LocalNamecoinService provides namecoinService,
|
|
||||||
) {
|
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = MaterialTheme.colorScheme.background,
|
color = MaterialTheme.colorScheme.background,
|
||||||
@@ -1068,7 +1060,6 @@ fun App(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end CompositionLocalProvider
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user