Skip to content

Commit 28e66c0

Browse files
committed
Auto switch host
1 parent da4e71d commit 28e66c0

File tree

5 files changed

+120
-21
lines changed

5 files changed

+120
-21
lines changed

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ import one.mixin.bot.api.SnapshotService
1818
import one.mixin.bot.api.UserService
1919
import one.mixin.bot.api.exception.ClientErrorException
2020
import one.mixin.bot.api.exception.ServerErrorException
21+
import one.mixin.bot.extension.HostSelectionInterceptor
2122
import one.mixin.bot.extension.base64Decode
2223
import one.mixin.bot.extension.base64Encode
24+
import one.mixin.bot.extension.isNeedSwitch
2325
import one.mixin.bot.util.getRSAPrivateKeyFromString
2426
import one.mixin.bot.vo.RpcRequest
2527
import org.bouncycastle.jce.provider.BouncyCastleProvider
@@ -33,7 +35,8 @@ import java.util.concurrent.TimeUnit
3335
class HttpClient private constructor(
3436
private val clientToken: SessionToken,
3537
cnServer: Boolean = false,
36-
debug: Boolean = false
38+
debug: Boolean = false,
39+
autoSwitch: Boolean = false
3740
) {
3841

3942
init {
@@ -59,7 +62,7 @@ class HttpClient private constructor(
5962
builder.readTimeout(10, TimeUnit.SECONDS)
6063
builder.pingInterval(15, TimeUnit.SECONDS)
6164
builder.retryOnConnectionFailure(false)
62-
65+
builder.addInterceptor(HostSelectionInterceptor.get(if (cnServer) { CN_URL } else { URL }))
6366
builder.addInterceptor(
6467
Interceptor { chain ->
6568
val request = chain.request().newBuilder()
@@ -90,9 +93,15 @@ class HttpClient private constructor(
9093
val response = try {
9194
chain.proceed(request)
9295
} catch (e: Exception) {
93-
if (e.message?.contains("502") == true) {
94-
throw ServerErrorException(502)
95-
} else throw e
96+
throw e.apply {
97+
if (autoSwitch && e.isNeedSwitch()) {
98+
HostSelectionInterceptor.get().switch(request)
99+
} else {
100+
if (e.message?.contains("502") == true) {
101+
throw ServerErrorException(502)
102+
} else throw e
103+
}
104+
}
96105
}
97106

98107
if (!response.isSuccessful) {
@@ -160,6 +169,7 @@ class HttpClient private constructor(
160169
private lateinit var clientToken: SessionToken
161170
private var cnServer: Boolean = false
162171
private var debug: Boolean = false
172+
private var autoSwitch: Boolean = false
163173

164174
fun configEdDSA(
165175
userId: String,
@@ -191,8 +201,14 @@ class HttpClient private constructor(
191201
return this
192202
}
193203

204+
205+
fun enableAutoSwitch(): Builder {
206+
debug = true
207+
return this
208+
}
209+
194210
fun build(): HttpClient {
195-
return HttpClient(clientToken, cnServer, debug)
211+
return HttpClient(clientToken, cnServer, debug, autoSwitch)
196212
}
197213
}
198214
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package one.mixin.bot.extension
2+
3+
import okhttp3.HttpUrl
4+
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
5+
import okhttp3.Interceptor
6+
import okhttp3.Request
7+
import one.mixin.bot.Constants
8+
import one.mixin.bot.Constants.API.URL
9+
import java.io.IOException
10+
import java.net.ConnectException
11+
import java.net.NoRouteToHostException
12+
import java.net.ProtocolException
13+
import java.net.SocketException
14+
import java.net.SocketTimeoutException
15+
import java.net.UnknownHostException
16+
import javax.net.ssl.SSLHandshakeException
17+
import javax.net.ssl.SSLPeerUnverifiedException
18+
19+
fun Throwable.isNeedSwitch(): Boolean {
20+
return (
21+
this is SocketTimeoutException ||
22+
this is UnknownHostException ||
23+
this is ConnectException ||
24+
this is ProtocolException ||
25+
this is NoRouteToHostException ||
26+
this is SocketException ||
27+
this is SSLPeerUnverifiedException ||
28+
this is SSLHandshakeException
29+
)
30+
}
31+
32+
class HostSelectionInterceptor private constructor() : Interceptor {
33+
@Volatile
34+
private var host: HttpUrl? = URL.toHttpUrlOrNull()
35+
36+
private fun setHost(url: String) {
37+
CURRENT_URL = url
38+
this.host = url.toHttpUrlOrNull()
39+
}
40+
41+
fun switch(request: Request) {
42+
val currentUrl = "${request.url.scheme}://${request.url.host}/"
43+
if (currentUrl != host.toString()) return
44+
if (currentUrl == URL) {
45+
setHost(Constants.API.CN_URL)
46+
} else {
47+
setHost(URL)
48+
}
49+
}
50+
51+
@Throws(IOException::class)
52+
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
53+
var request = chain.request()
54+
if (request.header("Upgrade") == "websocket") {
55+
return chain.proceed(request)
56+
}
57+
this.host?.let {
58+
val newUrl = request.url.newBuilder()
59+
.host(it.toUrl().toURI().host)
60+
.build()
61+
request = request.newBuilder()
62+
.url(newUrl)
63+
.build()
64+
}
65+
return chain.proceed(request)
66+
}
67+
68+
companion object {
69+
var CURRENT_URL: String = URL
70+
private set
71+
72+
@Synchronized
73+
fun get(url: String? = null): HostSelectionInterceptor {
74+
if (instance == null) {
75+
if (url != null) {
76+
CURRENT_URL = url
77+
}
78+
instance = HostSelectionInterceptor()
79+
}
80+
return instance as HostSelectionInterceptor
81+
}
82+
83+
private var instance: HostSelectionInterceptor? = null
84+
}
85+
}

samples/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ java {
1010
}
1111

1212
dependencies {
13-
implementation 'com.github.MixinNetwork:bot-api-kotlin-client:v0.5.1'
14-
// implementation 'com.github.MixinNetwork:bot-api-kotlin-client:main-SNAPSHOT'
13+
implementation project(":library")
14+
// implementation 'com.github.MixinNetwork:bot-api-kotlin-client:v0.5.1'
1515

1616
// Kotlin
1717
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"

samples/src/main/java/jvmMain/java/Sample.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package jvmMain.java;
22

3-
import com.google.gson.JsonObject;
43
import kotlin.Unit;
54
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
65
import net.i2p.crypto.eddsa.EdDSAPublicKey;
@@ -30,7 +29,7 @@ public class Sample {
3029
public static void main(String[] args) {
3130
EdDSAPrivateKey key = getEdDSAPrivateKeyFromString(privateKey);
3231
String pinToken = decryASEKey(pinTokenPem, key);
33-
HttpClient client = new HttpClient.Builder().configEdDSA(userId, sessionId, key).build();
32+
HttpClient client = new HttpClient.Builder().configEdDSA(userId, sessionId, key).enableDebug().enableAutoSwitch().build();
3433
try {
3534
utxo(client);
3635

@@ -101,9 +100,9 @@ public static void main(String[] args) {
101100
}
102101

103102
private static void utxo(HttpClient client) throws IOException {
104-
JsonObject response = client.getExternalService().getUtxoCall("b6afed179a8192513990e29953e3a6875eab53050b1e174d5c83ab76bbbd4b29",0).execute().body();
105-
assert response != null;
106-
System.out.printf("%s%n", Utxo.Companion.fromJson(response.getAsJsonObject("data")).getHash());
103+
// JsonObject response = client.getExternalService().getUtxoCall("b6afed179a8192513990e29953e3a6875eab53050b1e174d5c83ab76bbbd4b29",0).execute().body();
104+
// assert response != null;
105+
// System.out.printf("%s%n", Utxo.Companion.fromJson(response.getAsJsonObject("data")).getHash());
107106
}
108107

109108
private static String createAddress(HttpClient client, String userAesKey) throws IOException {
@@ -249,13 +248,13 @@ private static void sendTextMessage(HttpClient client, String recipientId, Strin
249248
recipientId, UUID.randomUUID().toString(), "PLAIN_TEXT",
250249
Base64.getEncoder().encodeToString(text.getBytes()), null, null
251250
));
252-
MixinResponse messageResponse = client.getMessageService().postMessageCall(messageRequests).execute().body();
253-
assert messageResponse != null;
254-
if (messageResponse.isSuccess()) {
255-
System.out.println("Send success");
256-
} else {
257-
System.out.println("Send failure");
258-
}
251+
// MixinResponse messageResponse = client.getMessageService().postMessageCall(messageRequests).execute().body();
252+
// assert messageResponse != null;
253+
// if (messageResponse.isSuccess()) {
254+
// System.out.println("Send success");
255+
// } else {
256+
// System.out.println("Send failure");
257+
// }
259258
}
260259

261260
private static SessionToken getUserToken(User user, KeyPair sessionKey, boolean isRsa) {

samples/src/main/java/jvmMain/kotlin/Sample.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import one.mixin.bot.util.decryASEKey
1616
import one.mixin.bot.util.generateEd25519KeyPair
1717
import one.mixin.bot.util.getEdDSAPrivateKeyFromString
1818
import one.mixin.bot.vo.*
19-
import retrofit2.http.Query
2019
import java.util.Random
2120
import java.util.UUID
2221

0 commit comments

Comments
 (0)