mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-28 20:45:17 +00:00
feat: more common library wrapper implementation and test
This commit is contained in:
parent
9bc69f7d54
commit
74b2486e92
@ -352,4 +352,199 @@ class InstrumentedTests {
|
||||
assertEquals(1, convos.sizeOneToOnes())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_open_group_urls() {
|
||||
val (base1, room1, pk1) = Conversation.OpenGroup.parseFullUrl(
|
||||
"https://example.com/" +
|
||||
"SomeRoom?public_key=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
)!!
|
||||
|
||||
val (base2, room2, pk2) = Conversation.OpenGroup.parseFullUrl(
|
||||
"HTTPS://EXAMPLE.COM/" +
|
||||
"sOMErOOM?public_key=0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base3, room3, pk3) = Conversation.OpenGroup.parseFullUrl(
|
||||
"HTTPS://EXAMPLE.COM/r/" +
|
||||
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base4, room4, pk4) = Conversation.OpenGroup.parseFullUrl(
|
||||
"http://example.com/r/" +
|
||||
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base5, room5, pk5) = Conversation.OpenGroup.parseFullUrl(
|
||||
"HTTPS://EXAMPLE.com:443/r/" +
|
||||
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base6, room6, pk6) = Conversation.OpenGroup.parseFullUrl(
|
||||
"HTTP://EXAMPLE.com:80/r/" +
|
||||
"someroom?public_key=0123456789aBcdEF0123456789abCDEF0123456789ABCdef0123456789ABCDEF"
|
||||
)!!
|
||||
|
||||
val (base7, room7, pk7) = Conversation.OpenGroup.parseFullUrl(
|
||||
"http://example.com:80/r/" +
|
||||
"someroom?public_key=ASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8"
|
||||
)!!
|
||||
val (base8, room8, pk8) = Conversation.OpenGroup.parseFullUrl(
|
||||
"http://example.com:80/r/" +
|
||||
"someroom?public_key=yrtwk3hjixg66yjdeiuauk6p7hy1gtm8tgih55abrpnsxnpm3zzo"
|
||||
)!!
|
||||
|
||||
assertEquals("https://example.com", base1)
|
||||
assertEquals(base1, base2)
|
||||
assertEquals(base1, base3)
|
||||
assertNotEquals(base1, base4)
|
||||
assertEquals(base4, "http://example.com")
|
||||
assertEquals(base1, base5)
|
||||
assertEquals(base4, base6)
|
||||
assertEquals(base4, base7)
|
||||
assertEquals(base4, base8)
|
||||
assertEquals(room1, "someroom")
|
||||
assertEquals(room2, "someroom")
|
||||
assertEquals(room3, "someroom")
|
||||
assertEquals(room4, "someroom")
|
||||
assertEquals(room5, "someroom")
|
||||
assertEquals(room6, "someroom")
|
||||
assertEquals(room7, "someroom")
|
||||
assertEquals(room8, "someroom")
|
||||
assertEquals(Hex.toStringCondensed(pk1), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk2), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk3), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk4), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk5), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk6), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk7), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assertEquals(Hex.toStringCondensed(pk8), "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_conversations() {
|
||||
val convos = ConversationVolatileConfig.newInstance(keyPair.secretKey)
|
||||
val definitelyRealId = "055000000000000000000000000000000000000000000000000000000000000000"
|
||||
assertNull(convos.getOneToOne(definitelyRealId))
|
||||
assertTrue(convos.empty())
|
||||
assertEquals(0, convos.size())
|
||||
|
||||
val c = convos.getOrConstructOneToOne(definitelyRealId)
|
||||
|
||||
assertEquals(definitelyRealId, c.sessionId)
|
||||
assertEquals(0, c.lastRead)
|
||||
|
||||
assertFalse(convos.needsPush())
|
||||
assertFalse(convos.needsDump())
|
||||
assertEquals(0, convos.push().seqNo)
|
||||
|
||||
val nowMs = System.currentTimeMillis()
|
||||
|
||||
c.lastRead = nowMs
|
||||
|
||||
convos.set(c)
|
||||
|
||||
assertNull(convos.getLegacyClosedGroup(definitelyRealId))
|
||||
assertNotNull(convos.getOneToOne(definitelyRealId))
|
||||
assertEquals(nowMs, convos.getOneToOne(definitelyRealId)?.lastRead)
|
||||
|
||||
assertTrue(convos.needsPush())
|
||||
assertTrue(convos.needsDump())
|
||||
|
||||
val openGroupPubKey = Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
|
||||
val og = convos.getOrConstructOpenGroup("http://Example.ORG:5678", "SudokuRoom", openGroupPubKey)
|
||||
|
||||
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)
|
||||
|
||||
og.unread = true
|
||||
|
||||
convos.set(og)
|
||||
|
||||
val (toPush, seqNo) = convos.push()
|
||||
|
||||
assertEquals(1, seqNo)
|
||||
|
||||
convos.confirmPushed(seqNo)
|
||||
|
||||
assertTrue(convos.needsDump())
|
||||
assertFalse(convos.needsPush())
|
||||
|
||||
val convos2 = ConversationVolatileConfig.newInstance(keyPair.secretKey, toPush)
|
||||
assertFalse(convos.needsPush())
|
||||
assertFalse(convos.needsDump())
|
||||
assertEquals(1, convos.push().seqNo)
|
||||
assertFalse(convos.needsDump())
|
||||
|
||||
val x1 = convos2.getOneToOne(definitelyRealId)!!
|
||||
assertEquals(nowMs, x1.lastRead)
|
||||
assertEquals(definitelyRealId, x1.sessionId)
|
||||
assertEquals(false, x1.unread)
|
||||
|
||||
val x2 = convos2.getOpenGroup("http://EXAMPLE.org:5678", "sudokuRoom", openGroupPubKey)!!
|
||||
assertEquals("http://example.org:5678", x2.baseUrl)
|
||||
assertEquals("sudokuroom", x2.room)
|
||||
assertEquals(x2.pubKeyHex, Hex.toStringCondensed(openGroupPubKey))
|
||||
assertTrue(x2.unread)
|
||||
|
||||
val anotherId = "051111111111111111111111111111111111111111111111111111111111111111"
|
||||
val c2 = convos.getOrConstructLegacyClosedGroup(anotherId)
|
||||
c2.unread = true
|
||||
convos2.set(c2)
|
||||
|
||||
val c3 = convos.getOrConstructLegacyClosedGroup(
|
||||
"05cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
||||
)
|
||||
c3.lastRead = nowMs - 50
|
||||
convos2.set(c3)
|
||||
|
||||
assertTrue(convos2.needsPush())
|
||||
|
||||
val (toPush2, seqNo2) = convos2.push()
|
||||
assertEquals(2, seqNo2)
|
||||
|
||||
convos.merge(toPush2)
|
||||
convos2.confirmPushed(seqNo2)
|
||||
|
||||
assertFalse(convos.needsPush())
|
||||
assertEquals(seqNo2, convos.push().seqNo)
|
||||
|
||||
val seen = mutableListOf<String>()
|
||||
for (conv in listOf(convos, convos2)) {
|
||||
seen.clear()
|
||||
assertEquals(4, conv.size())
|
||||
assertEquals(2, conv.sizeOneToOnes())
|
||||
assertEquals(1, conv.sizeOpenGroups())
|
||||
assertEquals(1, conv.sizeLegacyClosedGroups())
|
||||
assertFalse(conv.empty())
|
||||
for (convo in conv.all()) {
|
||||
when (convo) {
|
||||
is Conversation.OneToOne -> seen.add("1-to-1: ${convo.sessionId}")
|
||||
is Conversation.OpenGroup -> seen.add("og: ${convo.baseUrl}/r/${convo.room}")
|
||||
is Conversation.LegacyClosedGroup -> seen.add("cl: ${convo.groupId}")
|
||||
}
|
||||
}
|
||||
assertEquals(listOf(
|
||||
"1-to-1: " +
|
||||
"051111111111111111111111111111111111111111111111111111111111111111",
|
||||
"1-to-1: " +
|
||||
"055000000000000000000000000000000000000000000000000000000000000000",
|
||||
"og: http://example.org:5678/r/sudokuroom",
|
||||
"cl: " +
|
||||
"05ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
||||
), seen)
|
||||
}
|
||||
|
||||
assertFalse(convos.needsPush())
|
||||
convos.eraseOneToOne("052000000000000000000000000000000000000000000000000000000000000000")
|
||||
assertFalse(convos.needsPush())
|
||||
convos.eraseOneToOne("055000000000000000000000000000000000000000000000000000000000000000")
|
||||
assertTrue(convos.needsPush())
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,26 @@
|
||||
#include "conversation.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_util_Conversation_00024OpenGroup_00024Companion_parseFullUrl(
|
||||
JNIEnv *env, jobject thiz, jstring full_url) {
|
||||
auto bytes = env->GetStringUTFChars(full_url, nullptr);
|
||||
auto [base, room, pk] = session::config::convo::open_group::parse_full_url(bytes);
|
||||
env->ReleaseStringUTFChars(full_url, bytes);
|
||||
|
||||
jclass clazz = env->FindClass("kotlin/Triple");
|
||||
jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||
|
||||
auto base_j = env->NewStringUTF(base.data());
|
||||
auto room_j = env->NewStringUTF(room.data());
|
||||
auto pk_jbytes = util::bytes_from_ustring(env, pk);
|
||||
|
||||
jobject triple = env->NewObject(clazz, constructor, base_j, room_j, pk_jbytes);
|
||||
return triple;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||
JNIEXPORT jobject JNICALL
|
||||
@ -32,15 +52,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Com
|
||||
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
|
||||
@ -79,3 +91,42 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseAll
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_size(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
auto config = ptrToConvoInfo(env, thiz);
|
||||
return (jint)config->size();
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_empty(JNIEnv *env,
|
||||
jobject thiz) {
|
||||
auto config = ptrToConvoInfo(env, thiz);
|
||||
return config->empty();
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_set(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject to_store) {
|
||||
|
||||
auto convos = ptrToConvoInfo(env, thiz);
|
||||
|
||||
jclass one_to_one = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OneToOne");
|
||||
jclass open_group = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$OpenGroup");
|
||||
jclass legacy_closed_group = env->FindClass("network/loki/messenger/libsession_util/util/Conversation$LegacyClosedGroup");
|
||||
|
||||
jclass to_store_class = env->GetObjectClass(to_store);
|
||||
if (to_store_class == one_to_one) {
|
||||
// store as 1to1
|
||||
convos->set(*deserialize_one_to_one(env, to_store));
|
||||
} else if (to_store_class == open_group) {
|
||||
// store as open_group
|
||||
convos->set(*deserialize_open_group(env, to_store));
|
||||
} else if (to_store_class == legacy_closed_group) {
|
||||
// store as legacy_closed_group
|
||||
convos->set(*deserialize_legacy_closed_group(env, to_store));
|
||||
}
|
||||
}
|
@ -78,16 +78,18 @@ class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) {
|
||||
|
||||
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 getOpenGroup(baseUrl: String, room: String, pubKey: ByteArray): Conversation.OpenGroup?
|
||||
external fun getOrConstructOpenGroup(baseUrl: String, room: String, pubKey: ByteArray): Conversation.OpenGroup
|
||||
external fun getOrConstructOpenGroup(baseUrl: String, room: String, pubKeyHex: String): Conversation.OpenGroup
|
||||
|
||||
external fun getLegacyClosedGroup(groupId: String): Conversation.LegacyClosedGroup?
|
||||
external fun getOrConstructLegacyClosedGroup(groupId: String): Conversation.LegacyClosedGroup
|
||||
|
||||
external fun erase(conversation: Conversation): Boolean
|
||||
|
||||
external fun set(toStore: Conversation)
|
||||
|
||||
/**
|
||||
* Erase all conversations that do not satisfy the `predicate`, similar to [MutableList.removeAll]
|
||||
*/
|
||||
@ -96,6 +98,9 @@ class ConversationVolatileConfig(pointer: Long): ConfigBase(pointer) {
|
||||
external fun sizeOneToOnes(): Int
|
||||
external fun sizeOpenGroups(): Int
|
||||
external fun sizeLegacyClosedGroups(): Int
|
||||
external fun size(): Int
|
||||
|
||||
external fun empty(): Boolean
|
||||
|
||||
external fun all(): List<Conversation>
|
||||
|
||||
|
@ -1,23 +1,35 @@
|
||||
package network.loki.messenger.libsession_util.util
|
||||
|
||||
import org.session.libsignal.utilities.Hex
|
||||
|
||||
sealed class Conversation {
|
||||
|
||||
abstract val lastRead: Long
|
||||
abstract val unread: Boolean
|
||||
abstract var lastRead: Long
|
||||
abstract var unread: Boolean
|
||||
|
||||
data class OneToOne(
|
||||
val sessionId: String,
|
||||
override val lastRead: Long,
|
||||
override val unread: Boolean
|
||||
override var lastRead: Long,
|
||||
override var unread: Boolean
|
||||
): Conversation()
|
||||
|
||||
data class OpenGroup(
|
||||
val baseUrl: String,
|
||||
val room: String, // lowercase
|
||||
val pubKey: ByteArray,
|
||||
override val lastRead: Long,
|
||||
override val unread: Boolean
|
||||
override var lastRead: Long,
|
||||
override var unread: Boolean
|
||||
) : Conversation() {
|
||||
|
||||
val pubKeyHex: String
|
||||
get() = Hex.toStringCondensed(pubKey)
|
||||
companion object {
|
||||
init {
|
||||
System.loadLibrary("session_util")
|
||||
}
|
||||
external fun parseFullUrl(fullUrl: String): Triple<String, String, ByteArray>?
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
@ -43,7 +55,7 @@ sealed class Conversation {
|
||||
|
||||
data class LegacyClosedGroup(
|
||||
val groupId: String,
|
||||
override val lastRead: Long,
|
||||
override val unread: Boolean
|
||||
override var lastRead: Long,
|
||||
override var unread: Boolean
|
||||
): Conversation()
|
||||
}
|
Loading…
Reference in New Issue
Block a user