fix(android): consume local socket snapshots on core events

This commit is contained in:
evgeny committed 2026-10-17 22:07:58 +02:00
1 parent c69f8d8975
commit 1dfe349eb8
3 files changed
+28 -12

No files matched your search

@@ -123,8 +123,19 @@ data class MemberLinks(val connected: Boolean = false, val initialized: Boolean
data class LocalSocketState(
val sockId: Int = 0, val ifName: String = "", val bindIp: String = "",
val port: Int = 0, val protocol: String = "", val state: Int = 0,
val linksUp: Int = 0, val linksDown: Int = 0
val linksUp: Int = 0, val linksDown: Int = 0,
val natMapping: Int = 0, val natInbound: Int = 0, val natSource: Int = 0,
val externalIp: String = "", val externalPort: Int = 0
) {
val natLabelRes: Int get() = when {
natSource == 0 -> R.string.socket_nat_unmeasured
natMapping == 1 -> R.string.socket_no_nat
natMapping == 2 && natInbound == 1 -> R.string.socket_eim_open
natMapping == 2 && natInbound == 2 -> R.string.socket_eim_filtered
natMapping == 2 -> R.string.address_nat_eim_unverified
natMapping == 3 -> R.string.address_nat_dependent
else -> R.string.address_nat_unknown
}
val stateLabel: String get() = AppLanguage.text(when (state) {
2 -> R.string.connection_up; 1 -> R.string.connection_connecting; else -> R.string.connection_down
})
@@ -543,9 +554,9 @@ class ChatRepository {
return MemberLinks()
}
fun getLocalSockets(): List<LocalSocketState> {
fun parseLocalSockets(json: String): List<LocalSocketState> {
try {
val arr = JSONArray(NativeLib.getLocalSockets())
val arr = JSONArray(json)
val list = mutableListOf<LocalSocketState>()
for (i in 0 until arr.length()) {
val obj = arr.getJSONObject(i)
@@ -559,12 +570,17 @@ class ChatRepository {
protocol = obj.optString("pt", ""),
state = obj.optInt("st", 0),
linksUp = obj.optInt("lu", 0),
linksDown = obj.optInt("ld", 0)
linksDown = obj.optInt("ld", 0),
natMapping = obj.getInt("nmapping"),
natInbound = obj.getInt("ninbound"),
natSource = obj.getInt("nsource"),
externalIp = obj.getString("external"),
externalPort = obj.getInt("externalPort")
))
}
list.sortWith(compareBy<LocalSocketState> { it.ifName }.thenBy { it.bindIp }.thenBy { it.protocol }.thenBy { it.port })
return list
} catch (e: Exception) { Log.w("utun-gui", "getLocalSockets error", e) }
} catch (e: Exception) { Log.w("utun-gui", "local sockets snapshot parse error", e) }
return emptyList()
}
@@ -169,7 +169,7 @@ object NativeLib {
fun getMemberLinks(nodeId: Long): String = nativeGetMemberLinks(nodeId) ?: "{}"
/* ── Local sockets (for auto-mode display) ── */
fun getLocalSockets(): String = nativeGetLocalSockets() ?: "[]"
fun requestLocalSockets() = nativeRequestLocalSockets()
/* ── Voice recording ── */
fun voiceStart(channelId: String, replyTo: String = "", requestId: Long = 0): Boolean =
@@ -364,7 +364,7 @@ object NativeLib {
private external fun nativeGetMemberLinks(nodeId: Long): String?
/* ── Local sockets JNI ── */
private external fun nativeGetLocalSockets(): String?
private external fun nativeRequestLocalSockets()
/* ── Voice recording JNI ── */
private external fun nativeVoiceStart(channelId: String, replyTo: ByteArray, requestId: Long): Boolean
@@ -675,7 +675,10 @@ class ChatViewModel : ViewModel() {
LogManager.addLog("ERROR", "stream", "source snapshot parse group=$group: ${e.message}")
}
}
19 -> { if (repo != null) refreshLocalSockets() } /* LOCAL_SOCKETS */
19 -> { /* LOCAL_SOCKETS: снимок создан в потоке ядра; пустое событие просит обновить его. */
if (data == null || data.isEmpty()) refreshLocalSockets()
else repo?.let { _localSockets.value = it.parseLocalSockets(String(data, Charsets.UTF_8)) }
}
23 -> { /* MEMBER_LIST: live-снимок дополняет расширенный JSON-список. */
if (data == null || data.size < 3) {
LogManager.addLog("ERROR", "VM", "MEMBER_LIST: missing header"); return
@@ -1487,10 +1490,7 @@ class ChatViewModel : ViewModel() {
}
fun refreshLocalSockets() {
val r = repo ?: return
viewModelScope.launch {
_localSockets.value = withContext(Dispatchers.IO) { r.getLocalSockets() }
}
if (repo != null) NativeLib.requestLocalSockets()
}
fun sendMessage(text: String) {