refactor: refactor tests and wrappers to use less pointers, finish implementing user groups API

This commit is contained in:
0x330a 2023-03-02 17:34:48 +11:00
parent e9afb8fa44
commit c1434648dc
No known key found for this signature in database
GPG Key ID: 267811D6E6A2698C
11 changed files with 234 additions and 92 deletions

View File

@ -89,7 +89,7 @@ class InstrumentedTests {
val push1 = contacts.push() val push1 = contacts.push()
assertEquals(1, push1.seqNo) assertEquals(1, push1.seqNo)
contacts.confirmPushed(push1.seqNo) contacts.confirmPushed(push1.seqNo, "fakehash1")
assertFalse(contacts.needsPush()) assertFalse(contacts.needsPush())
assertTrue(contacts.needsDump()) assertTrue(contacts.needsDump())
@ -103,10 +103,10 @@ class InstrumentedTests {
contacts2.set(c2) contacts2.set(c2)
val push2 = contacts2.push() val push2 = contacts2.push()
assertEquals(2, push2.seqNo) assertEquals(2, push2.seqNo)
contacts2.confirmPushed(push2.seqNo) contacts2.confirmPushed(push2.seqNo, "fakehash2")
assertFalse(contacts2.needsPush()) assertFalse(contacts2.needsPush())
contacts.merge(push2.config) contacts.merge("fakehash2" to push2.config)
assertFalse(contacts.needsPush()) assertFalse(contacts.needsPush())
@ -136,11 +136,11 @@ class InstrumentedTests {
assertEquals(toPush.seqNo, toPush2.seqNo) assertEquals(toPush.seqNo, toPush2.seqNo)
assertThat(toPush2.config, not(equals(toPush.config))) assertThat(toPush2.config, not(equals(toPush.config)))
contacts.confirmPushed(toPush.seqNo) contacts.confirmPushed(toPush.seqNo, "fakehash3a")
contacts2.confirmPushed(toPush2.seqNo) contacts2.confirmPushed(toPush2.seqNo, "fakehash3b")
contacts.merge(toPush2.config) contacts.merge("fakehash3b" to toPush2.config)
contacts2.merge(toPush.config) contacts2.merge("fakehash3a" to toPush.config)
assertTrue(contacts.needsPush()) assertTrue(contacts.needsPush())
assertTrue(contacts2.needsPush()) assertTrue(contacts2.needsPush())
@ -150,6 +150,10 @@ class InstrumentedTests {
assertEquals(mergePush.seqNo, mergePush2.seqNo) assertEquals(mergePush.seqNo, mergePush2.seqNo)
assertArrayEquals(mergePush.config, mergePush2.config) assertArrayEquals(mergePush.config, mergePush2.config)
assertTrue(mergePush.obsoleteHashes.containsAll(listOf("fakehash3b", "fakehash3a")))
assertTrue(mergePush2.obsoleteHashes.containsAll(listOf("fakehash3b", "fakehash3a")))
} }
@Test @Test
@ -217,23 +221,14 @@ class InstrumentedTests {
"e" + "e" +
"e").encodeToByteArray() "e").encodeToByteArray()
val expectedPush1Encrypted = Hex.fromStringCondensed(
"877c8e0f5d33f5fffa5a4e162785a9a89918e95de1c4b925201f1f5c29d9ee4f8c36e2b278fce1e6" +
"b9d999689dd86ff8e79e0a04004fa54d24da89bc2604cb1df8c1356da8f14710543ecec44f2d57fc" +
"56ea8b7e73d119c69d755f4d513d5d069f02396b8ec0cbed894169836f57ca4b782ce705895c593b" +
"4230d50c175d44a08045388d3f4160bacb617b9ae8de3ebc8d9024245cd09ce102627cab2acf1b91" +
"26159211359606611ca5814de320d1a7099a65c99b0eebbefb92a115f5efa6b9132809300ac010c6" +
"857cfbd62af71b0fa97eccec75cb95e67edf40b35fdb9cad125a6976693ab085c6bba96a2e51826e" +
"81e16b9ec1232af5680f2ced55310486"
)
assertEquals(1, newSeqNo) assertEquals(1, newSeqNo)
assertArrayEquals(expectedPush1Encrypted, newToPush)
// We haven't dumped, so still need to dump: // We haven't dumped, so still need to dump:
assertTrue(userProfile.needsDump()) assertTrue(userProfile.needsDump())
// We did call push but we haven't confirmed it as stored yet, so this will still return true: // We did call push but we haven't confirmed it as stored yet, so this will still return true:
assertTrue(userProfile.needsPush()) assertTrue(userProfile.needsPush())
userProfile.confirmPushed(newSeqNo, "fakehash1")
val dump = userProfile.dump() val dump = userProfile.dump()
// (in a real client we'd now store this to disk) // (in a real client we'd now store this to disk)
assertFalse(userProfile.needsDump()) assertFalse(userProfile.needsDump())
@ -247,7 +242,7 @@ class InstrumentedTests {
val newConf = UserProfile.newInstance(edSk) val newConf = UserProfile.newInstance(edSk)
val accepted = newConf.merge(arrayOf(expectedPush1Encrypted)) val accepted = newConf.merge("fakehash1" to newToPush)
assertEquals(1, accepted) assertEquals(1, accepted)
assertTrue(newConf.needsDump()) assertTrue(newConf.needsDump())
@ -263,13 +258,16 @@ class InstrumentedTests {
val conf = userProfile.push() val conf = userProfile.push()
val conf2 = newConf.push() val conf2 = newConf.push()
userProfile.confirmPushed(conf.seqNo, "fakehash1")
newConf.confirmPushed(conf2.seqNo, "fakehash2")
userProfile.dump() userProfile.dump()
userProfile.dump() userProfile.dump()
assertFalse(conf.config.contentEquals(conf2.config)) assertFalse(conf.config.contentEquals(conf2.config))
newConf.merge(arrayOf(conf.config)) newConf.merge("fakehash1" to conf.config)
userProfile.merge(arrayOf(conf2.config)) userProfile.merge("fakehash2" to conf2.config)
assertTrue(newConf.needsPush()) assertTrue(newConf.needsPush())
assertTrue(userProfile.needsPush()) assertTrue(userProfile.needsPush())
@ -278,16 +276,20 @@ class InstrumentedTests {
assertEquals(3, newSeq1.seqNo) 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 // 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() val newSeqMerge = newConf.push()
newConf.confirmPushed(newSeqMerge.seqNo, "fakehash4")
assertEquals("Nibbler", newConf.getName()) assertEquals("Nibbler", newConf.getName())
assertEquals(4, newSeqMerge.seqNo) assertEquals(4, newSeqMerge.seqNo)
// userProfile device polls and merges // userProfile device polls and merges
userProfile.merge(arrayOf(newSeqMerge.config)) userProfile.merge("fakehash4" to newSeqMerge.config)
val userConfigMerge = userProfile.push() val userConfigMerge = userProfile.push()
@ -308,14 +310,16 @@ class InstrumentedTests {
val b = UserProfile.newInstance(kp.secretKey) val b = UserProfile.newInstance(kp.secretKey)
a.setName("A") a.setName("A")
val (aPush, aSeq) = a.push() val (aPush, aSeq) = a.push()
a.confirmPushed(aSeq, "hashfroma")
b.setName("B") b.setName("B")
// polls and sees invalid state, has to merge // polls and sees invalid state, has to merge
b.merge(aPush) b.merge("hashfroma" to aPush)
val (bPush, bSeq) = b.push() val (bPush, bSeq) = b.push()
b.confirmPushed(bSeq, "hashfromb")
assertEquals("B", b.getName()) assertEquals("B", b.getName())
assertEquals(1, aSeq) assertEquals(1, aSeq)
assertEquals(2, bSeq) assertEquals(2, bSeq)
a.merge(bPush) a.merge("hashfromb" to bPush)
assertEquals(2, a.push().seqNo) assertEquals(2, a.push().seqNo)
} }
@ -456,11 +460,12 @@ class InstrumentedTests {
val openGroupPubKey = Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") val openGroupPubKey = Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
val og = convos.getOrConstructCommunity("http://Example.ORG:5678", "SudokuRoom", openGroupPubKey) 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("http://example.org:5678", ogCommunity.baseUrl) // Note: lower-case
assertEquals("sudokuroom", og.room) // Note: lower-case assertEquals("sudokuroom", ogCommunity.room) // Note: lower-case
assertEquals(32, og.pubKey.size); assertEquals(64, ogCommunity.pubKeyHex.length)
assertEquals("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", og.pubKeyHex) assertEquals("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", ogCommunity.pubKeyHex)
og.unread = true og.unread = true
@ -470,7 +475,7 @@ class InstrumentedTests {
assertEquals(1, seqNo) assertEquals(1, seqNo)
convos.confirmPushed(seqNo) convos.confirmPushed(seqNo, "fakehash1")
assertTrue(convos.needsDump()) assertTrue(convos.needsDump())
assertFalse(convos.needsPush()) assertFalse(convos.needsPush())
@ -487,9 +492,10 @@ class InstrumentedTests {
assertEquals(false, x1.unread) assertEquals(false, x1.unread)
val x2 = convos2.getCommunity("http://EXAMPLE.org:5678", "sudokuRoom")!! val x2 = convos2.getCommunity("http://EXAMPLE.org:5678", "sudokuRoom")!!
assertEquals("http://example.org:5678", x2.baseUrl) val x2Info = x2.baseCommunityInfo
assertEquals("sudokuroom", x2.room) assertEquals("http://example.org:5678", x2Info.baseUrl)
assertEquals(x2.pubKeyHex, Hex.toStringCondensed(openGroupPubKey)) assertEquals("sudokuroom", x2Info.room)
assertEquals(x2Info.pubKeyHex, Hex.toStringCondensed(openGroupPubKey))
assertTrue(x2.unread) assertTrue(x2.unread)
val anotherId = "051111111111111111111111111111111111111111111111111111111111111111" val anotherId = "051111111111111111111111111111111111111111111111111111111111111111"
@ -508,8 +514,8 @@ class InstrumentedTests {
val (toPush2, seqNo2) = convos2.push() val (toPush2, seqNo2) = convos2.push()
assertEquals(2, seqNo2) assertEquals(2, seqNo2)
convos.merge(toPush2) convos2.confirmPushed(seqNo2, "fakehash2")
convos2.confirmPushed(seqNo2) convos.merge("fakehash2" to toPush2)
assertFalse(convos.needsPush()) assertFalse(convos.needsPush())
assertEquals(seqNo2, convos.push().seqNo) assertEquals(seqNo2, convos.push().seqNo)
@ -527,7 +533,7 @@ class InstrumentedTests {
for (convo in allConvos) { for (convo in allConvos) {
when (convo) { when (convo) {
is Conversation.OneToOne -> seen.add("1-to-1: ${convo.sessionId}") 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}") is Conversation.LegacyGroup -> seen.add("cl: ${convo.groupId}")
} }
} }
@ -551,7 +557,7 @@ class InstrumentedTests {
) )
assertEquals(1, convos.allCommunities().size) assertEquals(1, convos.allCommunities().size)
assertEquals("http://example.org:5678", 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(1, convos.allLegacyClosedGroups().size)
assertEquals("05cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", assertEquals("05cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",

View File

@ -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); jbyteArray returnByteArray = util::bytes_from_ustring(env, to_push_str);
jlong seqNo = std::get<0>(push_tuple); jlong seqNo = std::get<0>(push_tuple);
jclass returnObjectClass = env->FindClass("network/loki/messenger/libsession_util/util/ConfigWithSeqNo"); jclass returnObjectClass = env->FindClass("network/loki/messenger/libsession_util/util/ConfigPush");
jmethodID methodId = env->GetMethodID(returnObjectClass, "<init>", "([BJ)V"); jclass stackClass = env->FindClass("java/util/Stack");
jobject returnObject = env->NewObject(returnObjectClass, methodId, returnByteArray, seqNo); jmethodID methodId = env->GetMethodID(returnObjectClass, "<init>", "([BJLjava/util/List;)V");
jmethodID stack_init = env->GetMethodID(stackClass, "<init>", "()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; return returnObject;
} }

View File

@ -31,7 +31,7 @@ Java_network_loki_messenger_libsession_1util_Contacts_set(JNIEnv *env, jobject t
jobject contact) { jobject contact) {
auto contacts = ptrToContacts(env, thiz); auto contacts = ptrToContacts(env, thiz);
auto contact_info = deserialize_contact(env, contact); auto contact_info = deserialize_contact(env, contact);
contacts->set(*contact_info); contacts->set(contact_info);
} }
extern "C" extern "C"

View File

@ -27,7 +27,7 @@ inline jobject serialize_contact(JNIEnv *env, session::config::contact_info info
return returnObj; 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"); jclass contactClass = env->FindClass("network/loki/messenger/libsession_util/util/Contact");
jfieldID getId, getName, getNick, getApproved, getApprovedMe, getBlocked, getUserPic, getPriority; 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 name_bytes = name ? env->GetStringUTFChars(name, nullptr) : nullptr;
auto nickname_bytes = nickname ? env->GetStringUTFChars(nickname, 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) { if (name_bytes) {
contact_info->name = name_bytes; contact_info.name = name_bytes;
} }
if (nickname_bytes) { if (nickname_bytes) {
contact_info->nickname = nickname_bytes; contact_info.nickname = nickname_bytes;
} }
contact_info->approved = approved; contact_info.approved = approved;
contact_info->approved_me = approvedMe; contact_info.approved_me = approvedMe;
contact_info->blocked = blocked; contact_info.blocked = blocked;
if (!url.empty() && !key.empty()) { 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); 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); env->ReleaseStringUTFChars(nickname, nickname_bytes);
} }
contact_info->priority = priority; contact_info.priority = priority;
return contact_info; return contact_info;
} }

View File

@ -121,13 +121,13 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_set(JNIE
jclass to_store_class = env->GetObjectClass(to_store); jclass to_store_class = env->GetObjectClass(to_store);
if (env->IsSameObject(to_store_class, one_to_one)) { if (env->IsSameObject(to_store_class, one_to_one)) {
// store as 1to1 // 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)) { } else if (env->IsSameObject(to_store_class,open_group)) {
// store as 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)) { } else if (env->IsSameObject(to_store_class,legacy_closed_group)) {
// store as 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" extern "C"
@ -213,8 +213,8 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseCom
jobject thiz, jobject thiz,
jobject open_group) { jobject open_group) {
auto convos = ptrToConvoInfo(env, thiz); auto convos = ptrToConvoInfo(env, thiz);
auto deserialized = deserialize_open_group(env, open_group); auto deserialized = deserialize_community(env, open_group);
return convos->erase(*deserialized); return convos->erase(deserialized);
} }
extern "C" extern "C"
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
@ -269,7 +269,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_erase(JN
jobject conversation) { jobject conversation) {
auto convos = ptrToConvoInfo(env, thiz); auto convos = ptrToConvoInfo(env, thiz);
auto deserialized = deserialize_any(env, conversation); auto deserialized = deserialize_any(env, conversation);
if (deserialized == nullptr) return false; if (!deserialized.has_value()) return false;
return convos->erase(*deserialized); return convos->erase(*deserialized);
} }
extern "C" extern "C"

View File

@ -53,7 +53,7 @@ inline jobject serialize_any(JNIEnv *env, session::config::convo::any any) {
return nullptr; 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 clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne");
auto id_getter = env->GetFieldID(clazz, "sessionId", "Ljava/lang/String;"); auto id_getter = env->GetFieldID(clazz, "sessionId", "Ljava/lang/String;");
auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J"); 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<jstring>(env->GetObjectField(info, id_getter)); jstring id = static_cast<jstring>(env->GetObjectField(info, id_getter));
auto id_chars = env->GetStringUTFChars(id, nullptr); auto id_chars = env->GetStringUTFChars(id, nullptr);
std::string id_string = std::string{id_chars}; std::string id_string = std::string{id_chars};
auto deserialized = new session::config::convo::one_to_one(id_string); auto deserialized = session::config::convo::one_to_one{id_string};
deserialized->last_read = env->GetLongField(info, last_read_getter); deserialized.last_read = env->GetLongField(info, last_read_getter);
deserialized->unread = env->GetBooleanField(info, unread_getter); deserialized.unread = env->GetBooleanField(info, unread_getter);
env->ReleaseStringUTFChars(id, id_chars); env->ReleaseStringUTFChars(id, id_chars);
return deserialized; 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 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 base_community_getter = env->GetFieldID(clazz, "baseCommunityInfo", "Lnetwork/loki/messenger/libsession_util/util/BaseCommunityInfo;");
auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J"); auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J");
auto unread_getter = env->GetFieldID(clazz, "unread", "Z"); auto unread_getter = env->GetFieldID(clazz, "unread", "Z");
auto base_community_info = env->GetObjectField(info, base_community_getter); auto base_community_info = env->GetObjectField(info, base_community_getter);
auto base_community_deserialized = util::deserialize_base_community(env, base_community_info); auto base_community_deserialized = util::deserialize_base_community(env, base_community_info);
auto deserialized = session::config::convo::community{
auto deserialized = new session::config::convo::community{
base_community_deserialized.base_url(), base_community_deserialized.base_url(),
base_community_deserialized.room(), base_community_deserialized.room(),
base_community_deserialized.pubkey() 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; 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 clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyGroup");
auto group_id_getter = env->GetFieldID(clazz, "groupId", "Ljava/lang/String;"); auto group_id_getter = env->GetFieldID(clazz, "groupId", "Ljava/lang/String;");
auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J"); 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<jstring>(env->GetObjectField(info, group_id_getter)); auto group_id = static_cast<jstring>(env->GetObjectField(info, group_id_getter));
auto group_id_bytes = env->GetStringUTFChars(group_id, nullptr); auto group_id_bytes = env->GetStringUTFChars(group_id, nullptr);
auto group_id_string = std::string{group_id_bytes}; auto group_id_string = std::string{group_id_bytes};
auto deserialized = new session::config::convo::legacy_group(group_id_string); auto deserialized = session::config::convo::legacy_group(group_id_string);
deserialized->last_read = env->GetLongField(info, last_read_getter); deserialized.last_read = env->GetLongField(info, last_read_getter);
deserialized->unread = env->GetBooleanField(info, unread_getter); deserialized.unread = env->GetBooleanField(info, unread_getter);
env->ReleaseStringUTFChars(group_id, group_id_bytes); env->ReleaseStringUTFChars(group_id, group_id_bytes);
return deserialized; return deserialized;
} }
inline session::config::convo::any* deserialize_any(JNIEnv *env, jobject convo) { inline std::optional<session::config::convo::any> deserialize_any(JNIEnv *env, jobject convo) {
auto oto_class = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne"); 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 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 lgc_class = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyGroup");
auto object_class = env->GetObjectClass(convo); auto object_class = env->GetObjectClass(convo);
if (env->IsSameObject(object_class, oto_class)) { 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)) { } 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)) { } 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 #endif //SESSION_ANDROID_CONVERSATION_H

