feat: add basic conversation info volatile types and implementations, start working on tests

This commit is contained in:
0x330a 2023-01-31 18:16:59 +11:00
parent ee35cadfc6
commit 9bc69f7d54
No known key found for this signature in database
GPG Key ID: 267811D6E6A2698C
5 changed files with 211 additions and 21 deletions

View File

@ -3,6 +3,7 @@ package network.loki.messenger.libsession_util
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import network.loki.messenger.libsession_util.util.Contact
import network.loki.messenger.libsession_util.util.Conversation
import network.loki.messenger.libsession_util.util.KeyPair
import network.loki.messenger.libsession_util.util.Sodium
import network.loki.messenger.libsession_util.util.UserPic
@ -329,4 +330,26 @@ class InstrumentedTests {
userProfile.free()
}
@Test
fun jni_remove_all_test() {
val convos = ConversationVolatileConfig.newInstance(keyPair.secretKey)
assertEquals(0 /* number removed */, convos.eraseAll { true /* 'erase' every item */ })
val definitelyRealId = "050000000000000000000000000000000000000000000000000000000000000000"
val definitelyRealConvo = Conversation.OneToOne(definitelyRealId, System.currentTimeMillis(), false)
convos.set(definitelyRealConvo)
val anotherDefinitelyReadId = "051111111111111111111111111111111111111111111111111111111111111111"
val anotherDefinitelyRealConvo = Conversation.OneToOne(anotherDefinitelyReadId, System.currentTimeMillis(), false)
convos.set(anotherDefinitelyRealConvo)
assertEquals(2, convos.sizeOneToOnes())
val numErased = convos.eraseAll { convo ->
convo is Conversation.OneToOne && convo.sessionId == definitelyRealId
}
assertEquals(1, numErased)
assertEquals(1, convos.sizeOneToOnes())
}
}

View File

@ -7,13 +7,75 @@ extern "C"
JNIEXPORT jobject JNICALL
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Companion_newInstance___3B(
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key) {
auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key);
auto* convo_info_volatile = new session::config::ConvoInfoVolatile(secret_key, std::nullopt);
jclass convoClass = env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig");
jmethodID constructor = env->GetMethodID(convoClass, "<init>", "(J)V");
jobject newConfig = env->NewObject(convoClass, constructor, reinterpret_cast<jlong>(convo_info_volatile));
return newConfig;
}
extern "C"
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
JNIEXPORT jobject JNICALL
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Companion_newInstance___3B_3B(
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key, jbyteArray initial_dump) {
auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key);
auto initial = util::ustring_from_bytes(env, initial_dump);
auto* convo_info_volatile = new session::config::ConvoInfoVolatile(secret_key, initial);
jclass convoClass = env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig");
jmethodID constructor = env->GetMethodID(convoClass, "<init>", "(J)V");
jobject newConfig = env->NewObject(convoClass, constructor, reinterpret_cast<jlong>(convo_info_volatile));
return newConfig;
}
extern "C"
JNIEXPORT void JNICALL
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_set(JNIEnv *env,
jobject thiz,
jobject to_store) {
auto conversations = ptrToConvoInfo(env, thiz);
auto one_to_one = deserialize_one_to_one(env, to_store);
conversations->set(*one_to_one);
}
extern "C"
JNIEXPORT jint JNICALL
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_sizeOneToOnes(JNIEnv *env,
jobject thiz) {
auto conversations = ptrToConvoInfo(env, thiz);
return conversations->size_1to1();
}
#pragma clang diagnostic pop
extern "C"
JNIEXPORT jint JNICALL
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseAll(JNIEnv *env,
jobject thiz,
jobject predicate) {
auto conversations = ptrToConvoInfo(env, thiz);
jclass predicate_class = env->FindClass("kotlin/jvm/functions/Function1");
jmethodID predicate_call = env->GetMethodID(predicate_class, "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;");
jclass bool_class = env->FindClass("java/lang/Boolean");
jfieldID bool_value = env->GetFieldID(bool_class, "value", "Z");
int removed = 0;
for (auto it = conversations->begin(); it != conversations->end(); ) {
auto result = env->CallObjectMethod(predicate, predicate_call, serialize_any(env, *it));
bool bool_result = env->GetBooleanField(result, bool_value);
if (bool_result) {
it = conversations->erase(it);
removed++;
} else {
++it;
}
}
return removed;
}

