mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-25 11:05:25 +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())
|
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"
|
#include "conversation.h"
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
#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"
|
extern "C"
|
||||||
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
#pragma ide diagnostic ignored "bugprone-reserved-identifier"
|
||||||
JNIEXPORT jobject JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
@ -32,15 +52,7 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_00024Com
|
|||||||
return newConfig;
|
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"
|
extern "C"
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
@ -78,4 +90,43 @@ Java_network_loki_messenger_libsession_1util_ConversationVolatileConfig_eraseAll
|
|||||||
}
|
}
|
||||||
|
|
||||||
return removed;
|
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 getOneToOne(pubKeyHex: String): Conversation.OneToOne?
|
||||||
external fun getOrConstructOneToOne(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, 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, pubKey: ByteArray): Conversation.OpenGroup
|
||||||
|
external fun getOrConstructOpenGroup(baseUrl: String, room: String, pubKeyHex: String): Conversation.OpenGroup
|
||||||
|
|
||||||
external fun getLegacyClosedGroup(groupId: String): Conversation.LegacyClosedGroup?
|
external fun getLegacyClosedGroup(groupId: String): Conversation.LegacyClosedGroup?
|
||||||
external fun getOrConstructLegacyClosedGroup(groupId: String): Conversation.LegacyClosedGroup
|
external fun getOrConstructLegacyClosedGroup(groupId: String): Conversation.LegacyClosedGroup
|
||||||
|
|
||||||
external fun erase(conversation: Conversation): Boolean
|
external fun erase(conversation: Conversation): Boolean
|
||||||
|
|
||||||
|
external fun set(toStore: Conversation)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erase all conversations that do not satisfy the `predicate`, similar to [MutableList.removeAll]
|
* 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 sizeOneToOnes(): Int
|
||||||
external fun sizeOpenGroups(): Int
|
external fun sizeOpenGroups(): Int
|
||||||
external fun sizeLegacyClosedGroups(): Int
|
external fun sizeLegacyClosedGroups(): Int
|
||||||
|
external fun size(): Int
|
||||||
|
|
||||||
|
external fun empty(): Boolean
|
||||||
|
|
||||||
external fun all(): List<Conversation>
|
external fun all(): List<Conversation>
|
||||||
|
|
||||||
|
@ -1,23 +1,35 @@
|
|||||||
package network.loki.messenger.libsession_util.util
|
package network.loki.messenger.libsession_util.util
|
||||||
|
|
||||||
|
import org.session.libsignal.utilities.Hex
|
||||||
|
|
||||||
sealed class Conversation {
|
sealed class Conversation {
|
||||||
|
|
||||||
abstract val lastRead: Long
|
abstract var lastRead: Long
|
||||||
abstract val unread: Boolean
|
abstract var unread: Boolean
|
||||||
|
|
||||||
data class OneToOne(
|
data class OneToOne(
|
||||||
val sessionId: String,
|
val sessionId: String,
|
||||||
override val lastRead: Long,
|
override var lastRead: Long,
|
||||||
override val unread: Boolean
|
override var unread: Boolean
|
||||||
): Conversation()
|
): Conversation()
|
||||||
|
|
||||||
data class OpenGroup(
|
data class OpenGroup(
|
||||||
val baseUrl: String,
|
val baseUrl: String,
|
||||||
val room: String, // lowercase
|
val room: String, // lowercase
|
||||||
val pubKey: ByteArray,
|
val pubKey: ByteArray,
|
||||||
override val lastRead: Long,
|
override var lastRead: Long,
|
||||||
override val unread: Boolean
|
override var unread: Boolean
|
||||||
) : Conversation() {
|
) : 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 {
|
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
|
||||||
@ -43,7 +55,7 @@ sealed class Conversation {
|
|||||||
|
|
||||||
data class LegacyClosedGroup(
|
data class LegacyClosedGroup(
|
||||||
val groupId: String,
|
val groupId: String,
|
||||||
override val lastRead: Long,
|
override var lastRead: Long,
|
||||||
override val unread: Boolean
|
override var unread: Boolean
|
||||||
): Conversation()
|
): Conversation()
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user