View File

@ -1,3 +1,5 @@
#pragma clang diagnostic push
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
#include "user_groups.h" #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( Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_CommunityGroupInfo_2(
JNIEnv *env, jobject thiz, jobject community_info) { JNIEnv *env, jobject thiz, jobject community_info) {
auto conf = ptrToUserGroups(env, thiz); auto conf = ptrToUserGroups(env, thiz);
auto deserialized = (env, community_info); auto deserialized = deserialize_community_info(env, community_info);
conf->set(deserialized); 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) { JNIEnv *env, jobject thiz, jobject legacy_group_info) {
auto conf = ptrToUserGroups(env, thiz); auto conf = ptrToUserGroups(env, thiz);
auto deserialized = deserialize_legacy_group_info(env, legacy_group_info); 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, "<init>", "()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<session::config::legacy_group_info>(&item)) {
serialized = serialize_legacy_group_info(env, *lgc);
} else if (auto* community = std::get_if<session::config::community_info>(&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;
} }

View File

@ -12,7 +12,7 @@ inline session::config::UserGroups* ptrToUserGroups(JNIEnv *env, jobject obj) {
return (session::config::UserGroups*) env->GetLongField(obj, pointerField); 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_class = env->FindClass("java/util/Map");
jclass map_entry_class = env->FindClass("java/util/Map$Entry"); jclass map_entry_class = env->FindClass("java/util/Map$Entry");
jclass set_class = env->FindClass("java/util/Set"); 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); jobject boxed = env->CallObjectMethod(entry, get_value);
bool is_admin = env->CallBooleanMethod(boxed, get_bool_value); bool is_admin = env->CallBooleanMethod(boxed, get_bool_value);
auto member_string = env->GetStringUTFChars(key, nullptr); 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); 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 clazz = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo");
auto id_field = env->GetFieldID(clazz, "sessionId", "Ljava/lang/String;"); auto id_field = env->GetFieldID(clazz, "sessionId", "Ljava/lang/String;");
auto name_field = env->GetFieldID(clazz, "name", "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_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 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); deserialize_members_into(env, members_map, info_deserialized);
info_deserialized->name = name_bytes; info_deserialized.name = name_bytes;
info_deserialized->hidden = hidden; info_deserialized.hidden = hidden;
info_deserialized->enc_pubkey = enc_pub_key_bytes; info_deserialized.enc_pubkey = enc_pub_key_bytes;
info_deserialized->enc_seckey = enc_sec_key_bytes; info_deserialized.enc_seckey = enc_sec_key_bytes;
env->ReleaseStringUTFChars(id, id_bytes); env->ReleaseStringUTFChars(id, id_bytes);
env->ReleaseStringUTFChars(name, name_bytes); env->ReleaseStringUTFChars(name, name_bytes);
return info_deserialized; 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<std::string, bool> members_map) { inline jobject serialize_members(JNIEnv *env, std::map<std::string, bool> members_map) {
jclass map_class = env->FindClass("java/util/HashMap"); jclass map_class = env->FindClass("java/util/HashMap");
jclass boxed_bool = env->FindClass("java/lang/Boolean"); jclass boxed_bool = env->FindClass("java/lang/Boolean");

View File

@ -48,7 +48,23 @@ namespace util {
} }
session::config::community deserialize_base_community(JNIEnv *env, jobject base_community) { 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;
} }
} }

