Skip to content

Commit e3efc8a

Browse files
authored
support config client with access token (#23)
1 parent e909dc9 commit e3efc8a

File tree

8 files changed

+67
-37
lines changed

8 files changed

+67
-37
lines changed

library/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ configurations {
1616

1717
dependencies {
1818
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
19+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
1920
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
2021
implementation "com.squareup.okhttp3:logging-interceptor:$okhttpVersion"
2122
implementation "org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion"

library/src/main/kotlin/one/mixin/bot/HttpClient.kt

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,21 @@ import java.security.Security
1616

1717
@Suppress("unused")
1818
class HttpClient private constructor(
19-
val safeUser: SafeUser,
19+
val safeUser: SafeUser?,
20+
private val accessToken: String? = null,
2021
debug: Boolean = false,
2122
) {
2223
init {
2324
Security.addProvider(BouncyCastleProvider())
2425
}
2526

2627
private val okHttpClient: OkHttpClient by lazy {
27-
createHttpClient(safeUser, false, debug)
28+
createHttpClient(safeUser, accessToken, false, debug)
2829
}
2930

3031
private val retrofit: Retrofit by lazy {
31-
val builder = Retrofit.Builder()
32-
.baseUrl(URL)
33-
.addCallAdapterFactory(CoroutineCallAdapterFactory())
34-
.addConverterFactory(GsonConverterFactory.create())
35-
.client(okHttpClient)
32+
val builder = Retrofit.Builder().baseUrl(URL).addCallAdapterFactory(CoroutineCallAdapterFactory())
33+
.addConverterFactory(GsonConverterFactory.create()).client(okHttpClient)
3634
builder.build()
3735
}
3836

@@ -91,8 +89,9 @@ class HttpClient private constructor(
9189
}
9290

9391
class Builder {
94-
private lateinit var safeUser: SafeUser
92+
private var safeUser: SafeUser? = null
9593
private var debug: Boolean = false
94+
private var accessToken: String? = null
9695

9796
fun configSafeUser(
9897
userId: String,
@@ -101,7 +100,13 @@ class HttpClient private constructor(
101100
serverPublicKey: ByteArray? = null,
102101
spendPrivateKey: ByteArray? = null,
103102
): Builder {
104-
safeUser = SafeUser(userId, sessionId, sessionPrivateKey.sliceArray(0..31), serverPublicKey, spendPrivateKey)
103+
safeUser =
104+
SafeUser(userId, sessionId, sessionPrivateKey.sliceArray(0..31), serverPublicKey, spendPrivateKey)
105+
return this
106+
}
107+
108+
fun configAccessToken(accessToken: String): Builder {
109+
this.accessToken = accessToken
105110
return this
106111
}
107112

@@ -111,7 +116,10 @@ class HttpClient private constructor(
111116
}
112117

113118
fun build(): HttpClient {
114-
return HttpClient(safeUser, debug)
119+
require(!(safeUser == null && accessToken == null)) { "safeUser and accessToken can't be null at the same time" }
120+
return HttpClient(safeUser, accessToken, debug)
115121
}
116122
}
123+
124+
117125
}

library/src/main/kotlin/one/mixin/bot/api/call/UtxoCallService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import retrofit2.http.Query
1919
interface UtxoCallService {
2020
@GET("safe/outputs")
2121
fun getOutputsCall(
22-
@Query("members") members: String,
22+
@Query("members") members: String?,
2323
@Query("threshold") threshold: Int,
2424
@Query("offset") offset: Long? = null,
2525
@Query("limit") limit: Int = 500,

library/src/main/kotlin/one/mixin/bot/blaze/BlazeClient.kt

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class BlazeClient private constructor(
3030
private var reconnectInterval = 5000
3131

3232
private val okHttpClient: OkHttpClient by lazy {
33-
createHttpClient(safeUser, true, debug)
33+
createHttpClient(safeUser, null, true, debug)
3434
}
3535

3636
private var webSocket: WebSocket? = null
@@ -80,7 +80,8 @@ class BlazeClient private constructor(
8080
serverPublicKey: ByteArray? = null,
8181
spendPrivateKey: ByteArray? = null,
8282
): Builder {
83-
safeUser = SafeUser(userId, sessionId, sessionPrivateKey.sliceArray(0..31), serverPublicKey, spendPrivateKey)
83+
safeUser =
84+
SafeUser(userId, sessionId, sessionPrivateKey.sliceArray(0..31), serverPublicKey, spendPrivateKey)
8485
return this
8586
}
8687

@@ -124,8 +125,7 @@ class BlazeClient private constructor(
124125
}
125126

126127
override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
127-
try {
128-
// 消息通的时,重置连接次数
128+
try { // 消息通的时,重置连接次数
129129
connectCount = 0
130130

131131
val blazeMsg = decodeAs(bytes, parseData)
@@ -163,17 +163,26 @@ fun sendMsg(webSocket: WebSocket, action: Action, msgParam: MsgParam?): Boolean
163163
}
164164

165165
fun sendTextMsg(webSocket: WebSocket, conversationId: String, recipientId: String, text: String): Boolean {
166-
val msgParam = MsgParam(UUID.randomUUID().toString(), Category.PLAIN_TEXT.toString(), conversationId, recipientId, text)
166+
val msgParam =
167+
MsgParam(UUID.randomUUID().toString(), Category.PLAIN_TEXT.toString(), conversationId, recipientId, text)
167168
return sendMsg(webSocket, Action.CREATE_MESSAGE, msgParam)
168169
}
169170

170171
fun sendCardMsg(webSocket: WebSocket, conversationId: String, recipientId: String, cards: Cards): Boolean {
171-
val msgParam = MsgParam(UUID.randomUUID().toString(), Category.APP_CARD.toString(), conversationId, recipientId, Gson().toJson(cards))
172+
val msgParam = MsgParam(
173+
UUID.randomUUID().toString(), Category.APP_CARD.toString(), conversationId, recipientId, Gson().toJson(cards)
174+
)
172175
return sendMsg(webSocket, Action.CREATE_MESSAGE, msgParam)
173176
}
174177

175178
fun sendButtonsMsg(webSocket: WebSocket, conversationId: String, recipientId: String, buttons: List<Buttons>): Boolean {
176-
val msgParam = MsgParam(UUID.randomUUID().toString(), Category.APP_BUTTON_GROUP.toString(), conversationId, recipientId, Gson().toJson(buttons))
179+
val msgParam = MsgParam(
180+
UUID.randomUUID().toString(),
181+
Category.APP_BUTTON_GROUP.toString(),
182+
conversationId,
183+
recipientId,
184+
Gson().toJson(buttons)
185+
)
177186
return sendMsg(webSocket, Action.CREATE_MESSAGE, msgParam)
178187
}
179188

library/src/main/kotlin/one/mixin/bot/safe/Output.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import java.math.BigDecimal
77

88
fun assetBalance(
99
botClient: HttpClient, assetId: String,
10-
members: List<String> = listOf(botClient.safeUser.userId),
10+
members: List<String> = listOf(),
1111
): String {
1212
val outputs = listUnspentOutputs(
1313
botClient, buildHashMembers(members), 1, assetId
@@ -37,8 +37,9 @@ fun listOutputs(
3737
offset: Long,
3838
limit: Int,
3939
): List<Output> {
40-
val resp =
41-
botClient.utxoService.getOutputsCall(membersHash, threshold, offset, limit, state, assetId).execute().body()
40+
val resp = botClient.utxoService.getOutputsCall(
41+
membersHash.ifEmpty { null }, threshold, offset, limit, state, assetId
42+
).execute().body()
4243
if (resp == null || !resp.isSuccess()) {
4344
throw SafeException("get safe/outputs ${resp?.error}")
4445
}

library/src/main/kotlin/one/mixin/bot/safe/Transaction.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ fun sendTransactionToUser(
3636
memo: String?,
3737
traceId: String,
3838
): List<TransactionResponse> {
39+
requireNotNull(botClient.safeUser) { "safe user is null" }
3940
verifyTxId(botClient, traceId) // check assetId is kernel assetId
4041

4142
// get unspent outputs for asset and may throw insufficient outputs error
@@ -122,6 +123,7 @@ suspend fun withdrawalToAddress(
122123
memo: String? = null,
123124
traceId: String = UUID.randomUUID().toString(),
124125
): List<TransactionResponse> {
126+
requireNotNull(botClient.safeUser) { "safe user is null" }
125127
verifyTxId(botClient, traceId)
126128
val token = botClient.tokenService.getAssetById(assetId).requiredData()
127129
val chain = if (token.assetId == token.chainId) {
@@ -245,7 +247,7 @@ private suspend fun HttpClient.withdrawalTransaction(
245247
val withdrawalData = requestResponse.first { it.requestId == traceId }
246248
val feeData = requestResponse.first { it.requestId == feeTraceId }
247249

248-
val spendKey = safeUser.spendPrivateKey ?: throw SafeException("spend key is null")
250+
val spendKey = safeUser?.spendPrivateKey ?: throw SafeException("spend key is null")
249251

250252
val signedWithdrawalRaw = withdrawalTx.sign(withdrawalData.views, utxos, spendKey.toHex())
251253
val signedFeeRaw = feeTx.sign(feeData.views, feeUtxos, spendKey.toHex())
@@ -302,7 +304,7 @@ private suspend fun HttpClient.withdrawalTransaction(
302304
utxoService.transactionRequest(listOf(TransactionRequest(tx.encodeToString(), traceId))).requiredData()
303305
.firstOrNull() ?: throw SafeException("request transaction response data null")
304306

305-
val spendKey = safeUser.spendPrivateKey ?: throw SafeException("spend key is null")
307+
val spendKey = safeUser?.spendPrivateKey ?: throw SafeException("spend key is null")
306308
val signedRaw = tx.sign(verifiedTx.views, utxos, spendKey.toHex())
307309

308310
utxoService.transactions(listOf(TransactionRequest(signedRaw, traceId))).requiredData()
@@ -313,6 +315,7 @@ private fun requestUnspentOutputsForRecipients(
313315
assetId: String,
314316
amount: String,
315317
): Pair<List<Output>, BigDecimal> {
318+
requireNotNull(botClient.safeUser) { "safe user is null" }
316319
val memberHash = buildHashMembers(listOf(botClient.safeUser.userId))
317320
val outputs = listUnspentOutputs(botClient, memberHash, 1, assetId)
318321
if (outputs.isEmpty()) {
@@ -333,6 +336,9 @@ private fun requestUnspentOutputsForRecipients(
333336
}
334337

335338
fun buildHashMembers(ids: List<String>): String {
339+
if (ids.isEmpty()) {
340+
return ""
341+
}
336342
return ids.sortedBy { it }.joinToString("").sha3Sum256().joinToString("") { "%02x".format(it) }
337343
}
338344

library/src/main/kotlin/one/mixin/bot/util/OkHttpProvider.kt

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ import java.util.*
1515
import java.util.concurrent.TimeUnit
1616

1717
fun createHttpClient(
18-
safeUser: SafeUser,
18+
safeUser: SafeUser?,
19+
accessToken: String?,
1920
websocket: Boolean,
2021
debug: Boolean,
2122
): OkHttpClient {
23+
require(!(safeUser == null && accessToken == null)) { "safeUser and accessToken can't be null at the same time" }
24+
2225
val builder = OkHttpClient.Builder()
2326
if (debug) {
2427
val logging = HttpLoggingInterceptor()
@@ -52,25 +55,24 @@ fun createHttpClient(
5255
if (websocket) {
5356
requestBuilder.addHeader("Sec-WebSocket-Protocol", "MixinBot-Blaze-1")
5457
}
55-
requestBuilder.addHeader("User-Agent", Constants.UA).addHeader("Accept-Language", Locale.getDefault().language).addHeader(
56-
"Authorization",
57-
"Bearer " +
58-
signToken(
59-
safeUser.userId,
58+
requestBuilder.addHeader("User-Agent", Constants.UA)
59+
.addHeader("Accept-Language", Locale.getDefault().language).addHeader(
60+
"Authorization",
61+
"Bearer " + (accessToken ?: signToken(
62+
safeUser!!.userId,
6063
safeUser.sessionId,
6164
chain.request(),
6265
EdDSAPrivateKey(safeUser.sessionPrivateKey.toByteString()),
63-
),
64-
)
66+
)),
67+
)
6568

6669
val request = requestBuilder.build()
6770

68-
val response =
69-
try {
70-
chain.proceed(request)
71-
} catch (e: Exception) {
72-
throw e
73-
}
71+
val response = try {
72+
chain.proceed(request)
73+
} catch (e: Exception) {
74+
throw e
75+
}
7476

7577
if (!response.isSuccessful) {
7678
val code = response.code

samples/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,7 @@ dependencies {
2121
// Kotlin
2222
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
2323
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
24+
25+
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
26+
2427
}

0 commit comments

Comments
 (0)