From c1434648dcd8950c9287ab0c47930df6104451ce Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Thu, 2 Mar 2023 17:34:48 +1100 Subject: [PATCH] refactor: refactor tests and wrappers to use less pointers, finish implementing user groups API --- .../libsession_util/InstrumentedTests.kt | 80 +++++++++------- libsession-util/src/main/cpp/config_base.cpp | 14 ++- libsession-util/src/main/cpp/contacts.cpp | 2 +- libsession-util/src/main/cpp/contacts.h | 18 ++-- libsession-util/src/main/cpp/conversation.cpp | 12 +-- libsession-util/src/main/cpp/conversation.h | 39 ++++---- libsession-util/src/main/cpp/user_groups.cpp | 96 ++++++++++++++++++- libsession-util/src/main/cpp/user_groups.h | 30 ++++-- libsession-util/src/main/cpp/util.cpp | 16 ++++ .../loki/messenger/libsession_util/Config.kt | 13 ++- .../messenger/libsession_util/util/Utils.kt | 6 +- 11 files changed, 234 insertions(+), 92 deletions(-) diff --git a/libsession-util/src/androidTest/java/network/loki/messenger/libsession_util/InstrumentedTests.kt b/libsession-util/src/androidTest/java/network/loki/messenger/libsession_util/InstrumentedTests.kt index 9e37dfbaa1..260a9160bd 100644 --- a/libsession-util/src/androidTest/java/network/loki/messenger/libsession_util/InstrumentedTests.kt +++ b/libsession-util/src/androidTest/java/network/loki/messenger/libsession_util/InstrumentedTests.kt @@ -89,7 +89,7 @@ class InstrumentedTests { val push1 = contacts.push() assertEquals(1, push1.seqNo) - contacts.confirmPushed(push1.seqNo) + contacts.confirmPushed(push1.seqNo, "fakehash1") assertFalse(contacts.needsPush()) assertTrue(contacts.needsDump()) @@ -103,10 +103,10 @@ class InstrumentedTests { contacts2.set(c2) val push2 = contacts2.push() assertEquals(2, push2.seqNo) - contacts2.confirmPushed(push2.seqNo) + contacts2.confirmPushed(push2.seqNo, "fakehash2") assertFalse(contacts2.needsPush()) - contacts.merge(push2.config) + contacts.merge("fakehash2" to push2.config) assertFalse(contacts.needsPush()) @@ -136,11 +136,11 @@ class InstrumentedTests { assertEquals(toPush.seqNo, toPush2.seqNo) assertThat(toPush2.config, not(equals(toPush.config))) - contacts.confirmPushed(toPush.seqNo) - contacts2.confirmPushed(toPush2.seqNo) + contacts.confirmPushed(toPush.seqNo, "fakehash3a") + contacts2.confirmPushed(toPush2.seqNo, "fakehash3b") - contacts.merge(toPush2.config) - contacts2.merge(toPush.config) + contacts.merge("fakehash3b" to toPush2.config) + contacts2.merge("fakehash3a" to toPush.config) assertTrue(contacts.needsPush()) assertTrue(contacts2.needsPush()) @@ -150,6 +150,10 @@ class InstrumentedTests { assertEquals(mergePush.seqNo, mergePush2.seqNo) assertArrayEquals(mergePush.config, mergePush2.config) + + assertTrue(mergePush.obsoleteHashes.containsAll(listOf("fakehash3b", "fakehash3a"))) + assertTrue(mergePush2.obsoleteHashes.containsAll(listOf("fakehash3b", "fakehash3a"))) + } @Test @@ -217,23 +221,14 @@ class InstrumentedTests { "e" + "e").encodeToByteArray() - val expectedPush1Encrypted = Hex.fromStringCondensed( - "877c8e0f5d33f5fffa5a4e162785a9a89918e95de1c4b925201f1f5c29d9ee4f8c36e2b278fce1e6" + - "b9d999689dd86ff8e79e0a04004fa54d24da89bc2604cb1df8c1356da8f14710543ecec44f2d57fc" + - "56ea8b7e73d119c69d755f4d513d5d069f02396b8ec0cbed894169836f57ca4b782ce705895c593b" + - "4230d50c175d44a08045388d3f4160bacb617b9ae8de3ebc8d9024245cd09ce102627cab2acf1b91" + - "26159211359606611ca5814de320d1a7099a65c99b0eebbefb92a115f5efa6b9132809300ac010c6" + - "857cfbd62af71b0fa97eccec75cb95e67edf40b35fdb9cad125a6976693ab085c6bba96a2e51826e" + - "81e16b9ec1232af5680f2ced55310486" - ) - assertEquals(1, newSeqNo) - assertArrayEquals(expectedPush1Encrypted, newToPush) // We haven't dumped, so still need to dump: assertTrue(userProfile.needsDump()) // We did call push but we haven't confirmed it as stored yet, so this will still return true: assertTrue(userProfile.needsPush()) + userProfile.confirmPushed(newSeqNo, "fakehash1") + val dump = userProfile.dump() // (in a real client we'd now store this to disk) assertFalse(userProfile.needsDump()) @@ -247,7 +242,7 @@ class InstrumentedTests { val newConf = UserProfile.newInstance(edSk) - val accepted = newConf.merge(arrayOf(expectedPush1Encrypted)) + val accepted = newConf.merge("fakehash1" to newToPush) assertEquals(1, accepted) assertTrue(newConf.needsDump()) @@ -263,13 +258,16 @@ class InstrumentedTests { val conf = userProfile.push() val conf2 = newConf.push() + userProfile.confirmPushed(conf.seqNo, "fakehash1") + newConf.confirmPushed(conf2.seqNo, "fakehash2") + userProfile.dump() userProfile.dump() assertFalse(conf.config.contentEquals(conf2.config)) - newConf.merge(arrayOf(conf.config)) - userProfile.merge(arrayOf(conf2.config)) + newConf.merge("fakehash1" to conf.config) + userProfile.merge("fakehash2" to conf2.config) assertTrue(newConf.needsPush()) assertTrue(userProfile.needsPush()) @@ -278,16 +276,20 @@ class InstrumentedTests { assertEquals(3, newSeq1.seqNo) + userProfile.confirmPushed(newSeq1.seqNo, "fakehash3") + // assume newConf push gets rejected as it was last to write and clear previous config by hash on oxenss - newConf.merge(arrayOf(newSeq1.config)) + newConf.merge("fakehash3" to newSeq1.config) val newSeqMerge = newConf.push() + newConf.confirmPushed(newSeqMerge.seqNo, "fakehash4") + assertEquals("Nibbler", newConf.getName()) assertEquals(4, newSeqMerge.seqNo) // userProfile device polls and merges - userProfile.merge(arrayOf(newSeqMerge.config)) + userProfile.merge("fakehash4" to newSeqMerge.config) val userConfigMerge = userProfile.push() @@ -308,14 +310,16 @@ class InstrumentedTests { val b = UserProfile.newInstance(kp.secretKey) a.setName("A") val (aPush, aSeq) = a.push() + a.confirmPushed(aSeq, "hashfroma") b.setName("B") // polls and sees invalid state, has to merge - b.merge(aPush) + b.merge("hashfroma" to aPush) val (bPush, bSeq) = b.push() + b.confirmPushed(bSeq, "hashfromb") assertEquals("B", b.getName()) assertEquals(1, aSeq) assertEquals(2, bSeq) - a.merge(bPush) + a.merge("hashfromb" to bPush) assertEquals(2, a.push().seqNo) } @@ -456,11 +460,12 @@ class InstrumentedTests { val openGroupPubKey = Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") val og = convos.getOrConstructCommunity("http://Example.ORG:5678", "SudokuRoom", openGroupPubKey) + val ogCommunity = og.baseCommunityInfo - assertEquals("http://example.org:5678", og.baseUrl) // Note: lower-case - assertEquals("sudokuroom", og.room) // Note: lower-case - assertEquals(32, og.pubKey.size); - assertEquals("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", og.pubKeyHex) + assertEquals("http://example.org:5678", ogCommunity.baseUrl) // Note: lower-case + assertEquals("sudokuroom", ogCommunity.room) // Note: lower-case + assertEquals(64, ogCommunity.pubKeyHex.length) + assertEquals("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", ogCommunity.pubKeyHex) og.unread = true @@ -470,7 +475,7 @@ class InstrumentedTests { assertEquals(1, seqNo) - convos.confirmPushed(seqNo) + convos.confirmPushed(seqNo, "fakehash1") assertTrue(convos.needsDump()) assertFalse(convos.needsPush()) @@ -487,9 +492,10 @@ class InstrumentedTests { assertEquals(false, x1.unread) val x2 = convos2.getCommunity("http://EXAMPLE.org:5678", "sudokuRoom")!! - assertEquals("http://example.org:5678", x2.baseUrl) - assertEquals("sudokuroom", x2.room) - assertEquals(x2.pubKeyHex, Hex.toStringCondensed(openGroupPubKey)) + val x2Info = x2.baseCommunityInfo + assertEquals("http://example.org:5678", x2Info.baseUrl) + assertEquals("sudokuroom", x2Info.room) + assertEquals(x2Info.pubKeyHex, Hex.toStringCondensed(openGroupPubKey)) assertTrue(x2.unread) val anotherId = "051111111111111111111111111111111111111111111111111111111111111111" @@ -508,8 +514,8 @@ class InstrumentedTests { val (toPush2, seqNo2) = convos2.push() assertEquals(2, seqNo2) - convos.merge(toPush2) - convos2.confirmPushed(seqNo2) + convos2.confirmPushed(seqNo2, "fakehash2") + convos.merge("fakehash2" to toPush2) assertFalse(convos.needsPush()) assertEquals(seqNo2, convos.push().seqNo) @@ -527,7 +533,7 @@ class InstrumentedTests { for (convo in allConvos) { when (convo) { is Conversation.OneToOne -> seen.add("1-to-1: ${convo.sessionId}") - is Conversation.Community -> seen.add("og: ${convo.baseUrl}/r/${convo.room}") + is Conversation.Community -> seen.add("og: ${convo.baseCommunityInfo.baseUrl}/r/${convo.baseCommunityInfo.room}") is Conversation.LegacyGroup -> seen.add("cl: ${convo.groupId}") } } @@ -551,7 +557,7 @@ class InstrumentedTests { ) assertEquals(1, convos.allCommunities().size) assertEquals("http://example.org:5678", - convos.allCommunities().map(Conversation.Community::baseUrl).first() + convos.allCommunities().map { it.baseCommunityInfo.baseUrl }.first() ) assertEquals(1, convos.allLegacyClosedGroups().size) assertEquals("05cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", diff --git a/libsession-util/src/main/cpp/config_base.cpp b/libsession-util/src/main/cpp/config_base.cpp index 3d2fbbb917..f59fbb1a92 100644 --- a/libsession-util/src/main/cpp/config_base.cpp +++ b/libsession-util/src/main/cpp/config_base.cpp @@ -29,9 +29,17 @@ Java_network_loki_messenger_libsession_1util_ConfigBase_push(JNIEnv *env, jobjec jbyteArray returnByteArray = util::bytes_from_ustring(env, to_push_str); jlong seqNo = std::get<0>(push_tuple); - jclass returnObjectClass = env->FindClass("network/loki/messenger/libsession_util/util/ConfigWithSeqNo"); - jmethodID methodId = env->GetMethodID(returnObjectClass, "", "([BJ)V"); - jobject returnObject = env->NewObject(returnObjectClass, methodId, returnByteArray, seqNo); + jclass returnObjectClass = env->FindClass("network/loki/messenger/libsession_util/util/ConfigPush"); + jclass stackClass = env->FindClass("java/util/Stack"); + jmethodID methodId = env->GetMethodID(returnObjectClass, "", "([BJLjava/util/List;)V"); + jmethodID stack_init = env->GetMethodID(stackClass, "", "()V"); + jobject our_stack = env->NewObject(stackClass, stack_init); + jmethodID push_stack = env->GetMethodID(stackClass, "push", "(Ljava/lang/Object;)Ljava/lang/Object;"); + for (auto entry : to_delete) { + auto entry_jstring = env->NewStringUTF(entry.data()); + env->CallObjectMethod(our_stack, push_stack, entry_jstring); + } + jobject returnObject = env->NewObject(returnObjectClass, methodId, returnByteArray, seqNo, our_stack); return returnObject; } diff --git a/libsession-util/src/main/cpp/contacts.cpp b/libsession-util/src/main/cpp/contacts.cpp index 156812b8e1..3f7b052fac 100644 --- a/libsession-util/src/main/cpp/contacts.cpp +++ b/libsession-util/src/main/cpp/contacts.cpp @@ -31,7 +31,7 @@ Java_network_loki_messenger_libsession_1util_Contacts_set(JNIEnv *env, jobject t jobject contact) { auto contacts = ptrToContacts(env, thiz); auto contact_info = deserialize_contact(env, contact); - contacts->set(*contact_info); + contacts->set(contact_info); } extern "C" diff --git a/libsession-util/src/main/cpp/contacts.h b/libsession-util/src/main/cpp/contacts.h index 9c070975b8..9d7735f28b 100644 --- a/libsession-util/src/main/cpp/contacts.h +++ b/libsession-util/src/main/cpp/contacts.h @@ -27,7 +27,7 @@ inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info return returnObj; } -inline session::config::contact_info* deserialize_contact(JNIEnv *env, jobject info) { +inline session::config::contact_info deserialize_contact(JNIEnv *env, jobject info) { jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact"); jfieldID getId, getName, getNick, getApproved, getApprovedMe, getBlocked, getUserPic, getPriority; @@ -66,18 +66,18 @@ inline session::config::contact_info* deserialize_contact(JNIEnv *env, jobject i auto name_bytes = name ? env->GetStringUTFChars(name, nullptr) : nullptr; auto nickname_bytes = nickname ? env->GetStringUTFChars(nickname, nullptr) : nullptr; - auto contact_info = new session::config::contact_info(session_id_bytes); + auto contact_info = session::config::contact_info(session_id_bytes); if (name_bytes) { - contact_info->name = name_bytes; + contact_info.name = name_bytes; } if (nickname_bytes) { - contact_info->nickname = nickname_bytes; + contact_info.nickname = nickname_bytes; } - contact_info->approved = approved; - contact_info->approved_me = approvedMe; - contact_info->blocked = blocked; + contact_info.approved = approved; + contact_info.approved_me = approvedMe; + contact_info.blocked = blocked; if (!url.empty() && !key.empty()) { - contact_info->profile_picture = session::config::profile_pic(url, key); + contact_info.profile_picture = session::config::profile_pic(url, key); } env->ReleaseStringUTFChars(session_id, session_id_bytes); @@ -88,7 +88,7 @@ inline session::config::contact_info* deserialize_contact(JNIEnv *env, jobject i env->ReleaseStringUTFChars(nickname, nickname_bytes); } - contact_info->priority = priority; + contact_info.priority = priority; return contact_info; } diff --git a/libsession-util/src/main/cpp/conversation.cpp b/libsession-util/src/main/cpp/conversation.cpp index 5d87272298..0b28fc0508 100644 --- a/libsession-util/src/main/cpp/conversation.cpp +++ b/libsession-util/src/main/cpp/conversation.cpp @@ -121,13 +121,13 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_set(JNIE jclass to_store_class = env->GetObjectClass(to_store); if (env->IsSameObject(to_store_class, one_to_one)) { // store as 1to1 - convos->set(*deserialize_one_to_one(env, to_store)); + convos->set(deserialize_one_to_one(env, to_store)); } else if (env->IsSameObject(to_store_class,open_group)) { // store as open_group - convos->set(*deserialize_open_group(env, to_store)); + convos->set(deserialize_community(env, to_store)); } else if (env->IsSameObject(to_store_class,legacy_closed_group)) { // store as legacy_closed_group - convos->set(*deserialize_legacy_closed_group(env, to_store)); + convos->set(deserialize_legacy_closed_group(env, to_store)); } } extern "C" @@ -213,8 +213,8 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseCom jobject thiz, jobject open_group) { auto convos = ptrToConvoInfo(env, thiz); - auto deserialized = deserialize_open_group(env, open_group); - return convos->erase(*deserialized); + auto deserialized = deserialize_community(env, open_group); + return convos->erase(deserialized); } extern "C" JNIEXPORT jboolean JNICALL @@ -269,7 +269,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_erase(JN jobject conversation) { auto convos = ptrToConvoInfo(env, thiz); auto deserialized = deserialize_any(env, conversation); - if (deserialized == nullptr) return false; + if (!deserialized.has_value()) return false; return convos->erase(*deserialized); } extern "C" diff --git a/libsession-util/src/main/cpp/conversation.h b/libsession-util/src/main/cpp/conversation.h index db18b85276..be0f0cc8f5 100644 --- a/libsession-util/src/main/cpp/conversation.h +++ b/libsession-util/src/main/cpp/conversation.h @@ -53,7 +53,7 @@ inline jobject serialize_any(JNIEnv *env, session::config::convo::any any) { return nullptr; } -inline session::config::convo::one_to_one* deserialize_one_to_one(JNIEnv *env, jobject info) { +inline session::config::convo::one_to_one deserialize_one_to_one(JNIEnv *env, jobject info) { auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne"); auto id_getter = env->GetFieldID(clazz, "sessionId", "Ljava/lang/String;"); auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J"); @@ -61,36 +61,35 @@ inline session::config::convo::one_to_one* deserialize_one_to_one(JNIEnv *env, j jstring id = static_cast(env->GetObjectField(info, id_getter)); auto id_chars = env->GetStringUTFChars(id, nullptr); std::string id_string = std::string{id_chars}; - auto deserialized = new session::config::convo::one_to_one(id_string); - deserialized->last_read = env->GetLongField(info, last_read_getter); - deserialized->unread = env->GetBooleanField(info, unread_getter); + auto deserialized = session::config::convo::one_to_one{id_string}; + deserialized.last_read = env->GetLongField(info, last_read_getter); + deserialized.unread = env->GetBooleanField(info, unread_getter); env->ReleaseStringUTFChars(id, id_chars); return deserialized; } -inline session::config::convo::community* deserialize_open_group(JNIEnv *env, jobject info) { +inline session::config::convo::community deserialize_community(JNIEnv *env, jobject info) { auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$Community"); - auto base_community_getter = env->GetFieldID(clazz, "baseCommunityInfo", "Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;"); - auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J"); auto unread_getter = env->GetFieldID(clazz, "unread", "Z"); auto base_community_info = env->GetObjectField(info, base_community_getter); auto base_community_deserialized = util::deserialize_base_community(env, base_community_info); - - auto deserialized = new session::config::convo::community{ + auto deserialized = session::config::convo::community{ base_community_deserialized.base_url(), base_community_deserialized.room(), base_community_deserialized.pubkey() }; - deserialized->last_read = env->GetLongField(info, last_read_getter); - deserialized->unread = env->GetBooleanField(info, unread_getter); + + deserialized.last_read = env->GetLongField(info, last_read_getter); + deserialized.unread = env->GetBooleanField(info, unread_getter); + return deserialized; } -inline session::config::convo::legacy_group* deserialize_legacy_closed_group(JNIEnv *env, jobject info) { +inline session::config::convo::legacy_group deserialize_legacy_closed_group(JNIEnv *env, jobject info) { auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyGroup"); auto group_id_getter = env->GetFieldID(clazz, "groupId", "Ljava/lang/String;"); auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J"); @@ -98,26 +97,26 @@ inline session::config::convo::legacy_group* deserialize_legacy_closed_group(JNI auto group_id = static_cast(env->GetObjectField(info, group_id_getter)); auto group_id_bytes = env->GetStringUTFChars(group_id, nullptr); auto group_id_string = std::string{group_id_bytes}; - auto deserialized = new session::config::convo::legacy_group(group_id_string); - deserialized->last_read = env->GetLongField(info, last_read_getter); - deserialized->unread = env->GetBooleanField(info, unread_getter); + auto deserialized = session::config::convo::legacy_group(group_id_string); + deserialized.last_read = env->GetLongField(info, last_read_getter); + deserialized.unread = env->GetBooleanField(info, unread_getter); env->ReleaseStringUTFChars(group_id, group_id_bytes); return deserialized; } -inline session::config::convo::any* deserialize_any(JNIEnv *env, jobject convo) { +inline std::optional deserialize_any(JNIEnv *env, jobject convo) { auto oto_class = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne"); auto og_class = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$Community"); auto lgc_class = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyGroup"); auto object_class = env->GetObjectClass(convo); if (env->IsSameObject(object_class, oto_class)) { - return new session::config::convo::any{*deserialize_one_to_one(env, convo)}; + return session::config::convo::any{deserialize_one_to_one(env, convo)}; } else if (env->IsSameObject(object_class, og_class)) { - return new session::config::convo::any{*deserialize_open_group(env, convo)}; + return session::config::convo::any{deserialize_community(env, convo)}; } else if (env->IsSameObject(object_class, lgc_class)) { - return new session::config::convo::any{*deserialize_legacy_closed_group(env, convo)}; + return session::config::convo::any{deserialize_legacy_closed_group(env, convo)}; } - return nullptr; + return std::nullopt; } #endif //SESSION_ANDROID_CONVERSATION_H \ No newline at end of file diff --git a/libsession-util/src/main/cpp/user_groups.cpp b/libsession-util/src/main/cpp/user_groups.cpp index f0dde7b343..07d5ee066b 100644 --- a/libsession-util/src/main/cpp/user_groups.cpp +++ b/libsession-util/src/main/cpp/user_groups.cpp @@ -1,3 +1,5 @@ +#pragma clang diagnostic push +#pragma ide diagnostic ignored "bugprone-reserved-identifier" #include "user_groups.h" @@ -113,7 +115,7 @@ JNIEXPORT void JNICALL Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_CommunityGroupInfo_2( JNIEnv *env, jobject thiz, jobject community_info) { auto conf = ptrToUserGroups(env, thiz); - auto deserialized = (env, community_info); + auto deserialized = deserialize_community_info(env, community_info); conf->set(deserialized); } @@ -123,5 +125,95 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__Lnetwork_loki JNIEnv *env, jobject thiz, jobject legacy_group_info) { auto conf = ptrToUserGroups(env, thiz); auto deserialized = deserialize_legacy_group_info(env, legacy_group_info); - conf->set(*deserialized); + conf->set(deserialized); +} +#pragma clang diagnostic pop +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_UserGroupsConfig_erase__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_CommunityGroupInfo_2( + JNIEnv *env, jobject thiz, jobject community_info) { + auto conf = ptrToUserGroups(env, thiz); + auto deserialized = deserialize_community_info(env, community_info); + conf->erase(deserialized); +} + +extern "C" +JNIEXPORT void JNICALL +Java_network_loki_messenger_libsession_1util_UserGroupsConfig_erase__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_LegacyGroupInfo_2( + JNIEnv *env, jobject thiz, jobject legacy_group_info) { + auto conf = ptrToUserGroups(env, thiz); + auto deserialized = deserialize_legacy_group_info(env, legacy_group_info); + conf->erase(deserialized); +} + +extern "C" +JNIEXPORT jint JNICALL +Java_network_loki_messenger_libsession_1util_UserGroupsConfig_sizeCommunityInfo(JNIEnv *env, + jobject thiz) { + auto conf = ptrToUserGroups(env, thiz); + return conf->size_communities(); +} + +extern "C" +JNIEXPORT jint JNICALL +Java_network_loki_messenger_libsession_1util_UserGroupsConfig_sizeLegacyGroupInfo(JNIEnv *env, + jobject thiz) { + auto conf = ptrToUserGroups(env, thiz); + return conf->size_legacy_groups(); +} + +extern "C" +JNIEXPORT jint JNICALL +Java_network_loki_messenger_libsession_1util_UserGroupsConfig_size(JNIEnv *env, jobject thiz) { + auto conf = ptrToConvoInfo(env, thiz); + return conf->size(); +} + +inline jobject iterator_as_java_stack(JNIEnv *env, const session::config::UserGroups::iterator& begin, const session::config::UserGroups::iterator& end) { + jclass stack = env->FindClass("java/util/Stack"); + jmethodID init = env->GetMethodID(stack, "", "()V"); + jobject our_stack = env->NewObject(stack, init); + jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;"); + for (auto it = begin; it != end;) { + // do something with it + auto item = *it; + jobject serialized = nullptr; + if (auto* lgc = std::get_if(&item)) { + serialized = serialize_legacy_group_info(env, *lgc); + + } else if (auto* community = std::get_if(&item)) { + serialized = serialize_community_info(env, *community); + } + if (serialized != nullptr) { + env->CallObjectMethod(our_stack, push, serialized); + } + it++; + } + return our_stack; +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_UserGroupsConfig_all(JNIEnv *env, jobject thiz) { + auto conf = ptrToUserGroups(env, thiz); + jobject all_stack = iterator_as_java_stack(env, conf->begin(), conf->end()); + return all_stack; +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_UserGroupsConfig_allCommunityInfo(JNIEnv *env, + jobject thiz) { + auto conf = ptrToUserGroups(env, thiz); + jobject community_stack = iterator_as_java_stack(env, conf->begin_communities(), conf->end()); + return community_stack; +} + +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_UserGroupsConfig_allLegacyGroupInfo(JNIEnv *env, + jobject thiz) { + auto conf = ptrToUserGroups(env, thiz); + jobject legacy_stack = iterator_as_java_stack(env, conf->begin_legacy_groups(), conf->end()); + return legacy_stack; } \ No newline at end of file diff --git a/libsession-util/src/main/cpp/user_groups.h b/libsession-util/src/main/cpp/user_groups.h index 398d033c26..166efc65a3 100644 --- a/libsession-util/src/main/cpp/user_groups.h +++ b/libsession-util/src/main/cpp/user_groups.h @@ -12,7 +12,7 @@ inline session::config::UserGroups* ptrToUserGroups(JNIEnv *env, jobject obj) { return (session::config::UserGroups*) env->GetLongField(obj, pointerField); } -inline void deserialize_members_into(JNIEnv *env, jobject members_map, session::config::legacy_group_info *to_append_group) { +inline void deserialize_members_into(JNIEnv *env, jobject members_map, session::config::legacy_group_info& to_append_group) { jclass map_class = env->FindClass("java/util/Map"); jclass map_entry_class = env->FindClass("java/util/Map$Entry"); jclass set_class = env->FindClass("java/util/Set"); @@ -36,12 +36,12 @@ inline void deserialize_members_into(JNIEnv *env, jobject members_map, session:: jobject boxed = env->CallObjectMethod(entry, get_value); bool is_admin = env->CallBooleanMethod(boxed, get_bool_value); auto member_string = env->GetStringUTFChars(key, nullptr); - to_append_group->insert(member_string, is_admin); + to_append_group.insert(member_string, is_admin); env->ReleaseStringUTFChars(key, member_string); } } -inline session::config::legacy_group_info* deserialize_legacy_group_info(JNIEnv *env, jobject info) { +inline session::config::legacy_group_info deserialize_legacy_group_info(JNIEnv *env, jobject info) { auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo"); auto id_field = env->GetFieldID(clazz, "sessionId", "Ljava/lang/String;"); auto name_field = env->GetFieldID(clazz, "name", "Ljava/lang/String;"); @@ -63,19 +63,31 @@ inline session::config::legacy_group_info* deserialize_legacy_group_info(JNIEnv auto enc_pub_key_bytes = util::ustring_from_bytes(env, enc_pub_key); auto enc_sec_key_bytes = util::ustring_from_bytes(env, enc_sec_key); - auto info_deserialized = new session::config::legacy_group_info(id_bytes); + auto info_deserialized = session::config::legacy_group_info(id_bytes); - info_deserialized->priority = priority; + info_deserialized.priority = priority; deserialize_members_into(env, members_map, info_deserialized); - info_deserialized->name = name_bytes; - info_deserialized->hidden = hidden; - info_deserialized->enc_pubkey = enc_pub_key_bytes; - info_deserialized->enc_seckey = enc_sec_key_bytes; + info_deserialized.name = name_bytes; + info_deserialized.hidden = hidden; + info_deserialized.enc_pubkey = enc_pub_key_bytes; + info_deserialized.enc_seckey = enc_sec_key_bytes; env->ReleaseStringUTFChars(id, id_bytes); env->ReleaseStringUTFChars(name, name_bytes); return info_deserialized; } +inline session::config::community_info deserialize_community_info(JNIEnv *env, jobject info) { + auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo"); + auto base_info = env->GetFieldID(clazz, "community", "Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;"); + auto priority = env->GetFieldID(clazz, "priority", "I"); + jobject base_community_info = env->GetObjectField(info, base_info); + auto deserialized_base_info = util::deserialize_base_community(env, base_community_info); + int deserialized_priority = env->GetIntField(info, priority); + auto community_info = session::config::community_info(deserialized_base_info.base_url(), deserialized_base_info.room(), deserialized_base_info.pubkey_hex()); + community_info.priority = deserialized_priority; + return community_info; +} + inline jobject serialize_members(JNIEnv *env, std::map members_map) { jclass map_class = env->FindClass("java/util/HashMap"); jclass boxed_bool = env->FindClass("java/lang/Boolean"); diff --git a/libsession-util/src/main/cpp/util.cpp b/libsession-util/src/main/cpp/util.cpp index 8ef48381cb..7b093433cc 100644 --- a/libsession-util/src/main/cpp/util.cpp +++ b/libsession-util/src/main/cpp/util.cpp @@ -48,7 +48,23 @@ namespace util { } session::config::community deserialize_base_community(JNIEnv *env, jobject base_community) { + jclass base_community_clazz = env->FindClass("network/loki/messenger/libsession_util/util/BaseCommunityInfo"); + jfieldID base_url_field = env->GetFieldID(base_community_clazz, "baseUrl", "Ljava/lang/String;"); + jfieldID room_field = env->GetFieldID(base_community_clazz, "room", "Ljava/lang/String;"); + jfieldID pubkey_hex_field = env->GetFieldID(base_community_clazz, "pubKeyHex", "Ljava/lang/String;"); + auto base_url = (jstring)env->GetObjectField(base_community,base_url_field); + auto room = (jstring)env->GetObjectField(base_community, room_field); + auto pub_key_hex = (jstring)env->GetObjectField(base_community, pubkey_hex_field); + auto base_url_chars = env->GetStringUTFChars(base_url, nullptr); + auto room_chars = env->GetStringUTFChars(room, nullptr); + auto pub_key_hex_chars = env->GetStringUTFChars(pub_key_hex, nullptr); + auto community = session::config::community(base_url_chars, room_chars, pub_key_hex_chars); + + env->ReleaseStringUTFChars(base_url, base_url_chars); + env->ReleaseStringUTFChars(room, room_chars); + env->ReleaseStringUTFChars(pub_key_hex, pub_key_hex_chars); + return community; } } diff --git a/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt b/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt index 9b503df392..f732eff341 100644 --- a/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt +++ b/libsession-util/src/main/java/network/loki/messenger/libsession_util/Config.kt @@ -1,6 +1,6 @@ package network.loki.messenger.libsession_util -import network.loki.messenger.libsession_util.util.ConfigWithSeqNo +import network.loki.messenger.libsession_util.util.ConfigPush import network.loki.messenger.libsession_util.util.Contact import network.loki.messenger.libsession_util.util.Conversation import network.loki.messenger.libsession_util.util.GroupInfo @@ -29,7 +29,7 @@ sealed class ConfigBase(protected val /* yucky */ pointer: Long) { external fun dirty(): Boolean external fun needsPush(): Boolean external fun needsDump(): Boolean - external fun push(): ConfigWithSeqNo + external fun push(): ConfigPush external fun dump(): ByteArray external fun encryptionDomain(): String external fun confirmPushed(seqNo: Long, newHash: String) @@ -160,5 +160,12 @@ class UserGroupsConfig(pointer: Long): ConfigBase(pointer) { external fun getOrConstructLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo external fun set(communityInfo: GroupInfo.CommunityGroupInfo) external fun set(legacyGroupInfo: GroupInfo.LegacyGroupInfo) - + external fun erase(communityInfo: GroupInfo.CommunityGroupInfo) + external fun erase(legacyGroupInfo: GroupInfo.LegacyGroupInfo) + external fun sizeCommunityInfo(): Int + external fun sizeLegacyGroupInfo(): Int + external fun size(): Int + external fun all(): List + external fun allCommunityInfo(): List + external fun allLegacyGroupInfo(): List } \ No newline at end of file diff --git a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Utils.kt b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Utils.kt index 8b600a9db1..4222395b5d 100644 --- a/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Utils.kt +++ b/libsession-util/src/main/java/network/loki/messenger/libsession_util/util/Utils.kt @@ -1,14 +1,15 @@ package network.loki.messenger.libsession_util.util -data class ConfigWithSeqNo(val config: ByteArray, val seqNo: Long) { +data class ConfigPush(val config: ByteArray, val seqNo: Long, val obsoleteHashes: List) { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false - other as ConfigWithSeqNo + other as ConfigPush if (!config.contentEquals(other.config)) return false if (seqNo != other.seqNo) return false + if (obsoleteHashes != other.obsoleteHashes) return false return true } @@ -16,6 +17,7 @@ data class ConfigWithSeqNo(val config: ByteArray, val seqNo: Long) { override fun hashCode(): Int { var result = config.contentHashCode() result = 31 * result + seqNo.hashCode() + result = 31 * result + obsoleteHashes.hashCode() return result }