diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/ChatRepository.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/ChatRepository.kt index 57bed268..52277250 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/ChatRepository.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/ChatRepository.kt @@ -474,9 +474,15 @@ class ChatRepository(private val reportFailure: (String) -> Unit = { LogManager. fun deleteChannel(channelId: String) = NativeLib.deleteChannel(channelId) - fun getMemberLinks(nodeId: Long): MemberLinks { + fun getMemberLinks(nodeId: Long): MemberLinks? { + return try { parseMemberLinks(NativeLib.getMemberLinks(nodeId)) } + catch (e: Exception) { reportFailure("Member links unavailable node=$nodeId: $e"); null } + } + + /** null — ошибка снимка, {cn:false} либо {} — подтверждённое отсутствие соединения. */ + internal fun parseMemberLinks(json: String): MemberLinks? { try { - val obj = JSONObject(NativeLib.getMemberLinks(nodeId)) + val obj = JSONObject(json) if (!obj.optBoolean("cn", false)) return MemberLinks() val links = mutableListOf() val arr = obj.optJSONArray("lk") @@ -505,8 +511,8 @@ class ChatRepository(private val reportFailure: (String) -> Unit = { LogManager. linksUp = obj.optInt("lu", 0), links = links ) - } catch (e: Exception) { reportFailure("Member links failed node=$nodeId: $e") } - return MemberLinks() + } catch (e: Exception) { reportFailure("Member links snapshot failed: $e") } + return null } fun parseLocalSockets(json: String): List? { diff --git a/tools/chatgui-android/app/src/test/java/com/utun/chat/data/ChatRepositorySnapshotTest.kt b/tools/chatgui-android/app/src/test/java/com/utun/chat/data/ChatRepositorySnapshotTest.kt index 26f916ea..7264a2ba 100644 --- a/tools/chatgui-android/app/src/test/java/com/utun/chat/data/ChatRepositorySnapshotTest.kt +++ b/tools/chatgui-android/app/src/test/java/com/utun/chat/data/ChatRepositorySnapshotTest.kt @@ -33,4 +33,16 @@ class ChatRepositorySnapshotTest { assertEquals(emptyList(), repo.parseLocalSockets("[]")) assertEquals(before, repo.parseLocalSockets("[$row]")) } + + @Test fun brokenLinkSnapshotDoesNotTurnAConnectedPeerIntoDisconnected() { + val row = """{"cn":true,"in":true,"lu":1,"lk":[{"id":9,"st":3,"sn":"Wi-Fi 😀"}]}""" + val connected = repo.parseMemberLinks(row)!! + assertTrue(connected.connected) + assertEquals("Wi-Fi 😀", connected.links.single().socketName) + assertNull(repo.parseMemberLinks("""{"cn":true,"lk":[{},null]}""")) + assertTrue(errors.single().contains("Member links snapshot failed")) + assertEquals(MemberLinks(), repo.parseMemberLinks("{}")) + assertEquals(MemberLinks(), repo.parseMemberLinks("""{"cn":false}""")) + assertEquals(connected, repo.parseMemberLinks(row)) + } }