1
1
package org.xmtp.android.library
2
2
3
3
import com.google.protobuf.kotlin.toByteString
4
+ import io.grpc.Grpc
5
+ import io.grpc.InsecureChannelCredentials
6
+ import io.grpc.ManagedChannel
4
7
import kotlinx.coroutines.flow.Flow
5
8
import kotlinx.coroutines.flow.flow
6
9
import org.xmtp.android.library.messages.Pagination
7
10
import org.xmtp.android.library.messages.Topic
8
- import org.xmtp.proto.message.api.v1.MessageApiOuterClass.BatchQueryResponse
9
- import org.xmtp.proto.message.api.v1.MessageApiOuterClass.Cursor
10
- import org.xmtp.proto.message.api.v1.MessageApiOuterClass.Envelope
11
- import org.xmtp.proto.message.api.v1.MessageApiOuterClass.PagingInfo
12
- import org.xmtp.proto.message.api.v1.MessageApiOuterClass.QueryRequest
11
+ import io.grpc.Metadata
12
+ import io.grpc.TlsChannelCredentials
13
+ import org.xmtp.proto.message.api.v1.MessageApiGrpcKt
14
+ import org.xmtp.proto.message.api.v1.MessageApiOuterClass.*
13
15
import org.xmtp.proto.message.api.v1.MessageApiOuterClass.QueryResponse
14
- import org.xmtp.proto.message.api.v1.MessageApiOuterClass.SortDirection
15
16
import uniffi.xmtpv3.FfiCursor
16
17
import uniffi.xmtpv3.FfiEnvelope
17
18
import uniffi.xmtpv3.FfiPagingInfo
@@ -24,6 +25,7 @@ import uniffi.xmtpv3.FfiV2QueryRequest
24
25
import uniffi.xmtpv3.FfiV2QueryResponse
25
26
import uniffi.xmtpv3.FfiV2SubscribeRequest
26
27
import java.io.Closeable
28
+ import java.util.concurrent.TimeUnit
27
29
28
30
interface ApiClient {
29
31
val environment: XMTPEnvironment
@@ -38,7 +40,7 @@ interface ApiClient {
38
40
suspend fun batchQuery (requests : List <QueryRequest >): BatchQueryResponse
39
41
suspend fun envelopes (topic : String , pagination : Pagination ? = null): List <Envelope >
40
42
suspend fun publish (envelopes : List <Envelope >)
41
- suspend fun subscribe (topics : List < String >): Flow <Envelope >
43
+ suspend fun subscribe (request : Flow < SubscribeRequest >): Flow <Envelope >
42
44
}
43
45
44
46
data class GRPCApiClient (
@@ -48,6 +50,13 @@ data class GRPCApiClient(
48
50
) :
49
51
ApiClient , Closeable {
50
52
companion object {
53
+
54
+ val CLIENT_VERSION_HEADER_KEY : Metadata .Key <String > =
55
+ Metadata .Key .of(" X-Client-Version" , Metadata .ASCII_STRING_MARSHALLER )
56
+
57
+ val APP_VERSION_HEADER_KEY : Metadata .Key <String > =
58
+ Metadata .Key .of(" X-App-Version" , Metadata .ASCII_STRING_MARSHALLER )
59
+
51
60
fun makeQueryRequest (
52
61
topic : String ,
53
62
pagination : Pagination ? = null,
@@ -76,6 +85,26 @@ data class GRPCApiClient(
76
85
}.build()
77
86
}
78
87
}.build()
88
+
89
+ fun makeSubscribeRequest (
90
+ topics : List <String >,
91
+ ): SubscribeRequest = SubscribeRequest .newBuilder().addAllContentTopics(topics).build()
92
+ }
93
+
94
+ private val channel: ManagedChannel by lazy {
95
+ Grpc .newChannelBuilderForAddress(
96
+ environment.getValue(),
97
+ if (environment == XMTPEnvironment .LOCAL ) 5556 else 443 ,
98
+ if (environment != XMTPEnvironment .LOCAL ) {
99
+ TlsChannelCredentials .create()
100
+ } else {
101
+ InsecureChannelCredentials .create()
102
+ },
103
+ ).build()
104
+ }
105
+
106
+ private val client: MessageApiGrpcKt .MessageApiCoroutineStub by lazy {
107
+ MessageApiGrpcKt .MessageApiCoroutineStub (channel)
79
108
}
80
109
81
110
private var authToken: String? = null
@@ -133,25 +162,19 @@ data class GRPCApiClient(
133
162
rustV2Client.publish(request = request, authToken = authToken ? : " " )
134
163
}
135
164
136
- override suspend fun subscribe (topics : List <String >): Flow <Envelope > = flow {
137
- try {
138
- val subscription = rustV2Client.subscribe(FfiV2SubscribeRequest (topics))
139
- try {
140
- while (true ) {
141
- val nextEnvelope = subscription.next()
142
- emit(envelopeFromFFi(nextEnvelope))
143
- }
144
- } catch (e: Exception ) {
145
- throw e
146
- } finally {
147
- subscription.end()
148
- }
149
- } catch (e: Exception ) {
150
- throw e
165
+ override suspend fun subscribe (request : Flow <SubscribeRequest >): Flow <Envelope > {
166
+ val headers = Metadata ()
167
+ headers.put(CLIENT_VERSION_HEADER_KEY , Constants .VERSION )
168
+ if (appVersion != null ) {
169
+ headers.put(APP_VERSION_HEADER_KEY , appVersion)
151
170
}
171
+
172
+ return client.subscribe2(request, headers)
152
173
}
174
+
153
175
override fun close () {
154
176
rustV2Client.close()
177
+ channel.shutdown().awaitTermination(5 , TimeUnit .SECONDS )
155
178
}
156
179
157
180
private fun envelopeToFFi (envelope : Envelope ): FfiEnvelope {
0 commit comments