feat: fix the invite order properly

This commit is contained in:
0x330a 2023-11-20 16:45:55 +11:00
parent cc24542af3
commit d162522ac2
No known key found for this signature in database
GPG Key ID: 267811D6E6A2698C
7 changed files with 108 additions and 20 deletions

View File

@ -19,6 +19,7 @@ import network.loki.messenger.libsession_util.util.ExpiryMode
import network.loki.messenger.libsession_util.util.GroupDisplayInfo
import network.loki.messenger.libsession_util.util.GroupInfo
import network.loki.messenger.libsession_util.util.UserPic
import nl.komponents.kovenant.functional.bind
import org.session.libsession.avatars.AvatarHelper
import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.BlindedIdMapping
@ -1277,7 +1278,78 @@ open class Storage(
override fun inviteClosedGroupMembers(groupSessionId: String, invitees: List<String>) {
// don't try to process invitee acceptance if we aren't admin
if (configFactory.userGroups?.getClosedGroup(groupSessionId)?.hasAdminKey() != true) return
val infoConfig = configFactory
val adminKey = configFactory.userGroups?.getClosedGroup(groupSessionId)?.adminKey ?: return
val sessionId = SessionId.from(groupSessionId)
val membersConfig = configFactory.getGroupMemberConfig(sessionId) ?: return
val infoConfig = configFactory.getGroupInfoConfig(sessionId) ?: return
val filteredMembers = invitees.filter {
membersConfig.get(it) == null
}
filteredMembers.forEach { memberSessionId ->
val member = membersConfig.getOrConstruct(memberSessionId).copy(
invitePending = true,
)
membersConfig.set(member)
}
val keysConfig = configFactory.getGroupKeysConfig(
sessionId,
info = infoConfig,
members = membersConfig,
free = false
) ?: return
keysConfig.rekey(infoConfig, membersConfig)
val sentTimestamp = SnodeAPI.nowWithOffset
val message = SnodeMessage(
groupSessionId,
Base64.encodeBytes(keysConfig.pendingConfig()!!), // should not be null from checking has pending
SnodeMessage.CONFIG_TTL,
sentTimestamp
)
val authenticatedBatch = SnodeAPI.buildAuthenticatedStoreBatchInfo(
keysConfig.namespace(),
message,
adminKey
)
val response = SnodeAPI.getSingleTargetSnode(groupSessionId).bind { snode ->
SnodeAPI.getRawBatchResponse(
snode,
groupSessionId,
listOf(authenticatedBatch),
)
}
val destination = Destination.ClosedGroup(groupSessionId)
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(destination)
try {
response.get()
} catch (e: Exception) {
Log.e("ClosedGroup", "Failed to store new key", e)
infoConfig.free()
membersConfig.free()
keysConfig.free()
// toaster toast here
return
}
configFactory.saveGroupConfigs(keysConfig, infoConfig, membersConfig)
infoConfig.free()
membersConfig.free()
keysConfig.free()
val newConfigSync = ConfigurationSyncJob(destination)
JobQueue.shared.add(newConfigSync)
val job = InviteContactsJob(groupSessionId, filteredMembers.toTypedArray())
JobQueue.shared.add(job)
}
override fun setServerCapabilities(server: String, capabilities: List<String>) {

View File

@ -221,6 +221,8 @@ class ConfigFactory(
info?.free()
members?.free()
}
if (usedInfo !== info) usedInfo.free()
if (usedMembers !== members) usedMembers.free()
keys
}

View File

@ -48,8 +48,6 @@ import network.loki.messenger.R
import network.loki.messenger.libsession_util.util.GroupMember
import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.InviteContactsJob
import org.session.libsession.messaging.jobs.JobQueue
import org.thoughtcrime.securesms.groups.ContactList
import org.thoughtcrime.securesms.groups.destinations.EditClosedGroupInviteScreenDestination
import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
@ -98,7 +96,6 @@ fun EditClosedGroupInviteScreen(
val state by viewModel.viewState.collectAsState()
val viewState = state.viewState
val currentMemberSessionIds = viewState.currentMembers.map { it.memberSessionId }
val eventSink = state.eventSink
SelectContacts(
viewState.allContacts
@ -156,15 +153,10 @@ class EditGroupViewModel @AssistedInject constructor(
when (event) {
is EditGroupEvent.InviteContacts -> {
val sessionIds = event.contacts
val invite = InviteContactsJob(
groupSessionId,
sessionIds.contacts.map(Contact::sessionID).toTypedArray()
)
storage.inviteClosedGroupMembers(
groupSessionId,
sessionIds.contacts.map(Contact::sessionID)
)
JobQueue.shared.add(invite)
Toast.makeText(
event.context,
"Inviting ${event.contacts.contacts.size}",
@ -210,9 +202,7 @@ class EditGroupInviteViewModel @AssistedInject constructor(
EditGroupInviteState(
EditGroupInviteViewState(closedGroupMembers, contacts)
) { event ->
}
)
}
@AssistedFactory
@ -321,7 +311,6 @@ data class EditGroupState(
data class EditGroupInviteState(
val viewState: EditGroupInviteViewState,
val eventSink: (Unit) -> Unit
)
data class MemberViewModel(

View File

@ -104,6 +104,8 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_needsDump(JNIEnv *e
return keys->needs_dump();
}
extern "C"
JNIEXPORT jbyteArray JNICALL
Java_network_loki_messenger_libsession_1util_GroupKeysConfig_pendingKey(JNIEnv *env, jobject thiz) {
@ -257,4 +259,18 @@ Java_network_loki_messenger_libsession_1util_GroupKeysConfig_subAccountSign(JNIE
auto signing_value_ustring = util::ustring_from_bytes(env, signing_value);
auto swarm_auth = ptr->swarm_subaccount_sign(message_ustring, signing_value_ustring, false);
return util::deserialize_swarm_auth(env, swarm_auth);
}
extern "C"
JNIEXPORT jbyteArray JNICALL
Java_network_loki_messenger_libsession_1util_GroupKeysConfig_supplementFor(JNIEnv *env,
jobject thiz,
jstring user_session_id) {
std::lock_guard lock{util::util_mutex_};
auto ptr = ptrToKeys(env, thiz);
auto string = env->GetStringUTFChars(user_session_id, nullptr);
auto supplement = ptr->key_supplement(string);
auto supplement_jbytearray = util::bytes_from_ustring(env, supplement);
env->ReleaseStringUTFChars(user_session_id, string);
return supplement_jbytearray;
}

View File

@ -321,6 +321,7 @@ class GroupKeysConfig(pointer: Long): ConfigSig(pointer) {
members: GroupMembersConfig)
external fun needsRekey(): Boolean
external fun pendingKey(): ByteArray?
external fun supplementFor(userSessionId: String): ByteArray
external fun pendingConfig(): ByteArray?
external fun currentHashes(): List<String>
external fun rekey(info: GroupInfoConfig, members: GroupMembersConfig): ByteArray

View File

@ -234,8 +234,8 @@ data class ConfigurationSyncJob(val destination: Destination) : Job {
responseBody?.get("hash") as? String
?: run {
Log.w(
TAG,
"No hash returned for the configuration in namespace ${config.namespace()}"
TAG,
"No hash returned for the configuration in namespace ${config.namespace()}"
)
return@forEachIndexed
}
@ -247,8 +247,8 @@ data class ConfigurationSyncJob(val destination: Destination) : Job {
}
Log.d(
TAG,
"Successfully removed the deleted hashes from ${config.javaClass.simpleName}"
TAG,
"Successfully removed the deleted hashes from ${config.javaClass.simpleName}"
)
// dump and write config after successful
if (config is ConfigBase && config.needsDump()) { // usually this will be true? ))

View File

@ -24,10 +24,13 @@ import kotlin.math.roundToLong
class JobQueue : JobDelegate {
private var hasResumedPendingJobs = false // Just for debugging
private val jobTimestampMap = ConcurrentHashMap<Long, AtomicInteger>()
private val rxDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val rxMediaDispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher()
private val openGroupDispatcher = Executors.newFixedThreadPool(8).asCoroutineDispatcher()
private val txDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val configDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val scope = CoroutineScope(Dispatchers.Default) + SupervisorJob()
private val queue = Channel<Job>(UNLIMITED)
private val pendingJobIds = mutableSetOf<String>()
@ -114,19 +117,23 @@ class JobQueue : JobDelegate {
val txQueue = Channel<Job>(capacity = UNLIMITED)
val mediaQueue = Channel<Job>(capacity = UNLIMITED)
val openGroupQueue = Channel<Job>(capacity = UNLIMITED)
val configQueue = Channel<Job>(capacity = UNLIMITED)
val receiveJob = processWithDispatcher(rxQueue, rxDispatcher, "rx", asynchronous = false)
val txJob = processWithDispatcher(txQueue, txDispatcher, "tx")
val mediaJob = processWithDispatcher(mediaQueue, rxMediaDispatcher, "media")
val openGroupJob = processWithOpenGroupDispatcher(openGroupQueue, openGroupDispatcher, "openGroup")
val configJob = processWithDispatcher(configQueue, configDispatcher, "configDispatcher")
while (isActive) {
when (val job = queue.receive()) {
is InviteContactsJob,
is ConfigurationSyncJob -> {
configQueue.send(job)
}
is NotifyPNServerJob,
is AttachmentUploadJob,
is MessageSendJob,
is ConfigurationSyncJob,
is InviteContactsJob -> {
is MessageSendJob -> {
txQueue.send(job)
}
is RetrieveProfileAvatarJob,
@ -158,6 +165,7 @@ class JobQueue : JobDelegate {
txJob.cancel()
mediaJob.cancel()
openGroupJob.cancel()
configJob.cancel()
}
}