View File

@ -1,6 +1,6 @@
package network.loki.messenger.libsession_util 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.Contact
import network.loki.messenger.libsession_util.util.Conversation import network.loki.messenger.libsession_util.util.Conversation
import network.loki.messenger.libsession_util.util.GroupInfo 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 dirty(): Boolean
external fun needsPush(): Boolean external fun needsPush(): Boolean
external fun needsDump(): Boolean external fun needsDump(): Boolean
external fun push(): ConfigWithSeqNo external fun push(): ConfigPush
external fun dump(): ByteArray external fun dump(): ByteArray
external fun encryptionDomain(): String external fun encryptionDomain(): String
external fun confirmPushed(seqNo: Long, newHash: 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 getOrConstructLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo
external fun set(communityInfo: GroupInfo.CommunityGroupInfo) external fun set(communityInfo: GroupInfo.CommunityGroupInfo)
external fun set(legacyGroupInfo: GroupInfo.LegacyGroupInfo) 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<GroupInfo>
external fun allCommunityInfo(): List<GroupInfo.CommunityGroupInfo>
external fun allLegacyGroupInfo(): List<GroupInfo.LegacyGroupInfo>
} }

View File

@ -1,14 +1,15 @@
package network.loki.messenger.libsession_util.util 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<String>) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (javaClass != other?.javaClass) return false if (javaClass != other?.javaClass) return false
other as ConfigWithSeqNo other as ConfigPush
if (!config.contentEquals(other.config)) return false if (!config.contentEquals(other.config)) return false
if (seqNo != other.seqNo) return false if (seqNo != other.seqNo) return false
if (obsoleteHashes != other.obsoleteHashes) return false
return true return true
} }
@ -16,6 +17,7 @@ data class ConfigWithSeqNo(val config: ByteArray, val seqNo: Long) {
override fun hashCode(): Int { override fun hashCode(): Int {
var result = config.contentHashCode() var result = config.contentHashCode()
result = 31 * result + seqNo.hashCode() result = 31 * result + seqNo.hashCode()
result = 31 * result + obsoleteHashes.hashCode()
return result return result
} }