@@ -31,6 +31,7 @@ import org.xmtp.android.library.messages.walletAddress
31
31
import org.xmtp.proto.keystore.api.v1.Keystore.TopicMap.TopicData
32
32
import org.xmtp.proto.message.contents.Contact
33
33
import org.xmtp.proto.message.contents.Invitation
34
+ import org.xmtp.android.library.messages.DecryptedMessage
34
35
import java.util.Date
35
36
36
37
data class Conversations (
@@ -307,6 +308,37 @@ data class Conversations(
307
308
return messages
308
309
}
309
310
311
+ fun listBatchDecryptedMessages (
312
+ topics : List <Pair <String , Pagination ?>>,
313
+ ): List <DecryptedMessage > {
314
+ val requests = topics.map { (topic, page) ->
315
+ makeQueryRequest(topic = topic, pagination = page)
316
+ }
317
+
318
+ // The maximum number of requests permitted in a single batch call.
319
+ val maxQueryRequestsPerBatch = 50
320
+ val messages: MutableList <DecryptedMessage > = mutableListOf ()
321
+ val batches = requests.chunked(maxQueryRequestsPerBatch)
322
+ for (batch in batches) {
323
+ runBlocking {
324
+ messages.addAll(
325
+ client.batchQuery(batch).responsesOrBuilderList.flatMap { res ->
326
+ res.envelopesList.mapNotNull { envelope ->
327
+ val conversation = conversationsByTopic[envelope.contentTopic]
328
+ if (conversation == null ) {
329
+ Log .d(TAG , " discarding message, unknown conversation $envelope " )
330
+ return @mapNotNull null
331
+ }
332
+ val msg = conversation.decrypt(envelope)
333
+ msg
334
+ }
335
+ }
336
+ )
337
+ }
338
+ }
339
+ return messages
340
+ }
341
+
310
342
fun sendInvitation (
311
343
recipient : SignedPublicKeyBundle ,
312
344
invitation : InvitationV1 ,
@@ -423,4 +455,59 @@ data class Conversations(
423
455
}
424
456
}
425
457
}
458
+
459
+ fun streamAllDecryptedMessages (): Flow <DecryptedMessage > = flow {
460
+ val topics = mutableListOf (
461
+ Topic .userInvite(client.address).description,
462
+ Topic .userIntro(client.address).description
463
+ )
464
+
465
+ for (conversation in list()) {
466
+ topics.add(conversation.topic)
467
+ }
468
+
469
+ val subscribeFlow = MutableStateFlow (makeSubscribeRequest(topics))
470
+
471
+ while (true ) {
472
+ try {
473
+ client.subscribe2(request = subscribeFlow).collect { envelope ->
474
+ when {
475
+ conversationsByTopic.containsKey(envelope.contentTopic) -> {
476
+ val conversation = conversationsByTopic[envelope.contentTopic]
477
+ val decrypted = conversation?.decrypt(envelope)
478
+ decrypted?.let { emit(it) }
479
+ }
480
+
481
+ envelope.contentTopic.startsWith(" /xmtp/0/invite-" ) -> {
482
+ val conversation = fromInvite(envelope = envelope)
483
+ conversationsByTopic[conversation.topic] = conversation
484
+ topics.add(conversation.topic)
485
+ subscribeFlow.value = makeSubscribeRequest(topics)
486
+ }
487
+
488
+ envelope.contentTopic.startsWith(" /xmtp/0/intro-" ) -> {
489
+ val conversation = fromIntro(envelope = envelope)
490
+ conversationsByTopic[conversation.topic] = conversation
491
+ val decrypted = conversation.decrypt(envelope)
492
+ emit(decrypted)
493
+ topics.add(conversation.topic)
494
+ subscribeFlow.value = makeSubscribeRequest(topics)
495
+ }
496
+
497
+ else -> {}
498
+ }
499
+ }
500
+ } catch (error: CancellationException ) {
501
+ break
502
+ } catch (error: StatusException ) {
503
+ if (error.status.code == io.grpc.Status .Code .UNAVAILABLE ) {
504
+ continue
505
+ } else {
506
+ break
507
+ }
508
+ } catch (error: Exception ) {
509
+ continue
510
+ }
511
+ }
512
+ }
426
513
}
0 commit comments