feat: open group joining should work now

This commit is contained in:
0x330a 2023-03-16 12:15:21 +11:00
parent c28fe290df
commit 061cff8437
No known key found for this signature in database
GPG Key ID: 267811D6E6A2698C
12 changed files with 92 additions and 63 deletions

View File

@ -40,7 +40,7 @@ class JoinOpenGroupDialog(private val name: String, private val url: String) : B
ThreadUtils.queue {
try {
OpenGroupManager.add(openGroup.server, openGroup.room, openGroup.serverPublicKey, activity)
MessagingModuleConfiguration.shared.storage.onOpenGroupAdded(openGroup.server)
MessagingModuleConfiguration.shared.storage.onOpenGroupAdded(openGroup.server, openGroup.room)
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(activity)
} catch (e: Exception) {
Toast.makeText(activity, R.string.activity_join_public_chat_error, Toast.LENGTH_SHORT).show()

View File

@ -7,13 +7,18 @@ import network.loki.messenger.libsession_util.Contacts
import network.loki.messenger.libsession_util.ConversationVolatileConfig
import network.loki.messenger.libsession_util.UserGroupsConfig
import network.loki.messenger.libsession_util.UserProfile
import network.loki.messenger.libsession_util.util.*
import network.loki.messenger.libsession_util.util.BaseCommunityInfo
import network.loki.messenger.libsession_util.util.Conversation
import network.loki.messenger.libsession_util.util.ExpiryMode
import network.loki.messenger.libsession_util.util.GroupInfo
import network.loki.messenger.libsession_util.util.UserPic
import org.session.libsession.avatars.AvatarHelper
import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.BlindedIdMapping
import org.session.libsession.messaging.calls.CallMessageType
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.AttachmentUploadJob
import org.session.libsession.messaging.jobs.BackgroundGroupAddJob
import org.session.libsession.messaging.jobs.ConfigurationSyncJob
import org.session.libsession.messaging.jobs.GroupAvatarDownloadJob
import org.session.libsession.messaging.jobs.Job
@ -64,6 +69,7 @@ import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.messages.SignalServiceAttachmentPointer
import org.session.libsignal.messages.SignalServiceGroup
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.Log
@ -400,8 +406,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
val lgc = userGroups.allLegacyGroupInfo()
val allOpenGroups = getAllOpenGroups()
val toDeleteCommunities = allOpenGroups.filter { it.value.joinURL !in communities.map { it.community.fullUrl() } }
val existingOpenGroups: Map<Long, OpenGroup> = allOpenGroups.filterKeys { it !in toDeleteCommunities.keys }
val existingJoinUrls = existingOpenGroups.values.map { it.joinURL }
val existingCommunities: Map<Long, OpenGroup> = allOpenGroups.filterKeys { it !in toDeleteCommunities.keys }
val toAddCommunities = communities.filter { it.community.fullUrl() !in existingCommunities.map { it.value.joinURL } }
val existingJoinUrls = existingCommunities.values.map { it.joinURL }
val existingClosedGroups = getAllGroups()
val lgcIds = lgc.map { it.sessionId }
val toDeleteClosedGroups = existingClosedGroups.filter { group ->
@ -422,6 +431,14 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
}
}
toAddCommunities.forEach { toAddCommunity ->
val joinUrl = toAddCommunity.community.fullUrl()
if (!hasBackgroundGroupAddJob(joinUrl)) {
Log.d("Loki-DBG", "Doesn't contain background job for open group, adding from config update")
JobQueue.shared.add(BackgroundGroupAddJob(joinUrl))
}
}
for (groupInfo in communities) {
val groupBaseCommunity = groupInfo.community
if (groupBaseCommunity.fullUrl() !in existingJoinUrls) {
@ -429,7 +446,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
val (threadId, _) = OpenGroupManager.add(groupBaseCommunity.baseUrl, groupBaseCommunity.room, groupBaseCommunity.pubKeyHex, context)
threadDb.setPinned(threadId, groupInfo.priority >= 1)
} else {
val (threadId, _) = existingOpenGroups.entries.first { (_, v) -> v.joinURL == groupInfo.community.fullUrl() }
val (threadId, _) = existingCommunities.entries.first { (_, v) -> v.joinURL == groupInfo.community.fullUrl() }
threadDb.setPinned(threadId, groupInfo.priority >= 1)
}
}
@ -699,6 +716,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
val existingGroup = getGroup(groupID)
?: return Log.w("Loki-DBG", "No existing group for ${groupPublicKey.take(4)}...${groupPublicKey.takeLast(4)} when updating group config")
val userGroups = configFactory.userGroups ?: return
if (!existingGroup.isActive) {
userGroups.eraseLegacyGroup(groupPublicKey)
return
}
val name = existingGroup.title
val admins = existingGroup.admins.map { it.serialize() }
val members = existingGroup.members.map { it.serialize() }
@ -855,8 +876,19 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
return OpenGroupManager.addOpenGroup(urlAsString, context)
}
override fun onOpenGroupAdded(server: String) {
override fun onOpenGroupAdded(server: String, room: String) {
OpenGroupManager.restartPollerForServer(server.removeSuffix("/"))
val groups = configFactory.userGroups ?: return
val volatileConfig = configFactory.convoVolatile ?: return
val openGroup = getOpenGroup(room, server) ?: return
val (infoServer, infoRoom, pubKey) = BaseCommunityInfo.parseFullUrl(openGroup.joinURL) ?: return
val pubKeyHex = Hex.toStringCondensed(pubKey)
val communityInfo = groups.getOrConstructCommunityInfo(infoServer, infoRoom, pubKeyHex)
groups.set(communityInfo)
val volatile = volatileConfig.getOrConstructCommunity(infoServer, infoRoom, pubKey).copy(
lastRead = SnodeAPI.nowWithOffset,
)
volatileConfig.set(volatile)
}
override fun hasBackgroundGroupAddJob(groupJoinUrl: String): Boolean {

View File

@ -11,6 +11,7 @@ import org.session.libsession.utilities.ConfigFactoryUpdateListener
import org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage
import org.thoughtcrime.securesms.database.ConfigDatabase
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
import java.util.concurrent.Executors
class ConfigFactory(private val context: Context,
private val configDatabase: ConfigDatabase,
@ -34,6 +35,7 @@ class ConfigFactory(private val context: Context,
private var _convoVolatileConfig: ConversationVolatileConfig? = null
private val userGroupsLock = Object()
private var _userGroups: UserGroupsConfig? = null
private val factoryExecutor = Executors.newSingleThreadExecutor()
private val listeners: MutableList<ConfigFactoryUpdateListener> = mutableListOf()
fun registerListener(listener: ConfigFactoryUpdateListener) { listeners += listener }
@ -127,15 +129,17 @@ class ConfigFactory(private val context: Context,
}
override fun persist(forConfigObject: ConfigBase) {
listeners.forEach { listener ->
listener.notifyUpdates(forConfigObject)
}
when (forConfigObject) {
is UserProfile -> persistUserConfigDump()
is Contacts -> persistContactsConfigDump()
is ConversationVolatileConfig -> persistConvoVolatileConfigDump()
is UserGroupsConfig -> persistUserGroupsConfigDump()
else -> throw UnsupportedOperationException("Can't support type of ${forConfigObject::class.simpleName} yet")
factoryExecutor.submit {
listeners.forEach { listener ->
listener.notifyUpdates(forConfigObject)
}
when (forConfigObject) {
is UserProfile -> persistUserConfigDump()
is Contacts -> persistContactsConfigDump()
is ConversationVolatileConfig -> persistConvoVolatileConfigDump()
is UserGroupsConfig -> persistUserGroupsConfigDump()
else -> throw UnsupportedOperationException("Can't support type of ${forConfigObject::class.simpleName} yet")
}
}
}

View File

@ -79,7 +79,7 @@ class JoinCommunityFragment : Fragment() {
val openGroupID = "$sanitizedServer.${openGroup.room}"
OpenGroupManager.add(sanitizedServer, openGroup.room, openGroup.serverPublicKey, requireContext())
val storage = MessagingModuleConfiguration.shared.storage
storage.onOpenGroupAdded(sanitizedServer)
storage.onOpenGroupAdded(sanitizedServer, openGroup.room)
val threadID = GroupManager.getOpenGroupThreadID(openGroupID, requireContext())
val groupID = GroupUtil.getEncodedOpenGroupID(openGroupID.toByteArray())

View File

@ -3,9 +3,11 @@ package org.thoughtcrime.securesms.sskenvironment
import android.content.Context
import network.loki.messenger.libsession_util.util.UserPic
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.utilities.SessionId
import org.session.libsession.utilities.SSKEnvironment
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.utilities.IdPrefix
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
@ -86,6 +88,8 @@ class ProfileManager(private val context: Context, private val configFactory: Co
override fun contactUpdatedInternal(contact: Contact) {
val contactConfig = configFactory.contacts ?: return
if (contact.sessionID == TextSecurePreferences.getLocalNumber(context)) return
val sessionId = SessionId(contact.sessionID)
if (sessionId.prefix != IdPrefix.STANDARD) return // only internally store standard session IDs
contactConfig.upsertContact(contact.sessionID) {
this.name = contact.name.orEmpty()
this.nickname = contact.nickname.orEmpty()

View File

@ -6,7 +6,11 @@ import network.loki.messenger.libsession_util.Contacts
import network.loki.messenger.libsession_util.ConversationVolatileConfig
import network.loki.messenger.libsession_util.UserGroupsConfig
import network.loki.messenger.libsession_util.UserProfile
import network.loki.messenger.libsession_util.util.*
import network.loki.messenger.libsession_util.util.BaseCommunityInfo
import network.loki.messenger.libsession_util.util.Contact
import network.loki.messenger.libsession_util.util.ExpiryMode
import network.loki.messenger.libsession_util.util.GroupInfo
import network.loki.messenger.libsession_util.util.UserPic
import nl.komponents.kovenant.Promise
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.jobs.ConfigurationSyncJob
@ -17,7 +21,6 @@ import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.utilities.SessionId
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.SSKEnvironment
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.Log
@ -167,6 +170,7 @@ object ConfigurationMessageUtilities {
}
val dump = contactConfig.dump()
contactConfig.free()
if (dump.isEmpty()) return null
return dump
}
@ -177,7 +181,7 @@ object ConfigurationMessageUtilities {
val threadDb = DatabaseComponent.get(context).threadDatabase()
threadDb.approvedConversationList.use { cursor ->
val reader = threadDb.readerFor(cursor)
var current = reader.current
var current = reader.next
while (current != null) {
val recipient = current.recipient
val contact = when {
@ -210,6 +214,7 @@ object ConfigurationMessageUtilities {
val dump = convoConfig.dump()
convoConfig.free()
if (dump.isEmpty()) return null
return dump
}
@ -226,7 +231,7 @@ object ConfigurationMessageUtilities {
GroupInfo.CommunityGroupInfo(baseInfo, if (isPinned) 1 else 0)
}
val allLgc = storage.getAllGroups().filter { it.isClosedGroup }.mapNotNull { group ->
val allLgc = storage.getAllGroups().filter { it.isClosedGroup && it.isActive }.mapNotNull { group ->
val groupAddress = Address.fromSerialized(group.encodedId)
val groupPublicKey = GroupUtil.doubleDecodeGroupID(groupAddress.serialize()).toHexString()
val recipient = storage.getRecipientSettings(groupAddress) ?: return@mapNotNull null
@ -252,6 +257,7 @@ object ConfigurationMessageUtilities {
}
val dump = groupConfig.dump()
groupConfig.free()
if (dump.isEmpty()) return null
return dump
}

View File

@ -29,7 +29,7 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_00024Companion_new
auto* user_groups = new session::config::UserGroups(secret_key, initial);
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/Contacts");
jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/UserGroupsConfig");
jmethodID constructor = env->GetMethodID(contactsClass, "<init>", "(J)V");
jobject newConfig = env->NewObject(contactsClass, constructor, reinterpret_cast<jlong>(user_groups));
@ -126,40 +126,21 @@ Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__Lnetwork_loki
}
}
extern "C"
JNIEXPORT void JNICALL
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__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);
conf->set(deserialized);
}
extern "C"
JNIEXPORT void JNICALL
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_set__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_LegacyGroupInfo_2(
JNIEnv *env, jobject thiz, jobject legacy_group_info) {
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_erase__Lnetwork_loki_messenger_libsession_1util_util_GroupInfo_2(
JNIEnv *env, jobject thiz, jobject group_info) {
auto conf = ptrToUserGroups(env, thiz);
auto deserialized = deserialize_legacy_group_info(env, legacy_group_info, conf);
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);
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);
conf->erase(deserialized);
auto communityInfo = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$CommunityGroupInfo");
auto legacyInfo = env->FindClass("network/loki/messenger/libsession_util/util/GroupInfo$LegacyGroupInfo");
if (env->GetObjectClass(group_info) == communityInfo) {
auto deserialized = deserialize_community_info(env, group_info, conf);
conf->erase(deserialized);
} else if (env->GetObjectClass(group_info) == legacyInfo) {
auto deserialized = deserialize_legacy_group_info(env, group_info, conf);
conf->erase(deserialized);
}
}
extern "C"

View File

@ -1,6 +1,11 @@
package network.loki.messenger.libsession_util
import network.loki.messenger.libsession_util.util.*
import network.loki.messenger.libsession_util.util.BaseCommunityInfo
import network.loki.messenger.libsession_util.util.ConfigPush
import network.loki.messenger.libsession_util.util.Contact
import network.loki.messenger.libsession_util.util.Conversation
import network.loki.messenger.libsession_util.util.GroupInfo
import network.loki.messenger.libsession_util.util.UserPic
import org.session.libsignal.protos.SignalServiceProtos.SharedConfigMessage.Kind
@ -152,10 +157,7 @@ class UserGroupsConfig(pointer: Long): ConfigBase(pointer) {
external fun getOrConstructCommunityInfo(baseUrl: String, room: String, pubKeyHex: String): GroupInfo.CommunityGroupInfo
external fun getOrConstructLegacyGroupInfo(sessionId: String): GroupInfo.LegacyGroupInfo
external fun set(groupInfo: GroupInfo)
external fun set(communityInfo: GroupInfo.CommunityGroupInfo)
external fun set(legacyGroupInfo: GroupInfo.LegacyGroupInfo)
external fun erase(communityInfo: GroupInfo.CommunityGroupInfo)
external fun erase(legacyGroupInfo: GroupInfo.LegacyGroupInfo)
external fun erase(communityInfo: GroupInfo)
external fun eraseCommunity(baseCommunityInfo: BaseCommunityInfo): Boolean
external fun eraseLegacyGroup(sessionId: String): Boolean
external fun sizeCommunityInfo(): Int

View File

@ -72,7 +72,7 @@ interface StorageProtocol {
fun updateOpenGroup(openGroup: OpenGroup)
fun getOpenGroup(threadId: Long): OpenGroup?
fun addOpenGroup(urlAsString: String): OpenGroupApi.RoomInfo?
fun onOpenGroupAdded(server: String)
fun onOpenGroupAdded(server: String, room: String)
fun hasBackgroundGroupAddJob(groupJoinUrl: String): Boolean
fun setOpenGroupServerMessageID(messageID: Long, serverID: Long, threadID: Long, isSms: Boolean)
fun getOpenGroup(room: String, server: String): OpenGroup?

View File

@ -45,7 +45,7 @@ class BackgroundGroupAddJob(val joinUrl: String): Job {
JobQueue.shared.add(GroupAvatarDownloadJob(openGroup.server, openGroup.room, imageId))
}
Log.d(KEY, "onOpenGroupAdded(${openGroup.server})")
storage.onOpenGroupAdded(openGroup.server)
storage.onOpenGroupAdded(openGroup.server, openGroup.room)
} catch (e: Exception) {
Log.e("OpenGroupDispatcher", "Failed to add group because",e)
delegate?.handleJobFailed(this, dispatcherName, e)

View File

@ -165,9 +165,9 @@ private fun handleConfigurationMessage(message: ConfigurationMessage) {
.replace(OpenGroupApi.httpDefaultServer, OpenGroupApi.defaultServer)
}) {
if (allV2OpenGroups.contains(openGroup)) continue
Log.d("OpenGroup", "All open groups doesn't contain $openGroup")
Log.d("OpenGroup", "All open groups doesn't contain open group")
if (!storage.hasBackgroundGroupAddJob(openGroup)) {
Log.d("OpenGroup", "Doesn't contain background job for $openGroup, adding")
Log.d("OpenGroup", "Doesn't contain background job for open group, adding")
JobQueue.shared.add(BackgroundGroupAddJob(openGroup))
}
}

View File

@ -136,9 +136,9 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti
snode,
userPublicKey,
namespace,
updateLatestHash = false,
updateStoredHashes = false,
).filter { (_, hash) -> !forConfigObject.currentHashes().contains(hash) }
updateLatestHash = true,
updateStoredHashes = true,
) // TODO: might not be needed anymore .filter { (_, hash) -> !forConfigObject.currentHashes().contains(hash) }
if (messages.isEmpty()) {
// no new messages to process