View File

@ -5,28 +5,108 @@
#include "util.h"
#include "session/config/convo_info_volatile.hpp"
inline session::config::ConvoInfoVolatile *ptrToContacts(JNIEnv *env, jobject obj) {
inline session::config::ConvoInfoVolatile *ptrToConvoInfo(JNIEnv *env, jobject obj) {
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig");
jfieldID pointerField = env->GetFieldID(contactsClass, "pointer", "J");
return (session::config::ConvoInfoVolatile *) env->GetLongField(obj, pointerField);
}
inline jobject serialize_one_on_one(JNIEnv *env, session::config::convo::one_to_one one_to_one) {
// TODO serialize function
inline jobject serialize_one_to_one(JNIEnv *env, session::config::convo::one_to_one *one_to_one) {
jclass clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne");
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;JZ)V");
auto session_id = env->NewStringUTF(one_to_one->session_id.data());
auto last_read = one_to_one->last_read;
auto unread = one_to_one->unread;
jobject serialized = env->NewObject(clazz, constructor, session_id, last_read, unread);
return serialized;
}
inline jobject serialize_open_group(JNIEnv *env, session::config::convo::open_group open_group) {
// TODO
inline jobject serialize_open_group(JNIEnv *env, session::config::convo::open_group *open_group) {
jclass clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OpenGroup");
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;Ljava/lang/String;[BJZ)V");
auto base_url = env->NewStringUTF(open_group->base_url().data());
auto room = env->NewStringUTF(open_group->room().data());
auto pubkey_ustring = open_group->pubkey();
auto pubkey_jarray = util::bytes_from_ustring(env, session::ustring_view {pubkey_ustring.data(), pubkey_ustring.size()});
auto last_read = open_group->last_read;
auto unread = open_group->unread;
jobject serialized = env->NewObject(clazz, constructor, base_url, room, pubkey_jarray, last_read, unread);
return serialized;
}
inline jobject serialize_legacy_group(JNIEnv *env, session::config::convo::legacy_closed_group legacy_group) {
inline jobject serialize_legacy_group(JNIEnv *env, session::config::convo::legacy_closed_group *legacy_group) {
jclass clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyClosedGroup");
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;JZ)V");
auto group_id = env->NewStringUTF(legacy_group->id.data());
auto last_read = legacy_group->last_read;
auto unread = legacy_group->unread;
jobject serialized = env->NewObject(clazz, constructor, group_id, last_read, unread);
return serialized;
}
inline jobject serialize_any(JNIEnv *env, session::config::convo::any)
inline jobject serialize_any(JNIEnv *env, session::config::convo::any any) {
if (auto* dm = std::get_if<session::config::convo::one_to_one>(&any)) {
return serialize_one_to_one(env, dm);
} else if (auto* og = std::get_if<session::config::convo::open_group>(&any)) {
return serialize_open_group(env, og);
} else if (auto* lgc = std::get_if<session::config::convo::legacy_closed_group>(&any)) {
return serialize_legacy_group(env, lgc);
}
return nullptr;
}
inline session::config::ConvoInfoVolatile* deserialize_convo_info(JNIEnv *env, jobject info) {
// TODO deserialize function
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");
auto unread_getter = env->GetFieldID(clazz, "unread", "Z");
jstring id = static_cast<jstring>(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);
env->ReleaseStringUTFChars(id, id_chars);
return deserialized;
}
inline session::config::convo::open_group* deserialize_open_group(JNIEnv *env, jobject info) {
auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OpenGroup");
auto url_getter = env->GetFieldID(clazz, "baseUrl", "Ljava/lang/String;");
auto room_getter = env->GetFieldID(clazz, "room", "Ljava/lang/String;");
auto pub_key_getter = env->GetFieldID(clazz, "pubKey", "[B");
auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J");
auto unread_getter = env->GetFieldID(clazz, "unread", "Z");
jstring base_url = static_cast<jstring>(env->GetObjectField(info, url_getter));
jstring room = static_cast<jstring>(env->GetObjectField(info, room_getter));
jbyteArray pub_key = (jbyteArray)env->GetObjectField(info, pub_key_getter);
auto base_bytes = env->GetStringUTFChars(base_url, nullptr);
auto base_string = std::string {base_bytes};
auto room_bytes = env->GetStringUTFChars(room, nullptr);
auto room_string = std::string {room_bytes};
auto pub_key_ustring = util::ustring_from_bytes(env, pub_key);
auto deserialized = new session::config::convo::open_group(base_string, room_string,pub_key_ustring);
deserialized->last_read = env->GetLongField(info, last_read_getter);
deserialized->unread = env->GetBooleanField(info, unread_getter);
env->ReleaseStringUTFChars(base_url, base_bytes);
env->ReleaseStringUTFChars(room, room_bytes);
return deserialized;
}
inline session::config::convo::legacy_closed_group* deserialize_legacy_closed_group(JNIEnv *env, jobject info) {
auto clazz = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyClosedGroup");
auto group_id_getter = env->GetFieldID(clazz, "groupId", "Ljava/lang/String;");
auto last_read_getter = env->GetFieldID(clazz, "lastRead", "J");
auto unread_getter = env->GetFieldID(clazz, "unread", "Z");
auto group_id = static_cast<jstring>(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_closed_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;
}
#endif //SESSION_ANDROID_CONVERSATION_H

View File

@ -2,6 +2,7 @@ package network.loki.messenger.libsession_util
import network.loki.messenger.libsession_util.util.ConfigWithSeqNo
import network.loki.messenger.libsession_util.util.Contact
import network.loki.messenger.libsession_util.util.Conversation
import network.loki.messenger.libsession_util.util.UserPic
@ -56,7 +57,6 @@ class UserProfile(pointer: Long) : ConfigBase(pointer) {
init {
System.loadLibrary("session_util")
}
external fun newInstance(ed25519SecretKey: ByteArray): UserProfile
external fun newInstance(ed25519SecretKey: ByteArray, initialDump: ByteArray): UserProfile
}
@ -72,11 +72,31 @@ class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) {
init {
System.loadLibrary("session_util")
}
external fun newInstance(ed25519SecretKey: ByteArray): ConversationVolatileConfig
external fun newInstance(ed25519SecretKey: ByteArray, initialDump: ByteArray): ConversationVolatileConfig
}
external fun getOneToOne(pubKeyHex: String): Conversation.OneToOne?
external fun getOrConstructOneToOne(pubKeyHex: String): Conversation.OneToOne
external fun set(toStore: Conversation.OneToOne)
external fun getOpenGroup(baseUrl: String, room: String, pubKeyHex: String): Conversation.OpenGroup?
external fun getOrConstructOpenGroup(baseUrl: String, room: String, pubKey: ByteArray): Conversation.OpenGroup
external fun getLegacyClosedGroup(groupId: String): Conversation.LegacyClosedGroup?
external fun getOrConstructLegacyClosedGroup(groupId: String): Conversation.LegacyClosedGroup
external fun erase(conversation: Conversation): Boolean
/**
* Erase all conversations that do not satisfy the `predicate`, similar to [MutableList.removeAll]
*/
external fun eraseAll(predicate: (Conversation) -> Boolean): Int
external fun sizeOneToOnes(): Int
external fun sizeOpenGroups(): Int
external fun sizeLegacyClosedGroups(): Int
external fun all(): List<Conversation>
}

View File

@ -1,17 +1,22 @@
package network.loki.messenger.libsession_util.util
sealed class Conversation {
abstract val lastRead: Long
abstract val unread: Boolean
data class OneToOne(
val sessionId: String,
val lastRead: Long,
val expiryMode: ExpiryMode,
override val lastRead: Long,
override val unread: Boolean
): Conversation()
data class OpenGroup(
val baseUrl: String,
val room: String,
val room: String, // lowercase
val pubKey: ByteArray,
val lastRead: Long,
override val lastRead: Long,
override val unread: Boolean
) : Conversation() {
override fun equals(other: Any?): Boolean {
if (this === other) return true
@ -38,7 +43,7 @@ sealed class Conversation {
data class LegacyClosedGroup(
val groupId: String,
val lastRead: Long,
val expiryMode: ExpiryMode
override val lastRead: Long,
override val unread: Boolean
): Conversation()
}