From f6583ffcf1fe8399fcd22ffa7a75fd97e55ff2a4 Mon Sep 17 00:00:00 2001 From: acite <1498045907@qq.com> Date: Sun, 7 Sep 2025 23:04:15 +0800 Subject: [PATCH] [feat] Smart Server Selection --- .../acitelight/aether/service/ApiClient.kt | 43 ++++++++++++++++--- .../aether/viewModel/HomeScreenViewModel.kt | 3 +- .../aether/viewModel/MeScreenViewModel.kt | 4 +- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/acitelight/aether/service/ApiClient.kt b/app/src/main/java/com/acitelight/aether/service/ApiClient.kt index 9d33cde..782c7c8 100644 --- a/app/src/main/java/com/acitelight/aether/service/ApiClient.kt +++ b/app/src/main/java/com/acitelight/aether/service/ApiClient.kt @@ -3,6 +3,8 @@ package com.acitelight.aether.service import android.content.Context import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import okhttp3.CertificatePinner import okhttp3.HttpUrl @@ -12,6 +14,9 @@ import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.io.ByteArrayInputStream +import java.net.HttpURLConnection +import java.net.InetAddress +import java.net.URL import java.security.KeyStore import java.security.cert.Certificate import java.security.cert.CertificateFactory @@ -88,19 +93,43 @@ object ApiClient { var api: ApiInterface? = null - fun apply(url: String, crt: String) - { - try{ - domain = url.toHttpUrlOrNull()?.host !! + suspend fun apply(urls: String, crt: String): String? { + try { + val urlList = urls.split(";").map { it.trim() } + + var selectedUrl: String? = null + for (url in urlList) { + val host = url.toHttpUrlOrNull()?.host + if (host != null && pingHost(host)) { + selectedUrl = url + break + } + } + + if (selectedUrl == null) { + throw Exception("No reachable URL found") + } + + domain = selectedUrl.toHttpUrlOrNull()?.host ?: "" cert = crt - base = url + base = selectedUrl api = createRetrofit().create(ApiInterface::class.java) - }catch (e: Exception) - { + return base + } catch (e: Exception) { api = null base = "" domain = "" cert = "" + return null + } + } + + private suspend fun pingHost(host: String): Boolean = withContext(Dispatchers.IO) { + return@withContext try { + val address = InetAddress.getByName(host) + address.isReachable(200) + } catch (e: Exception) { + false } } } \ No newline at end of file diff --git a/app/src/main/java/com/acitelight/aether/viewModel/HomeScreenViewModel.kt b/app/src/main/java/com/acitelight/aether/viewModel/HomeScreenViewModel.kt index 1a3f016..77278d4 100644 --- a/app/src/main/java/com/acitelight/aether/viewModel/HomeScreenViewModel.kt +++ b/app/src/main/java/com/acitelight/aether/viewModel/HomeScreenViewModel.kt @@ -1,6 +1,7 @@ package com.acitelight.aether.viewModel import android.app.Application +import android.widget.Toast import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel @@ -86,7 +87,7 @@ class HomeScreenViewModel(application: Application) : AndroidViewModel(applicati if(u=="" || p=="" || ur=="" || c=="") return@launch try{ - ApiClient.apply(ur, c) + val usedUrl = ApiClient.apply(ur, c) if (MediaManager.token == "null") MediaManager.token = AuthManager.fetchToken( diff --git a/app/src/main/java/com/acitelight/aether/viewModel/MeScreenViewModel.kt b/app/src/main/java/com/acitelight/aether/viewModel/MeScreenViewModel.kt index d79dd82..624a6eb 100644 --- a/app/src/main/java/com/acitelight/aether/viewModel/MeScreenViewModel.kt +++ b/app/src/main/java/com/acitelight/aether/viewModel/MeScreenViewModel.kt @@ -76,14 +76,14 @@ class MeScreenViewModel(application: Application) : AndroidViewModel(application if (u == "" || c == "" || p == "" || us == "") return@launch try { - ApiClient.apply(u, c) + val usedUrl = ApiClient.apply(u, c) MediaManager.token = AuthManager.fetchToken( us, p )!! Global.loggedIn = true - Toast.makeText(context, "Server Updated", Toast.LENGTH_SHORT).show() + Toast.makeText(context, "Server Updated, Used Url: $usedUrl", Toast.LENGTH_SHORT).show() } catch (e: Exception) { print(e.message) Toast.makeText(context, "Invalid Account or Server Information", Toast.LENGTH_SHORT).show()