mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-29 04:55:15 +00:00
feat: add basic conversation info volatile types and implementations, start working on tests
This commit is contained in:
parent
ee35cadfc6
commit
9bc69f7d54
@ -3,6 +3,7 @@ package network.loki.messenger.libsession_util
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
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.KeyPair
|
import network.loki.messenger.libsession_util.util.KeyPair
|
||||||
import network.loki.messenger.libsession_util.util.Sodium
|
import network.loki.messenger.libsession_util.util.Sodium
|
||||||
import network.loki.messenger.libsession_util.util.UserPic
|
import network.loki.messenger.libsession_util.util.UserPic
|
||||||
@ -329,4 +330,26 @@ class InstrumentedTests {
|
|||||||
userProfile.free()
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -7,13 +7,75 @@ extern "C"
|
|||||||
JNIEXPORT jobject JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Companion_newInstance___3B(
|
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Companion_newInstance___3B(
|
||||||
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key) {
|
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"
|
extern "C"
|
||||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||||
JNIEXPORT jobject JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Companion_newInstance___3B_3B(
|
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Companion_newInstance___3B_3B(
|
||||||
JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key, jbyteArray initial_dump) {
|
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
|
#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;
|
||||||
|
}
|
@ -5,28 +5,108 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "session/config/convo_info_volatile.hpp"
|
#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");
|
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/ConversationVolatileConfig");
|
||||||
jfieldID pointerField = env->GetFieldID(contactsClass, "pointer", "J");
|
jfieldID pointerField = env->GetFieldID(contactsClass, "pointer", "J");
|
||||||
return (session::config::ConvoInfoVolatile *) env->GetLongField(obj, pointerField);
|
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) {
|
inline jobject serialize_one_to_one(JNIEnv *env, session::config::convo::one_to_one *one_to_one) {
|
||||||
// TODO serialize function
|
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) {
|
inline jobject serialize_open_group(JNIEnv *env, session::config::convo::open_group *open_group) {
|
||||||
// TODO
|
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) {
|
inline session::config::convo::one_to_one* deserialize_one_to_one(JNIEnv *env, jobject info) {
|
||||||
// TODO deserialize function
|
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
|
#endif //SESSION_ANDROID_CONVERSATION_H
|
@ -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.ConfigWithSeqNo
|
||||||
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.UserPic
|
import network.loki.messenger.libsession_util.util.UserPic
|
||||||
|
|
||||||
|
|
||||||
@ -56,7 +57,6 @@ class UserProfile(pointer: Long) : ConfigBase(pointer) {
|
|||||||
init {
|
init {
|
||||||
System.loadLibrary("session_util")
|
System.loadLibrary("session_util")
|
||||||
}
|
}
|
||||||
|
|
||||||
external fun newInstance(ed25519SecretKey: ByteArray): UserProfile
|
external fun newInstance(ed25519SecretKey: ByteArray): UserProfile
|
||||||
external fun newInstance(ed25519SecretKey: ByteArray, initialDump: ByteArray): UserProfile
|
external fun newInstance(ed25519SecretKey: ByteArray, initialDump: ByteArray): UserProfile
|
||||||
}
|
}
|
||||||
@ -72,11 +72,31 @@ class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) {
|
|||||||
init {
|
init {
|
||||||
System.loadLibrary("session_util")
|
System.loadLibrary("session_util")
|
||||||
}
|
}
|
||||||
|
|
||||||
external fun newInstance(ed25519SecretKey: ByteArray): ConversationVolatileConfig
|
external fun newInstance(ed25519SecretKey: ByteArray): ConversationVolatileConfig
|
||||||
|
|
||||||
external fun newInstance(ed25519SecretKey: ByteArray, initialDump: 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>
|
||||||
|
|
||||||
}
|
}
|
@ -1,17 +1,22 @@
|
|||||||
package network.loki.messenger.libsession_util.util
|
package network.loki.messenger.libsession_util.util
|
||||||
|
|
||||||
sealed class Conversation {
|
sealed class Conversation {
|
||||||
|
|
||||||
|
abstract val lastRead: Long
|
||||||
|
abstract val unread: Boolean
|
||||||
|
|
||||||
data class OneToOne(
|
data class OneToOne(
|
||||||
val sessionId: String,
|
val sessionId: String,
|
||||||
val lastRead: Long,
|
override val lastRead: Long,
|
||||||
val expiryMode: ExpiryMode,
|
override val unread: Boolean
|
||||||
): Conversation()
|
): Conversation()
|
||||||
|
|
||||||
data class OpenGroup(
|
data class OpenGroup(
|
||||||
val baseUrl: String,
|
val baseUrl: String,
|
||||||
val room: String,
|
val room: String, // lowercase
|
||||||
val pubKey: ByteArray,
|
val pubKey: ByteArray,
|
||||||
val lastRead: Long,
|
override val lastRead: Long,
|
||||||
|
override val unread: Boolean
|
||||||
) : Conversation() {
|
) : Conversation() {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
@ -38,7 +43,7 @@ sealed class Conversation {
|
|||||||
|
|
||||||
data class LegacyClosedGroup(
|
data class LegacyClosedGroup(
|
||||||
val groupId: String,
|
val groupId: String,
|
||||||
val lastRead: Long,
|
override val lastRead: Long,
|
||||||
val expiryMode: ExpiryMode
|
override val unread: Boolean
|
||||||
): Conversation()
|
): Conversation()
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user