1
+ @file:Suppress(" ktlint:standard:import-ordering" )
2
+
1
3
package io.iohk.atala.prism.walletsdk.prismagent
2
4
3
5
import io.iohk.atala.prism.walletsdk.domain.buildingblocks.Castor
@@ -9,8 +11,14 @@ import io.iohk.atala.prism.walletsdk.domain.models.Message
9
11
import io.iohk.atala.prism.walletsdk.prismagent.connectionsmanager.ConnectionsManager
10
12
import io.iohk.atala.prism.walletsdk.prismagent.connectionsmanager.DIDCommConnection
11
13
import io.iohk.atala.prism.walletsdk.prismagent.mediation.MediationHandler
14
+ import java.time.Duration
15
+ import kotlinx.coroutines.CoroutineScope
16
+ import kotlinx.coroutines.Dispatchers
17
+ import kotlinx.coroutines.Job
18
+ import kotlinx.coroutines.delay
12
19
import kotlinx.coroutines.flow.Flow
13
20
import kotlinx.coroutines.flow.first
21
+ import kotlinx.coroutines.launch
14
22
import kotlin.jvm.Throws
15
23
16
24
/* *
@@ -27,9 +35,99 @@ class ConnectionManager(
27
35
private val castor : Castor ,
28
36
private val pluto : Pluto ,
29
37
internal val mediationHandler : MediationHandler ,
30
- private var pairings : MutableList <DIDPair >
38
+ private var pairings : MutableList <DIDPair >,
39
+ private val scope : CoroutineScope = CoroutineScope (Dispatchers .IO )
31
40
) : ConnectionsManager, DIDCommConnection {
32
41
42
+ var fetchingMessagesJob: Job ? = null
43
+
44
+ /* *
45
+ * Starts the process of fetching messages at a regular interval.
46
+ *
47
+ * @param requestInterval The time interval (in seconds) between message fetch requests.
48
+ * Defaults to 5 seconds if not specified.
49
+ */
50
+ @JvmOverloads
51
+ fun startFetchingMessages (requestInterval : Int = 5) {
52
+ // Check if the job for fetching messages is already running
53
+ if (fetchingMessagesJob == null ) {
54
+ // Launch a coroutine in the provided scope
55
+ fetchingMessagesJob = scope.launch {
56
+ // Retrieve the current mediator DID
57
+ val currentMediatorDID = mediationHandler.mediatorDID
58
+ // Resolve the DID document for the mediator
59
+ val mediatorDidDoc = castor.resolveDID(currentMediatorDID.toString())
60
+ var serviceEndpoint: String? = null
61
+
62
+ // Loop through the services in the DID document to find a WebSocket endpoint
63
+ mediatorDidDoc.services.forEach {
64
+ if (it.serviceEndpoint.uri.contains(" wss://" ) || it.serviceEndpoint.uri.contains(" ws://" )) {
65
+ serviceEndpoint = it.serviceEndpoint.uri
66
+ return @forEach // Exit loop once the WebSocket endpoint is found
67
+ }
68
+ }
69
+
70
+ // If a WebSocket service endpoint is found
71
+ serviceEndpoint?.let { serviceEndpointUrl ->
72
+ // Listen for unread messages on the WebSocket endpoint
73
+ mediationHandler.listenUnreadMessages(
74
+ serviceEndpointUrl
75
+ ) { arrayMessages ->
76
+ // Process the received messages
77
+ val messagesIds = mutableListOf<String >()
78
+ val messages = mutableListOf<Message >()
79
+ arrayMessages.map { pair ->
80
+ messagesIds.add(pair.first)
81
+ messages.add(pair.second)
82
+ }
83
+ // If there are any messages, mark them as read and store them
84
+ scope.launch {
85
+ if (messagesIds.isNotEmpty()) {
86
+ mediationHandler.registerMessagesAsRead(
87
+ messagesIds.toTypedArray()
88
+ )
89
+ pluto.storeMessages(messages)
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ // Fallback mechanism if no WebSocket service endpoint is available
96
+ if (serviceEndpoint == null ) {
97
+ while (true ) {
98
+ // Continuously await and process new messages
99
+ awaitMessages().collect { array ->
100
+ val messagesIds = mutableListOf<String >()
101
+ val messages = mutableListOf<Message >()
102
+ array.map { pair ->
103
+ messagesIds.add(pair.first)
104
+ messages.add(pair.second)
105
+ }
106
+ if (messagesIds.isNotEmpty()) {
107
+ mediationHandler.registerMessagesAsRead(
108
+ messagesIds.toTypedArray()
109
+ )
110
+ pluto.storeMessages(messages)
111
+ }
112
+ }
113
+ // Wait for the specified request interval before fetching new messages
114
+ delay(Duration .ofSeconds(requestInterval.toLong()).toMillis())
115
+ }
116
+ }
117
+ }
118
+
119
+ // Start the coroutine if it's not already active
120
+ fetchingMessagesJob?.let {
121
+ if (it.isActive) return
122
+ it.start()
123
+ }
124
+ }
125
+ }
126
+
127
+ fun stopConnection () {
128
+ fetchingMessagesJob?.cancel()
129
+ }
130
+
33
131
/* *
34
132
* Suspends the current coroutine and boots the registered mediator associated with the mediator handler.
35
133
* If no mediator is available, a [PrismAgentError.NoMediatorAvailableError] is thrown.
0 commit comments