@@ -6,38 +6,34 @@ import kotlinx.coroutines.async
6
6
import kotlinx.coroutines.awaitAll
7
7
import kotlinx.coroutines.coroutineScope
8
8
import network.loki.messenger.libsession_util.ConfigBase
9
- import network.loki.messenger.libsession_util.util.BlindKeyAPI
10
9
import org.session.libsession.messaging.MessagingModuleConfiguration
11
10
import org.session.libsession.messaging.messages.Destination
12
11
import org.session.libsession.messaging.messages.Message
13
12
import org.session.libsession.messaging.messages.Message.Companion.senderOrSync
14
13
import org.session.libsession.messaging.messages.control.CallMessage
15
- import org.session.libsession.messaging.messages.control.LegacyGroupControlMessage
16
- import org.session.libsession.messaging.messages.control.ConfigurationMessage
17
14
import org.session.libsession.messaging.messages.control.DataExtractionNotification
18
15
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
19
16
import org.session.libsession.messaging.messages.control.MessageRequestResponse
20
17
import org.session.libsession.messaging.messages.control.ReadReceipt
21
- import org.session.libsession.messaging.messages.control.SharedConfigurationMessage
22
18
import org.session.libsession.messaging.messages.control.TypingIndicator
23
19
import org.session.libsession.messaging.messages.control.UnsendRequest
24
20
import org.session.libsession.messaging.messages.visible.ParsedMessage
25
21
import org.session.libsession.messaging.messages.visible.VisibleMessage
26
22
import org.session.libsession.messaging.open_groups.OpenGroupApi
27
23
import org.session.libsession.messaging.sending_receiving.MessageReceiver
24
+ import org.session.libsession.messaging.sending_receiving.VisibleMessageHandlerContext
25
+ import org.session.libsession.messaging.sending_receiving.constructReactionRecords
28
26
import org.session.libsession.messaging.sending_receiving.handle
29
- import org.session.libsession.messaging.sending_receiving.handleOpenGroupReactions
30
27
import org.session.libsession.messaging.sending_receiving.handleUnsendRequest
31
28
import org.session.libsession.messaging.sending_receiving.handleVisibleMessage
32
29
import org.session.libsession.messaging.utilities.Data
33
30
import org.session.libsession.utilities.SSKEnvironment
34
31
import org.session.libsession.utilities.UserConfigType
35
32
import org.session.libsignal.protos.UtilProtos
36
33
import org.session.libsignal.utilities.AccountId
37
- import org.session.libsignal.utilities.Hex
38
- import org.session.libsignal.utilities.IdPrefix
39
34
import org.session.libsignal.utilities.Log
40
35
import org.thoughtcrime.securesms.database.model.MessageId
36
+ import org.thoughtcrime.securesms.database.model.ReactionRecord
41
37
import kotlin.math.max
42
38
43
39
data class MessageReceiveParameters (
@@ -83,12 +79,9 @@ class BatchMessageReceiveJob(
83
79
if (message is VisibleMessage ) return true
84
80
else { // message is control message otherwise
85
81
return when (message) {
86
- is SharedConfigurationMessage -> false
87
- is LegacyGroupControlMessage -> false // message.kind is ClosedGroupControlMessage.Kind.New && !message.isSenderSelf
88
82
is DataExtractionNotification -> false
89
83
is MessageRequestResponse -> false
90
84
is ExpirationTimerUpdate -> false
91
- is ConfigurationMessage -> false
92
85
is TypingIndicator -> false
93
86
is UnsendRequest -> false
94
87
is ReadReceipt -> false
@@ -175,45 +168,51 @@ class BatchMessageReceiveJob(
175
168
}
176
169
177
170
// iterate over threads and persist them (persistence is the longest constant in the batch process operation)
178
- fun processMessages (threadId : Long , messages : List <ParsedMessage >) {
171
+ suspend fun processMessages (threadId : Long , messages : List <ParsedMessage >) {
179
172
// The LinkedHashMap should preserve insertion order
180
173
val messageIds = linkedMapOf<MessageId , Pair <Boolean , Boolean >>()
181
174
val myLastSeen = storage.getLastSeen(threadId)
182
- var newLastSeen = myLastSeen.takeUnless { it == - 1L } ? : 0
175
+ var updatedLastSeen = myLastSeen.takeUnless { it == - 1L } ? : 0
176
+ val handlerContext = VisibleMessageHandlerContext (
177
+ module = MessagingModuleConfiguration .shared,
178
+ threadId = threadId,
179
+ openGroupID = openGroupID,
180
+ )
181
+
182
+ val communityReactions = mutableMapOf<MessageId , MutableList <ReactionRecord >>()
183
+
183
184
messages.forEach { (parameters, message, proto) ->
184
185
try {
185
186
when (message) {
186
187
is VisibleMessage -> {
187
188
val isUserBlindedSender =
188
- message.sender == serverPublicKey?.let {
189
- BlindKeyAPI .blind15KeyPairOrNull(
190
- ed25519SecretKey = storage.getUserED25519KeyPair()!!
191
- .secretKey.data,
192
- serverPubKey = Hex .fromStringCondensed(it),
193
- )
194
- }?.let {
195
- AccountId (IdPrefix .BLINDED , it.pubKey.data).hexString
196
- }
189
+ message.sender == handlerContext.userBlindedKey
190
+
197
191
if (message.sender == localUserPublicKey || isUserBlindedSender) {
198
192
// use sent timestamp here since that is technically the last one we have
199
- newLastSeen = max(newLastSeen , message.sentTimestamp!! )
193
+ updatedLastSeen = max(updatedLastSeen , message.sentTimestamp!! )
200
194
}
201
- val messageId = MessageReceiver .handleVisibleMessage(message, proto, openGroupID,
202
- threadId,
195
+ val messageId = MessageReceiver .handleVisibleMessage(
196
+ message = message,
197
+ proto = proto,
198
+ context = handlerContext,
203
199
runThreadUpdate = false ,
204
- runProfileUpdate = true )
200
+ runProfileUpdate = true
201
+ )
205
202
206
203
if (messageId != null && message.reaction == null ) {
207
204
messageIds[messageId] = Pair (
208
205
(message.sender == localUserPublicKey || isUserBlindedSender),
209
206
message.hasMention
210
207
)
211
208
}
209
+
212
210
parameters.openGroupMessageServerID?.let {
213
- MessageReceiver .handleOpenGroupReactions(
214
- threadId,
215
- it,
216
- parameters.reactions
211
+ constructReactionRecords(
212
+ openGroupMessageServerID = it,
213
+ context = handlerContext,
214
+ reactions = parameters.reactions,
215
+ out = communityReactions
217
216
)
218
217
}
219
218
}
@@ -248,13 +247,20 @@ class BatchMessageReceiveJob(
248
247
// increment unreads, notify, and update thread
249
248
// last seen will be the current last seen if not changed (re-computes the read counts for thread record)
250
249
// might have been updated from a different thread at this point
251
- val currentLastSeen = storage.getLastSeen(threadId).let { if (it == - 1L ) 0 else it }
252
- newLastSeen = max(newLastSeen, currentLastSeen)
253
- if (newLastSeen > 0 || currentLastSeen == 0L ) {
254
- storage.markConversationAsRead(threadId, newLastSeen, force = true )
250
+ val storedLastSeen = storage.getLastSeen(threadId).let { if (it == - 1L ) 0 else it }
251
+ updatedLastSeen = max(updatedLastSeen, storedLastSeen)
252
+ // Only call markConversationAsRead() when lastSeen actually advanced (we sent a message).
253
+ // For incoming-only batches (like reactions), skip this to preserve REACTIONS_UNREAD flags
254
+ // so the notification system can detect them. Thread updates happen separately below.
255
+ if (updatedLastSeen > storedLastSeen) {
256
+ storage.markConversationAsRead(threadId, updatedLastSeen, force = true )
255
257
}
256
258
storage.updateThread(threadId, true )
257
259
SSKEnvironment .shared.notificationManager.updateNotification(context, threadId)
260
+
261
+ if (communityReactions.isNotEmpty()) {
262
+ storage.addReactions(communityReactions, replaceAll = true , notifyUnread = false )
263
+ }
258
264
}
259
265
260
266
coroutineScope {
0 commit comments