Merge remote-tracking branch 'origin/release/1.21.0' into merge-release-1.21.0

pull/1710/head
SessionHero01 2 months ago
commit 20fc0a2d2d
No known key found for this signature in database

@ -11,6 +11,7 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
@ -33,6 +34,7 @@ import org.session.libsession.snode.utilities.await
import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsession.utilities.ConfigPushResult
import org.session.libsession.utilities.ConfigUpdateNotification
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.UserConfigType
import org.session.libsession.utilities.getGroup
import org.session.libsignal.utilities.AccountId
@ -43,6 +45,7 @@ import org.session.libsignal.utilities.Snode
import org.session.libsignal.utilities.retryWithUniformInterval
import org.thoughtcrime.securesms.util.InternetConnectivity
import javax.inject.Inject
import kotlin.math.log
private const val TAG = "ConfigUploader"
@ -62,6 +65,7 @@ class ConfigUploader @Inject constructor(
private val storageProtocol: StorageProtocol,
private val clock: SnodeClock,
private val internetConnectivity: InternetConnectivity,
private val textSecurePreferences: TextSecurePreferences,
) {
private var job: Job? = null
@ -82,6 +86,11 @@ class ConfigUploader @Inject constructor(
}
}
// A flow that emits true when there's a logged in user
private fun hasLoggedInUser(): Flow<Boolean> = textSecurePreferences.watchLocalNumber()
.map { it != null }
.distinctUntilChanged()
@OptIn(DelicateCoroutinesApi::class, FlowPreview::class, ExperimentalCoroutinesApi::class)
fun start() {
@ -92,41 +101,58 @@ class ConfigUploader @Inject constructor(
// For any of these events, we need to push the user configs:
// - The onion path has just become available to use
// - The user configs have been modified
// Also, these events are only relevant when there's a logged in user
val job1 = launch {
merge(
pathBecomesAvailable(),
configFactory.configUpdateNotifications
.filterIsInstance<ConfigUpdateNotification.UserConfigsModified>()
.debounce(1000L)
).collect {
try {
retryWithUniformInterval {
pushUserConfigChangesIfNeeded()
hasLoggedInUser()
.flatMapLatest { loggedIn ->
if (loggedIn) {
merge(
pathBecomesAvailable(),
configFactory.configUpdateNotifications
.filterIsInstance<ConfigUpdateNotification.UserConfigsModified>()
.debounce(1000L)
)
} else {
emptyFlow()
}
}
.collect {
try {
retryWithUniformInterval {
pushUserConfigChangesIfNeeded()
}
} catch (e: Exception) {
Log.e(TAG, "Failed to push user configs", e)
}
} catch (e: Exception) {
Log.e(TAG, "Failed to push user configs", e)
}
}
}
val job2 = launch {
merge(
// When the onion request path changes, we need to examine all the groups
// and push the pending configs for them
pathBecomesAvailable().flatMapLatest {
configFactory.withUserConfigs { configs -> configs.userGroups.allClosedGroupInfo() }
.asSequence()
.filter { !it.destroyed && !it.kicked }
.map { it.groupAccountId }
.asFlow()
},
// Or, when a group config is updated, we need to push the changes for that group
configFactory.configUpdateNotifications
.filterIsInstance<ConfigUpdateNotification.GroupConfigsUpdated>()
.map { it.groupId }
.debounce(1000L)
).collect { groupId ->
hasLoggedInUser()
.flatMapLatest { loggedIn ->
if (loggedIn) {
merge(
// When the onion request path changes, we need to examine all the groups
// and push the pending configs for them
pathBecomesAvailable().flatMapLatest {
configFactory.withUserConfigs { configs -> configs.userGroups.allClosedGroupInfo() }
.asSequence()
.filter { !it.destroyed && !it.kicked }
.map { it.groupAccountId }
.asFlow()
},
// Or, when a group config is updated, we need to push the changes for that group
configFactory.configUpdateNotifications
.filterIsInstance<ConfigUpdateNotification.GroupConfigsUpdated>()
.map { it.groupId }
.debounce(1000L)
)
} else {
emptyFlow()
}
}
.collect { groupId ->
try {
retryWithUniformInterval {
pushGroupConfigsChangesIfNeeded(groupId)

@ -56,7 +56,7 @@ object ResendMessageUtilities {
if (sentTimestamp != null && sender != null) {
if (isResync) {
MessagingModuleConfiguration.shared.storage.markAsResyncing(sentTimestamp, sender)
MessageSender.send(message, Destination.from(recipient.address), isSyncMessage = true)
MessageSender.sendNonDurably(message, Destination.from(recipient.address), isSyncMessage = true)
} else {
MessagingModuleConfiguration.shared.storage.markAsSending(sentTimestamp, sender)
MessageSender.send(message, recipient.address)

@ -101,10 +101,38 @@ abstract class BaseGroupMembersViewModel (
status = status.takeIf { !isMyself }, // Status is only meant for other members
highlightStatus = highlightStatus,
showAsAdmin = member.isAdminOrBeingPromoted(status),
clickable = !isMyself
clickable = !isMyself,
statusLabel = getMemberLabel(status, context, amIAdmin),
)
}
private fun getMemberLabel(status: GroupMember.Status, context: Context, amIAdmin: Boolean): String {
return when (status) {
GroupMember.Status.INVITE_FAILED -> context.getString(R.string.groupInviteFailed)
GroupMember.Status.INVITE_SENDING -> context.resources.getQuantityString(R.plurals.groupInviteSending, 1)
GroupMember.Status.INVITE_SENT -> context.getString(R.string.groupInviteSent)
GroupMember.Status.PROMOTION_FAILED -> context.getString(R.string.adminPromotionFailed)
GroupMember.Status.PROMOTION_SENDING -> context.resources.getQuantityString(R.plurals.adminSendingPromotion, 1)
GroupMember.Status.PROMOTION_SENT -> context.getString(R.string.adminPromotionSent)
GroupMember.Status.REMOVED,
GroupMember.Status.REMOVED_UNKNOWN,
GroupMember.Status.REMOVED_INCLUDING_MESSAGES -> {
if (amIAdmin) {
context.getString(R.string.groupPendingRemoval)
} else {
""
}
}
GroupMember.Status.INVITE_UNKNOWN,
GroupMember.Status.INVITE_ACCEPTED,
GroupMember.Status.INVITE_NOT_SENT,
GroupMember.Status.PROMOTION_NOT_SENT,
GroupMember.Status.PROMOTION_UNKNOWN,
GroupMember.Status.PROMOTION_ACCEPTED -> ""
}
}
// Refer to notion doc for the sorting logic
private fun sortMembers(members: List<GroupMemberState>, currentUserId: AccountId) =
members.sortedWith(
@ -150,37 +178,8 @@ data class GroupMemberState(
val canResendPromotion: Boolean,
val canRemove: Boolean,
val canPromote: Boolean,
val clickable: Boolean
val clickable: Boolean,
val statusLabel: String,
) {
val canEdit: Boolean get() = canRemove || canPromote || canResendInvite || canResendPromotion
}
// Function to get the label dynamically using the context
fun GroupMemberState.getLabel(context: Context): String {
return when (this.status) {
GroupMember.Status.INVITE_FAILED -> context.getString(R.string.groupInviteFailed)
GroupMember.Status.INVITE_SENDING -> context.resources.getQuantityString(R.plurals.groupInviteSending, 1)
GroupMember.Status.INVITE_SENT -> context.getString(R.string.groupInviteSent)
GroupMember.Status.PROMOTION_FAILED -> context.getString(R.string.adminPromotionFailed)
GroupMember.Status.PROMOTION_SENDING -> context.resources.getQuantityString(R.plurals.adminSendingPromotion, 1)
GroupMember.Status.PROMOTION_SENT -> context.getString(R.string.adminPromotionSent)
GroupMember.Status.REMOVED,
GroupMember.Status.REMOVED_UNKNOWN,
GroupMember.Status.REMOVED_INCLUDING_MESSAGES -> {
if (this.showAsAdmin) {
context.getString(R.string.groupPendingRemoval)
} else {
""
}
}
GroupMember.Status.INVITE_UNKNOWN,
GroupMember.Status.INVITE_ACCEPTED,
GroupMember.Status.INVITE_NOT_SENT,
GroupMember.Status.PROMOTION_NOT_SENT,
GroupMember.Status.PROMOTION_UNKNOWN,
GroupMember.Status.PROMOTION_ACCEPTED -> ""
null -> ""
}
}

@ -3,11 +3,9 @@ package org.thoughtcrime.securesms.groups
import android.content.Context
import com.google.protobuf.ByteString
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.first
@ -19,7 +17,6 @@ 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.GroupMember
import network.loki.messenger.libsession_util.util.Sodium
import network.loki.messenger.libsession_util.util.UserPic
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.database.StorageProtocol
@ -269,8 +266,8 @@ class GroupManagerV2Impl @Inject constructor(
subAccountTokens = subAccountTokens
)
// Before we send the invitation, we need to make sure the configs are pushed
configFactory.waitUntilGroupConfigsPushed(group)
// Send a group update message to the group telling members someone has been invited
sendGroupUpdateForAddingMembers(group, adminKey, newMembers)
// Call the API
try {
@ -307,9 +304,6 @@ class GroupManagerV2Impl @Inject constructor(
newMembers.map { it.hexString }.toTypedArray()
)
)
// Send a group update message to the group telling members someone has been invited
sendGroupUpdateForAddingMembers(group, adminKey, newMembers)
}
/**
@ -336,7 +330,8 @@ class GroupManagerV2Impl @Inject constructor(
)
.build()
).apply { this.sentTimestamp = timestamp }
MessageSender.send(updatedMessage, Destination.ClosedGroup(group.hexString), false)
MessageSender.send(updatedMessage, Address.fromSerialized(group.hexString))
storage.insertGroupInfoChange(updatedMessage, group)
}
@ -377,7 +372,7 @@ class GroupManagerV2Impl @Inject constructor(
updateMessage
).apply { sentTimestamp = timestamp }
MessageSender.send(message, Destination.ClosedGroup(groupAccountId.hexString), false).await()
MessageSender.send(message, Address.fromSerialized(groupAccountId.hexString))
storage.insertGroupInfoChange(message, groupAccountId)
}
@ -444,37 +439,27 @@ class GroupManagerV2Impl @Inject constructor(
}
if (group != null && !group.kicked && !weAreTheOnlyAdmin) {
val destination = Destination.ClosedGroup(groupId.hexString)
val sendMessageTasks = mutableListOf<Deferred<*>>()
val address = Address.fromSerialized(groupId.hexString)
// Always send a "XXX left" message to the group if we can
sendMessageTasks += async {
MessageSender.send(
GroupUpdated(
GroupUpdateMessage.newBuilder()
.setMemberLeftNotificationMessage(DataMessage.GroupUpdateMemberLeftNotificationMessage.getDefaultInstance())
.build()
),
destination,
isSyncMessage = false
).await()
}
MessageSender.send(
GroupUpdated(
GroupUpdateMessage.newBuilder()
.setMemberLeftNotificationMessage(DataMessage.GroupUpdateMemberLeftNotificationMessage.getDefaultInstance())
.build()
),
address
)
// If we are not the only admin, send a left message for other admin to handle the member removal
sendMessageTasks += async {
MessageSender.send(
GroupUpdated(
GroupUpdateMessage.newBuilder()
.setMemberLeftMessage(DataMessage.GroupUpdateMemberLeftMessage.getDefaultInstance())
.build()
),
destination,
isSyncMessage = false
).await()
}
sendMessageTasks.awaitAll()
MessageSender.send(
GroupUpdated(
GroupUpdateMessage.newBuilder()
.setMemberLeftMessage(DataMessage.GroupUpdateMemberLeftMessage.getDefaultInstance())
.build()
),
address,
)
}
// If we are the only admin, leaving this group will destroy the group
@ -537,11 +522,10 @@ class GroupManagerV2Impl @Inject constructor(
val promotionDeferred = members.associateWith { member ->
async {
MessageSender.sendNonDurably(
MessageSender.sendAndAwait(
message = promoteMessage,
address = Address.fromSerialized(member.hexString),
isSyncMessage = false
).await()
)
}
}
@ -585,7 +569,7 @@ class GroupManagerV2Impl @Inject constructor(
sentTimestamp = timestamp
}
MessageSender.send(message, Destination.ClosedGroup(group.hexString), false).await()
MessageSender.sendAndAwait(message, Address.fromSerialized(group.hexString))
storage.insertGroupInfoChange(message, group)
}
}
@ -683,7 +667,7 @@ class GroupManagerV2Impl @Inject constructor(
.setInviteResponse(inviteResponse)
val responseMessage = GroupUpdated(responseData.build(), profile = storage.getUserProfile())
// this will fail the first couple of times :)
MessageSender.send(
MessageSender.sendNonDurably(
responseMessage,
Destination.ClosedGroup(group.groupAccountId.hexString),
isSyncMessage = false
@ -962,7 +946,7 @@ class GroupManagerV2Impl @Inject constructor(
sentTimestamp = timestamp
}
MessageSender.send(message, Address.fromSerialized(groupId.hexString))
MessageSender.sendAndAwait(message, Address.fromSerialized(groupId.hexString))
storage.insertGroupInfoChange(message, groupId)
}
@ -1034,7 +1018,7 @@ class GroupManagerV2Impl @Inject constructor(
sentTimestamp = timestamp
}
MessageSender.send(message, Destination.ClosedGroup(groupId.hexString), false).await()
MessageSender.sendAndAwait(message, Address.fromSerialized(groupId.hexString))
}
override suspend fun handleDeleteMemberContent(

@ -50,7 +50,6 @@ import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY
import org.session.libsignal.utilities.AccountId
import org.thoughtcrime.securesms.groups.EditGroupViewModel
import org.thoughtcrime.securesms.groups.GroupMemberState
import org.thoughtcrime.securesms.groups.getLabel
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.DialogButtonModel
import org.thoughtcrime.securesms.ui.GetString
@ -442,7 +441,7 @@ fun EditMemberItem(
MemberItem(
accountId = member.accountId,
title = member.name,
subtitle = member.getLabel(LocalContext.current),
subtitle = member.statusLabel,
subtitleColor = if (member.highlightStatus) {
LocalColors.current.danger
} else {
@ -476,7 +475,8 @@ private fun EditGroupPreview3() {
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = false,
clickable = true
clickable = true,
statusLabel = "Invited"
)
val twoMember = GroupMemberState(
accountId = AccountId("05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1235"),
@ -488,7 +488,8 @@ private fun EditGroupPreview3() {
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = true,
clickable = true
clickable = true,
statusLabel = "Promotion failed"
)
val threeMember = GroupMemberState(
accountId = AccountId("05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1236"),
@ -500,7 +501,8 @@ private fun EditGroupPreview3() {
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = false,
clickable = true
clickable = true,
statusLabel = ""
)
val (editingName, setEditingName) = remember { mutableStateOf<String?>(null) }
@ -551,7 +553,8 @@ private fun EditGroupPreview() {
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = false,
clickable = true
clickable = true,
statusLabel = "Invited"
)
val twoMember = GroupMemberState(
accountId = AccountId("05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1235"),
@ -563,7 +566,8 @@ private fun EditGroupPreview() {
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = true,
clickable = true
clickable = true,
statusLabel = "Promotion failed"
)
val threeMember = GroupMemberState(
accountId = AccountId("05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1236"),
@ -575,7 +579,8 @@ private fun EditGroupPreview() {
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = false,
clickable = true
clickable = true,
statusLabel = ""
)
val (editingName, setEditingName) = remember { mutableStateOf<String?>(null) }
@ -628,7 +633,8 @@ private fun EditGroupEditNamePreview(
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = false,
clickable = true
clickable = true,
statusLabel = "Invited"
)
val twoMember = GroupMemberState(
accountId = AccountId("05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1235"),
@ -640,7 +646,8 @@ private fun EditGroupEditNamePreview(
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = true,
clickable = true
clickable = true,
statusLabel = "Promotion failed"
)
val threeMember = GroupMemberState(
accountId = AccountId("05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1236"),
@ -652,7 +659,8 @@ private fun EditGroupEditNamePreview(
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = false,
clickable = true
clickable = true,
statusLabel = ""
)
EditGroup(

@ -9,7 +9,6 @@ import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
@ -18,7 +17,6 @@ import network.loki.messenger.libsession_util.util.GroupMember
import org.session.libsignal.utilities.AccountId
import org.thoughtcrime.securesms.groups.GroupMemberState
import org.thoughtcrime.securesms.groups.GroupMembersViewModel
import org.thoughtcrime.securesms.groups.getLabel
import org.thoughtcrime.securesms.ui.components.BackAppBar
import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
@ -43,7 +41,7 @@ fun GroupMembersScreen(
@Composable
fun GroupMembers(
onBack: () -> Unit,
members: List<GroupMemberState>
members: List<GroupMemberState>,
) {
Scaffold(
@ -62,7 +60,7 @@ fun GroupMembers(
MemberItem(
accountId = member.accountId,
title = member.name,
subtitle = member.getLabel(LocalContext.current),
subtitle = member.statusLabel,
subtitleColor = if (member.highlightStatus) {
LocalColors.current.danger
} else {
@ -91,7 +89,8 @@ private fun EditGroupPreview() {
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = false,
clickable = true
clickable = true,
statusLabel = "Invited"
)
val twoMember = GroupMemberState(
accountId = AccountId("05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1235"),
@ -103,7 +102,8 @@ private fun EditGroupPreview() {
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = true,
clickable = true
clickable = true,
statusLabel = "Promotion failed"
)
val threeMember = GroupMemberState(
accountId = AccountId("05abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1236"),
@ -115,7 +115,8 @@ private fun EditGroupPreview() {
canResendInvite = false,
canResendPromotion = false,
showAsAdmin = false,
clickable = true
clickable = true,
statusLabel = ""
)
GroupMembers(

@ -416,7 +416,7 @@ class DefaultConversationRepository @Inject constructor(
)
} else {
val message = MessageRequestResponse(true)
MessageSender.send(
MessageSender.sendNonDurably(
message = message,
destination = Destination.from(recipient.address),
isSyncMessage = recipient.isLocalNumber

@ -139,7 +139,8 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess
destination.whisperTo,
destination.whisperMods,
destination.fileIds + uploadResult.id.toString()
)
),
statusCallback = it.statusCallback
)
updatedJob.id = it.id
updatedJob.delegate = it.delegate

@ -7,7 +7,6 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.withContext
import org.session.libsession.R
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.groups.GroupInviteException
import org.session.libsession.messaging.messages.Destination
@ -18,11 +17,7 @@ import org.session.libsession.messaging.utilities.MessageAuthentication.buildGro
import org.session.libsession.messaging.utilities.SodiumUtilities
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.snode.utilities.await
import org.session.libsession.utilities.StringSubstitutionConstants.GROUP_NAME_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.NAME_KEY
import org.session.libsession.utilities.StringSubstitutionConstants.OTHER_NAME_KEY
import org.session.libsession.utilities.getGroup
import org.session.libsession.utilities.truncateIdForDisplay
import org.session.libsignal.protos.SignalServiceProtos.DataMessage.GroupUpdateInviteMessage
import org.session.libsignal.protos.SignalServiceProtos.DataMessage.GroupUpdateMessage
import org.session.libsignal.utilities.AccountId
@ -81,7 +76,7 @@ class InviteContactsJob(val groupSessionId: String, val memberSessionIds: Array<
sentTimestamp = timestamp
}
MessageSender.send(update, Destination.Contact(memberSessionId), false)
MessageSender.sendNonDurably(update, Destination.Contact(memberSessionId), false)
.await()
}
}

@ -3,10 +3,10 @@ package org.session.libsession.messaging.jobs
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.withTimeout
import org.session.libsession.messaging.MessagingModuleConfiguration
@ -23,7 +23,7 @@ import org.session.libsignal.utilities.AccountId
import org.session.libsignal.utilities.HTTP
import org.session.libsignal.utilities.Log
class MessageSendJob(val message: Message, val destination: Destination) : Job {
class MessageSendJob(val message: Message, val destination: Destination, val statusCallback: SendChannel<Result<Unit>>?) : Job {
object AwaitingAttachmentUploadException : Exception("Awaiting attachment upload.")
@ -91,18 +91,25 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job {
.waitForGroupEncryptionKeys(AccountId(destination.publicKey))
}
MessageSender.send(this@MessageSendJob.message, destination, isSync).await()
MessageSender.sendNonDurably(this@MessageSendJob.message, destination, isSync).await()
}
this.handleSuccess(dispatcherName)
statusCallback?.trySend(Result.success(Unit))
} catch (e: HTTP.HTTPRequestFailedException) {
if (e.statusCode == 429) { this.handlePermanentFailure(dispatcherName, e) }
else { this.handleFailure(dispatcherName, e) }
statusCallback?.trySend(Result.failure(e))
} catch (e: MessageSender.Error) {
if (!e.isRetryable) { this.handlePermanentFailure(dispatcherName, e) }
else { this.handleFailure(dispatcherName, e) }
statusCallback?.trySend(Result.failure(e))
} catch (e: Exception) {
this.handleFailure(dispatcherName, e)
statusCallback?.trySend(Result.failure(e))
}
}
@ -191,7 +198,7 @@ class MessageSendJob(val message: Message, val destination: Destination) : Job {
}
destinationInput.close()
// Return
return MessageSendJob(message, destination)
return MessageSendJob(message, destination, statusCallback = null)
}
}
}

@ -2,9 +2,10 @@ package org.session.libsession.messaging.sending_receiving
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.launch
import kotlinx.coroutines.supervisorScope
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_HIDDEN
import network.loki.messenger.libsession_util.ConfigBase.Companion.PRIORITY_VISIBLE
import network.loki.messenger.libsession_util.util.ExpiryMode
import nl.komponents.kovenant.Promise
@ -30,24 +31,20 @@ import org.session.libsession.messaging.open_groups.OpenGroupApi.Capability
import org.session.libsession.messaging.open_groups.OpenGroupMessage
import org.session.libsession.messaging.utilities.MessageWrapper
import org.session.libsession.messaging.utilities.SodiumUtilities
import org.session.libsession.snode.RawResponsePromise
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.snode.SnodeAPI.nowWithOffset
import org.session.libsession.snode.SnodeMessage
import org.session.libsession.snode.SnodeModule
import org.session.libsession.snode.utilities.asyncPromise
import org.session.libsession.snode.utilities.await
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Device
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.SSKEnvironment
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.crypto.PushTransportDetails
import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.utilities.AccountId
import org.session.libsignal.utilities.Base64
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.Namespace
import org.session.libsignal.utilities.defaultRequiresAuth
import org.session.libsignal.utilities.hasNamespaces
@ -80,7 +77,7 @@ object MessageSender {
}
// Convenience
fun send(message: Message, destination: Destination, isSyncMessage: Boolean): Promise<Unit, Exception> {
fun sendNonDurably(message: Message, destination: Destination, isSyncMessage: Boolean): Promise<Unit, Exception> {
if (message is VisibleMessage) MessagingModuleConfiguration.shared.lastSentTimestampCache.submitTimestamp(message.threadID!!, message.sentTimestamp!!)
return if (destination is Destination.LegacyOpenGroup || destination is Destination.OpenGroup || destination is Destination.OpenGroupInbox) {
sendToOpenGroupDestination(destination, message)
@ -548,12 +545,13 @@ object MessageSender {
}
@JvmStatic
fun send(message: Message, address: Address) {
@JvmOverloads
fun send(message: Message, address: Address, statusCallback: SendChannel<Result<Unit>>? = null) {
val threadID = MessagingModuleConfiguration.shared.storage.getThreadId(address)
threadID?.let(message::applyExpiryMode)
message.threadID = threadID
val destination = Destination.from(address)
val job = MessageSendJob(message, destination)
val job = MessageSendJob(message, destination, statusCallback)
JobQueue.shared.add(job)
// if we are sending a 'Note to Self' make sure it is not hidden
@ -565,6 +563,12 @@ object MessageSender {
}
}
suspend fun sendAndAwait(message: Message, address: Address) {
val resultChannel = Channel<Result<Unit>>()
send(message, address, resultChannel)
resultChannel.receive().getOrThrow()
}
fun sendNonDurably(message: VisibleMessage, attachments: List<SignalAttachment>, address: Address, isSyncMessage: Boolean): Promise<Unit, Exception> {
val attachmentIDs = MessagingModuleConfiguration.shared.messageDataProvider.getAttachmentIDsFor(message.id!!)
message.attachmentIDs.addAll(attachmentIDs)
@ -575,7 +579,7 @@ object MessageSender {
val threadID = MessagingModuleConfiguration.shared.storage.getThreadId(address)
message.threadID = threadID
val destination = Destination.from(address)
return send(message, destination, isSyncMessage)
return sendNonDurably(message, destination, isSyncMessage)
}
// Closed groups

@ -6,11 +6,9 @@ import com.google.protobuf.ByteString
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.Channel
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.jobs.GroupLeavingJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.jobs.MessageSendJob
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
import org.session.libsession.messaging.sending_receiving.MessageSender.Error
import org.session.libsession.messaging.sending_receiving.notifications.PushRegistryV1
@ -22,14 +20,12 @@ import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.Device
import org.session.libsession.utilities.GroupUtil
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.crypto.ecc.Curve
import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.messages.SignalServiceGroup
import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.ThreadUtils
import org.session.libsignal.utilities.guava.Optional
import org.session.libsignal.utilities.hexEncodedPublicKey
import org.session.libsignal.utilities.removingIdPrefixIfNeeded
@ -85,7 +81,8 @@ fun MessageSender.create(
val closedGroupControlMessage = ClosedGroupControlMessage(closedGroupUpdateKind, groupID)
closedGroupControlMessage.sentTimestamp = sentTime
try {
sendNonDurably(closedGroupControlMessage, Address.fromSerialized(member), member == ourPubKey).await()
sendNonDurably(closedGroupControlMessage, fromSerialized(member), member == ourPubKey)
.await()
} catch (e: Exception) {
// We failed to properly create the group so delete it's associated data (in the past
// we didn't create this data until the messages successfully sent but this resulted

Loading…
Cancel
Save