refactor: turn inner wrapped group edit calls into synchronous calls to remove unnecessary nesting

pull/450/head
jubb 4 years ago
parent f45a285141
commit c8f1c862fb

@ -280,18 +280,15 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() {
ClosedGroupsProtocolV2.explicitLeave(this, groupPublicKey!!) ClosedGroupsProtocolV2.explicitLeave(this, groupPublicKey!!)
} else { } else {
task { task {
val name = if (hasNameChanged) {
if (hasNameChanged) ClosedGroupsProtocolV2.explicitNameChange(this@EditClosedGroupActivity,groupPublicKey!!,name) ClosedGroupsProtocolV2.explicitNameChange(this@EditClosedGroupActivity, groupPublicKey!!, name)
else Promise.of(Unit) }
name.get()
members.filterNot { it in originalMembers }.let { adds -> members.filterNot { it in originalMembers }.let { adds ->
if (adds.isNotEmpty()) ClosedGroupsProtocolV2.explicitAddMembers(this@EditClosedGroupActivity, groupPublicKey!!, adds.map { it.address.serialize() }) if (adds.isNotEmpty()) ClosedGroupsProtocolV2.explicitAddMembers(this@EditClosedGroupActivity, groupPublicKey!!, adds.map { it.address.serialize() })
else Promise.of(Unit) }
}.get()
originalMembers.filterNot { it in members }.let { removes -> originalMembers.filterNot { it in members }.let { removes ->
if (removes.isNotEmpty()) ClosedGroupsProtocolV2.explicitRemoveMembers(this@EditClosedGroupActivity, groupPublicKey!!, removes.map { it.address.serialize() }) if (removes.isNotEmpty()) ClosedGroupsProtocolV2.explicitRemoveMembers(this@EditClosedGroupActivity, groupPublicKey!!, removes.map { it.address.serialize() })
else Promise.of(Unit) }
}.get()
} }
} }
promise.successUi { promise.successUi {

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.loki.protocol
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import androidx.annotation.WorkerThread
import com.google.protobuf.ByteString import com.google.protobuf.ByteString
import nl.komponents.kovenant.Promise import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred import nl.komponents.kovenant.deferred
@ -129,147 +130,115 @@ object ClosedGroupsProtocolV2 {
} }
@JvmStatic @JvmStatic
fun explicitAddMembers(context: Context, groupPublicKey: String, membersToAdd: List<String>): Promise<Any, java.lang.Exception> { fun explicitAddMembers(context: Context, groupPublicKey: String, membersToAdd: List<String>) {
return task { val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
val apiDB = DatabaseFactory.getLokiAPIDatabase(context) val groupDB = DatabaseFactory.getGroupDatabase(context)
val groupDB = DatabaseFactory.getGroupDatabase(context) val groupID = doubleEncodeGroupID(groupPublicKey)
val groupID = doubleEncodeGroupID(groupPublicKey) val group = groupDB.getGroup(groupID).orNull()
val group = groupDB.getGroup(groupID).orNull() if (group == null) {
if (group == null) { Log.d("Loki", "Can't leave nonexistent closed group.")
Log.d("Loki", "Can't leave nonexistent closed group.") throw Error.NoThread
return@task Error.NoThread
}
val updatedMembers = group.members.map { it.serialize() }.toSet() + membersToAdd
// Save the new group members
groupDB.updateMembers(groupID, updatedMembers.map { Address.fromSerialized(it) })
val membersAsData = updatedMembers.map { Hex.fromStringCondensed(it) }
val newMembersAsData = membersToAdd.map { Hex.fromStringCondensed(it) }
val admins = group.admins.map { it.serialize() }
val adminsAsData = admins.map { Hex.fromStringCondensed(it) }
val sentTime = System.currentTimeMillis()
val encryptionKeyPair = pendingKeyPair.getOrElse(groupPublicKey) {
Optional.fromNullable(apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey))
}.orNull()
if (encryptionKeyPair == null) {
Log.d("Loki", "Couldn't get encryption key pair for closed group.")
return@task Error.NoKeyPair
}
val name = group.title
// Send the update to the group
val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.AddMembers(newMembersAsData)
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind, sentTime)
job.setContext(context)
job.onRun() // Run the job immediately
// Notify the user
val infoType = GroupContext.Type.UPDATE
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
// Send closed group update messages to any new members individually
for (member in membersToAdd) {
@Suppress("NAME_SHADOWING")
val closedGroupNewKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
@Suppress("NAME_SHADOWING")
val newMemberJob = ClosedGroupUpdateMessageSendJobV2(member, closedGroupNewKind, sentTime)
ApplicationContext.getInstance(context).jobManager.add(newMemberJob)
}
} }
} val updatedMembers = group.members.map { it.serialize() }.toSet() + membersToAdd
val membersAsData = updatedMembers.map { Hex.fromStringCondensed(it) }
@JvmStatic val newMembersAsData = membersToAdd.map { Hex.fromStringCondensed(it) }
fun explicitRemoveMembers(context: Context, groupPublicKey: String, membersToRemove: List<String>): Promise<Any, Exception> { val admins = group.admins.map { it.serialize() }
return task { val adminsAsData = admins.map { Hex.fromStringCondensed(it) }
val userPublicKey = TextSecurePreferences.getLocalNumber(context) val sentTime = System.currentTimeMillis()
val apiDB = DatabaseFactory.getLokiAPIDatabase(context) val encryptionKeyPair = pendingKeyPair.getOrElse(groupPublicKey) {
val groupDB = DatabaseFactory.getGroupDatabase(context) Optional.fromNullable(apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey))
val groupID = doubleEncodeGroupID(groupPublicKey) }.orNull()
val group = groupDB.getGroup(groupID).orNull() if (encryptionKeyPair == null) {
if (group == null) { Log.d("Loki", "Couldn't get encryption key pair for closed group.")
Log.d("Loki", "Can't leave nonexistent closed group.") throw Error.NoKeyPair
return@task Error.NoThread }
} val name = group.title
val updatedMembers = group.members.map { it.serialize() }.toSet() - membersToRemove // Send the update to the group
// Save the new group members val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.AddMembers(newMembersAsData)
groupDB.updateMembers(groupID, updatedMembers.map { Address.fromSerialized(it) }) val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind, sentTime)
val removeMembersAsData = membersToRemove.map { Hex.fromStringCondensed(it) } job.setContext(context)
val admins = group.admins.map { it.serialize() } job.onRun() // Run the job immediately
val sentTime = System.currentTimeMillis() // Save the new group members
val encryptionKeyPair = apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) groupDB.updateMembers(groupID, updatedMembers.map { Address.fromSerialized(it) })
if (encryptionKeyPair == null) { // Notify the user
Log.d("Loki", "Couldn't get encryption key pair for closed group.") val infoType = GroupContext.Type.UPDATE
return@task Error.NoKeyPair val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
} insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
if (membersToRemove.any { it in admins } && updatedMembers.isNotEmpty()) { // Send closed group update messages to any new members individually
Log.d("Loki", "Can't remove admin from closed group unless the group is destroyed entirely.") for (member in membersToAdd) {
return@task Error.InvalidUpdate @Suppress("NAME_SHADOWING")
} val closedGroupNewKind = ClosedGroupUpdateMessageSendJobV2.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, encryptionKeyPair, membersAsData, adminsAsData)
val name = group.title @Suppress("NAME_SHADOWING")
// Send the update to the group val newMemberJob = ClosedGroupUpdateMessageSendJobV2(member, closedGroupNewKind, sentTime)
val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.RemoveMembers(removeMembersAsData) ApplicationContext.getInstance(context).jobManager.add(newMemberJob)
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind, sentTime)
job.setContext(context)
job.onRun() // Run the job immediately
// Notify the user
val infoType = GroupContext.Type.UPDATE
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
val isCurrentUserAdmin = admins.contains(userPublicKey)
if (isCurrentUserAdmin) {
generateAndSendNewEncryptionKeyPair(context, groupPublicKey, updatedMembers)
}
return@task Unit
} }
} }
@JvmStatic @JvmStatic
fun explicitNameChange(context: Context, groupPublicKey: String, newName: String): Promise<Unit, Exception> { fun explicitRemoveMembers(context: Context, groupPublicKey: String, membersToRemove: List<String>) {
val deferred = deferred<Unit, Exception>() val userPublicKey = TextSecurePreferences.getLocalNumber(context)
ThreadUtils.queue { val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
val groupDB = DatabaseFactory.getGroupDatabase(context) val groupDB = DatabaseFactory.getGroupDatabase(context)
val groupID = doubleEncodeGroupID(groupPublicKey) val groupID = doubleEncodeGroupID(groupPublicKey)
val group = groupDB.getGroup(groupID).orNull() val group = groupDB.getGroup(groupID).orNull()
val members = group.members.map { it.serialize() }.toSet() if (group == null) {
val admins = group.admins.map { it.serialize() } Log.d("Loki", "Can't leave nonexistent closed group.")
val sentTime = System.currentTimeMillis() throw Error.NoThread
if (group == null) { }
Log.d("Loki", "Can't leave nonexistent closed group.") val updatedMembers = group.members.map { it.serialize() }.toSet() - membersToRemove
return@queue deferred.reject(Error.NoThread) val removeMembersAsData = membersToRemove.map { Hex.fromStringCondensed(it) }
} val admins = group.admins.map { it.serialize() }
// Send the update to the group val sentTime = System.currentTimeMillis()
val kind = ClosedGroupUpdateMessageSendJobV2.Kind.NameChange(newName) val encryptionKeyPair = apiDB.getLatestClosedGroupEncryptionKeyPair(groupPublicKey)
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, kind, sentTime) if (encryptionKeyPair == null) {
job.setContext(context) Log.d("Loki", "Couldn't get encryption key pair for closed group.")
job.onRun() // Run the job immediately throw Error.NoKeyPair
// Notify the user }
val infoType = GroupContext.Type.UPDATE if (membersToRemove.any { it in admins } && updatedMembers.isNotEmpty()) {
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false)) Log.d("Loki", "Can't remove admin from closed group unless the group is destroyed entirely.")
insertOutgoingInfoMessage(context, groupID, infoType, newName, members, admins, threadID, sentTime) throw Error.InvalidUpdate
// Update the group }
groupDB.updateTitle(groupID, newName) val name = group.title
deferred.resolve(Unit) // Send the update to the group
val memberUpdateKind = ClosedGroupUpdateMessageSendJobV2.Kind.RemoveMembers(removeMembersAsData)
val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, memberUpdateKind, sentTime)
job.setContext(context)
job.onRun() // Run the job immediately
// Save the new group members
groupDB.updateMembers(groupID, updatedMembers.map { Address.fromSerialized(it) })
// Notify the user
val infoType = GroupContext.Type.UPDATE
val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime)
val isCurrentUserAdmin = admins.contains(userPublicKey)
if (isCurrentUserAdmin) {
generateAndSendNewEncryptionKeyPair(context, groupPublicKey, updatedMembers)
} }
return deferred.promise
} }
@JvmStatic @JvmStatic
fun leave(context: Context, groupPublicKey: String): Promise<Unit, Exception> { fun explicitNameChange(context: Context, groupPublicKey: String, newName: String) {
val userPublicKey = TextSecurePreferences.getLocalNumber(context)!!
val groupDB = DatabaseFactory.getGroupDatabase(context) val groupDB = DatabaseFactory.getGroupDatabase(context)
val groupID = doubleEncodeGroupID(groupPublicKey) val groupID = doubleEncodeGroupID(groupPublicKey)
val group = groupDB.getGroup(groupID).orNull() val group = groupDB.getGroup(groupID).orNull()
val members = group.members.map { it.serialize() }.toSet()
val admins = group.admins.map { it.serialize() }
val sentTime = System.currentTimeMillis()
if (group == null) { if (group == null) {
Log.d("Loki", "Can't leave nonexistent closed group.") Log.d("Loki", "Can't leave nonexistent closed group.")
return Promise.ofFail(Error.NoThread) throw Error.NoThread
} }
val name = group.title // Send the update to the group
val oldMembers = group.members.map { it.serialize() }.toSet() val kind = ClosedGroupUpdateMessageSendJobV2.Kind.NameChange(newName)
val newMembers: Set<String> val job = ClosedGroupUpdateMessageSendJobV2(groupPublicKey, kind, sentTime)
val isCurrentUserAdmin = group.admins.map { it.toString() }.contains(userPublicKey) job.setContext(context)
if (!isCurrentUserAdmin) { job.onRun() // Run the job immediately
newMembers = oldMembers.minus(userPublicKey) // Notify the user
} else { val infoType = GroupContext.Type.UPDATE
newMembers = setOf() // If the admin leaves the group is destroyed val threadID = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
} insertOutgoingInfoMessage(context, groupID, infoType, newName, members, admins, threadID, sentTime)
return update(context, groupPublicKey, newMembers, name) // Update the group
groupDB.updateTitle(groupID, newName)
} }
fun update(context: Context, groupPublicKey: String, members: Collection<String>, name: String): Promise<Unit, Exception> { fun update(context: Context, groupPublicKey: String, members: Collection<String>, name: String): Promise<Unit, Exception> {

Loading…
Cancel
Save