[feat] Smart Server Selection

This commit is contained in:
acite
2025-09-07 23:04:15 +08:00
parent aacd226260
commit f6583ffcf1
3 changed files with 40 additions and 10 deletions

View File

@@ -3,6 +3,8 @@ package com.acitelight.aether.service
import android.content.Context import android.content.Context
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.CertificatePinner import okhttp3.CertificatePinner
import okhttp3.HttpUrl import okhttp3.HttpUrl
@@ -12,6 +14,9 @@ import okhttp3.OkHttpClient
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.net.HttpURLConnection
import java.net.InetAddress
import java.net.URL
import java.security.KeyStore import java.security.KeyStore
import java.security.cert.Certificate import java.security.cert.Certificate
import java.security.cert.CertificateFactory import java.security.cert.CertificateFactory
@@ -88,19 +93,43 @@ object ApiClient {
var api: ApiInterface? = null var api: ApiInterface? = null
fun apply(url: String, crt: String) suspend fun apply(urls: String, crt: String): String? {
{ try {
try{ val urlList = urls.split(";").map { it.trim() }
domain = url.toHttpUrlOrNull()?.host !!
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 cert = crt
base = url base = selectedUrl
api = createRetrofit().create(ApiInterface::class.java) api = createRetrofit().create(ApiInterface::class.java)
}catch (e: Exception) return base
{ } catch (e: Exception) {
api = null api = null
base = "" base = ""
domain = "" domain = ""
cert = "" 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
} }
} }
} }

View File

@@ -1,6 +1,7 @@
package com.acitelight.aether.viewModel package com.acitelight.aether.viewModel
import android.app.Application import android.app.Application
import android.widget.Toast
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@@ -86,7 +87,7 @@ class HomeScreenViewModel(application: Application) : AndroidViewModel(applicati
if(u=="" || p=="" || ur=="" || c=="") return@launch if(u=="" || p=="" || ur=="" || c=="") return@launch
try{ try{
ApiClient.apply(ur, c) val usedUrl = ApiClient.apply(ur, c)
if (MediaManager.token == "null") if (MediaManager.token == "null")
MediaManager.token = AuthManager.fetchToken( MediaManager.token = AuthManager.fetchToken(

View File

@@ -76,14 +76,14 @@ class MeScreenViewModel(application: Application) : AndroidViewModel(application
if (u == "" || c == "" || p == "" || us == "") return@launch if (u == "" || c == "" || p == "" || us == "") return@launch
try { try {
ApiClient.apply(u, c) val usedUrl = ApiClient.apply(u, c)
MediaManager.token = AuthManager.fetchToken( MediaManager.token = AuthManager.fetchToken(
us, us,
p p
)!! )!!
Global.loggedIn = true 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) { } catch (e: Exception) {
print(e.message) print(e.message)
Toast.makeText(context, "Invalid Account or Server Information", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Invalid Account or Server Information", Toast.LENGTH_SHORT).show()