Persist optional Android monitoring endpoints into native configuration

This commit is contained in:
evgeny committed 2026-10-30 22:23:15 +01:00
1 parent baf58a7971
commit f6009d3070
2 files changed
+62 -7

No files matched your search

@@ -63,8 +63,6 @@ class ConfigProvider(private val context: Context) {
private val nodePrivateKey = stringPreferencesKey("node_private_key")
private val nodePublicKey = stringPreferencesKey("node_public_key")
private val nodeName = stringPreferencesKey("node_name")
private val controlPort = intPreferencesKey("control_port")
private val controlBindIp = stringPreferencesKey("control_bind_ip")
private val dbPath = stringPreferencesKey("db_path")
private val debugConsoleLevel = stringPreferencesKey("debug_console_level")
private val debugLogFile = stringPreferencesKey("debug_log_file")
@@ -191,7 +189,7 @@ class ConfigProvider(private val context: Context) {
"node.public_key" to (prefs[nodePublicKey] ?: ""),
"node.name" to (prefs[nodeName] ?: getDeviceName()),
"gui.utun_enabled" to (prefs[guiUtunEnabled]?.toString() ?: "0"),
"control.port" to (prefs[controlPort]?.toString() ?: "9999"),
"control.port" to MonitoringSettings.read(prefs).port.toString(),
"db.path" to (prefs[dbPath] ?: context.filesDir.absolutePath),
"debug.console_level" to (prefs[debugConsoleLevel] ?: "info"),
"debug.log_file" to (prefs[debugLogFile] ?: "utun.log"),
@@ -209,6 +207,21 @@ class ConfigProvider(private val context: Context) {
udpLogSettings(context.dataStore.data.first())
}.await()
suspend fun getMonitoringSettings(): MonitoringSettings = configFiles.submit("load monitoring settings") {
MonitoringSettings.read(context.dataStore.data.first())
}.await()
/** Атомарно сохраняет enabled/endpoint и обновляет INI также при остановленном ядре.
* Runtime применяет общий restart настроек при выходе с экрана. */
fun saveMonitoringSettings(settings: MonitoringSettings): Deferred<Unit> = configFiles.submit("save monitoring settings") {
context.dataStore.edit { settings.writeTo(it) }
val snapshot = configSnapshot()
val servers = loadServers(File(snapshot.directory, "utun.cfg"))
saveConfig(snapshot, servers.active, servers.inactive)
LogManager.addLog("INFO", "CFG", "Monitoring saved enabled=${settings.enabled} " +
if (settings.enabled) "endpoint=${settings.ip}:${settings.port}" else "endpoint removed")
}
fun saveUdpLogSettings(settings: UdpLogSettings): Deferred<Unit> = configFiles.submit("save UDP log settings") {
context.dataStore.edit { prefs ->
prefs[logUdpEnabled] = settings.enabled; prefs[logUdpIp] = settings.ip; prefs[logUdpPort] = settings.port
@@ -346,7 +359,7 @@ class ConfigProvider(private val context: Context) {
"node.public_key" -> keys?.first ?: prefs[nodePublicKey]
"node.name" -> prefs[nodeName] ?: getDeviceName()
"db.path" -> prefs[dbPath] ?: context.filesDir.absolutePath
"control.bind_ip" -> prefs[controlBindIp] ?: "127.0.0.1"
"control.bind_ip" -> MonitoringSettings.read(prefs).ip
"debug.console_level" -> prefs[debugConsoleLevel] ?: "info"
"debug.log_file" -> prefs[debugLogFile] ?: "utun.log"
"debug.categories" -> prefs[debugCategories] ?: ""
@@ -361,7 +374,8 @@ class ConfigProvider(private val context: Context) {
private fun intValue(key: String, prefs: Preferences): Int =
when (key) {
"gui.utun_enabled" -> prefs[guiUtunEnabled] ?: 0
"control.port" -> prefs[controlPort] ?: 9999
"control.enabled" -> if (MonitoringSettings.read(prefs).enabled) 1 else 0
"control.port" -> MonitoringSettings.read(prefs).port
"log_udp.enabled" -> if (prefs[logUdpEnabled] ?: false) 1 else 0
"log_udp.port" -> prefs[logUdpPort] ?: UdpLogSettings.DEFAULT_PORT
"chat.storage_autoload" -> prefs[chatStorageAutoload] ?: 1
@@ -407,8 +421,6 @@ class ConfigProvider(private val context: Context) {
"node.private_key" -> prefs[nodePrivateKey] = value
"node.public_key" -> prefs[nodePublicKey] = value
"node.name" -> prefs[nodeName] = value
"control.port" -> prefs[controlPort] = value.toIntOrNull() ?: 9999
"control.bind_ip" -> prefs[controlBindIp] = value
"db.path" -> prefs[dbPath] = value
"debug.console_level" -> prefs[debugConsoleLevel] = value
"debug.log_file" -> prefs[debugLogFile] = value
@@ -889,6 +901,7 @@ class ConfigProvider(private val context: Context) {
appendLine()
for (srv in servers) appendServerSection(this, srv, false)
for (srv in commented) appendServerSection(this, srv, true)
MonitoringSettings.read(prefs).appendConfig(this)
appendLine("[allowed_keys]")
appendLine("allow_all=yes")
appendLine()
@@ -0,0 +1,42 @@
package com.utun.chat.data
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.MutablePreferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
/** TCP-монитор ядра: только числовой IPv4 (ACL control server не поддерживает IPv6).
* Выключение удаляет endpoint из DataStore; значения по умолчанию — только для следующего включения. */
data class MonitoringSettings(val enabled: Boolean = false, val ip: String = "127.0.0.1", val port: Int = 9999) {
val valid: Boolean get() = port in 1..65535 && ip.split('.').let { parts ->
parts.size == 4 && parts.all { part -> part.toIntOrNull()?.let { it in 0..255 && part == it.toString() } == true }
}
fun writeTo(prefs: MutablePreferences) {
require(!enabled || valid) { "Monitoring requires a numeric IPv4 address and port 1..65535" }
prefs[enabledKey] = enabled
if (enabled) { prefs[ipKey] = ip; prefs[portKey] = port }
else { prefs.remove(ipKey); prefs.remove(portKey) }
}
/** Слушаем только выбранный IP; при включении разрешаем TCP-клиентам подключаться к этому endpoint. */
fun appendConfig(config: StringBuilder) {
if (!enabled) return
require(valid) { "Invalid monitoring endpoint" }
config.appendLine("[control]")
config.appendLine("ip=$ip")
config.appendLine("port=$port")
config.appendLine("allow=0.0.0.0/0")
config.appendLine()
}
companion object {
private val enabledKey = booleanPreferencesKey("control_enabled")
private val ipKey = stringPreferencesKey("control_bind_ip")
private val portKey = intPreferencesKey("control_port")
fun read(prefs: Preferences): MonitoringSettings = if (prefs[enabledKey] == true)
MonitoringSettings(true, prefs[ipKey] ?: "127.0.0.1", prefs[portKey] ?: 9999) else MonitoringSettings()
}
}