Point Android monitor to public bot API

This commit is contained in:
Codex
2026-06-26 21:52:17 +03:00
parent 2706242fc7
commit 9c983ac0bb
4 changed files with 52 additions and 11 deletions
+8 -2
View File
@@ -33,10 +33,16 @@ android/TradeBotMonitor/app/build/outputs/apk/debug/app-debug.apk
В настройках приложения укажи адрес API, например:
```text
http://192.168.0.185:8787
https://tb.kusoft.xyz
```
Важно: сейчас Docker на Pi пробрасывает порт как `127.0.0.1:8787:8787`, то есть API доступен только на самом Pi. Для телефона нужен безопасный доступ по LAN/VPN/reverse proxy или осознанное изменение проброса порта.
Этот адрес установлен в приложении по умолчанию. Если в настройках ввести просто `tb.kusoft.xyz`, приложение само добавит `https://`.
Если домен защищён авторизацией, в поле `API auth` можно указать:
- `login:password` — приложение отправит HTTP Basic;
- `Basic ...` — готовый Basic header;
- `Bearer ...` или просто токен — приложение отправит Bearer.
## Переобучение
@@ -5,9 +5,16 @@ import android.content.Context
class AppPrefs(context: Context) {
private val prefs = context.getSharedPreferences("tradebot_monitor", Context.MODE_PRIVATE)
init {
val saved = prefs.getString("api_base_url", null)?.trim()
if (saved.isNullOrBlank() || saved == LEGACY_PI_API_BASE_URL) {
prefs.edit().putString("api_base_url", DEFAULT_API_BASE_URL).apply()
}
}
var apiBaseUrl: String
get() = prefs.getString("api_base_url", "http://192.168.0.185:8787") ?: "http://192.168.0.185:8787"
set(value) = prefs.edit().putString("api_base_url", value.trim().trimEnd('/')).apply()
get() = normalizeBaseUrl(prefs.getString("api_base_url", DEFAULT_API_BASE_URL) ?: DEFAULT_API_BASE_URL)
set(value) = prefs.edit().putString("api_base_url", normalizeBaseUrl(value)).apply()
var commandToken: String
get() = prefs.getString("command_token", "") ?: ""
@@ -32,4 +39,19 @@ class AppPrefs(context: Context) {
var retrainIntervalHours: Int
get() = prefs.getInt("retrain_interval_hours", 6)
set(value) = prefs.edit().putInt("retrain_interval_hours", value.coerceAtLeast(1)).apply()
private fun normalizeBaseUrl(value: String): String {
val trimmed = value.trim().trimEnd('/')
if (trimmed.isBlank()) return DEFAULT_API_BASE_URL
return if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
trimmed
} else {
"https://$trimmed"
}
}
private companion object {
const val DEFAULT_API_BASE_URL = "https://tb.kusoft.xyz"
const val LEGACY_PI_API_BASE_URL = "http://192.168.0.185:8787"
}
}
@@ -245,7 +245,7 @@ class MainActivity : Activity() {
val data = snapshot
val box = scrollContent()
val apiInput = input("Адрес API бота", prefs.apiBaseUrl)
val tokenInput = input("Токен команд, если включим защиту API", prefs.commandToken).apply {
val tokenInput = input("API auth: token, Bearer, Basic или login:password", prefs.commandToken).apply {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
}
box.addView(panel("Подключение", LinearLayout(this).apply {
@@ -1,5 +1,6 @@
package xyz.kusoft.tradebotmonitor
import android.util.Base64
import org.json.JSONArray
import org.json.JSONObject
import java.io.BufferedReader
@@ -63,9 +64,7 @@ class TradeBotApi(
connectTimeout = 6000
readTimeout = 9000
setRequestProperty("Accept", "application/json")
if (token.isNotBlank()) {
setRequestProperty("X-TradeBot-Token", token)
}
applyAuthHeaders(this, token)
if (method == "POST") {
doOutput = true
setRequestProperty("Content-Type", "application/json")
@@ -229,9 +228,7 @@ class RetrainCommandClient(
doOutput = true
setRequestProperty("Content-Type", "application/json")
setRequestProperty("Accept", "application/json,text/plain,*/*")
if (token.isNotBlank()) {
setRequestProperty("X-TradeBot-Token", token)
}
applyAuthHeaders(this, token)
outputStream.use { stream -> stream.write("{\"source\":\"android\"}".toByteArray(StandardCharsets.UTF_8)) }
}
val code = connection.responseCode
@@ -244,3 +241,19 @@ class RetrainCommandClient(
return text.ifBlank { "Команда retrain отправлена" }
}
}
private fun applyAuthHeaders(connection: HttpURLConnection, token: String) {
val value = token.trim()
if (value.isBlank()) return
connection.setRequestProperty("X-TradeBot-Token", value)
val authorization = when {
value.startsWith("Basic ", ignoreCase = true) -> value
value.startsWith("Bearer ", ignoreCase = true) -> value
":" in value -> {
val encoded = Base64.encodeToString(value.toByteArray(StandardCharsets.UTF_8), Base64.NO_WRAP)
"Basic $encoded"
}
else -> "Bearer $value"
}
connection.setRequestProperty("Authorization", authorization)
}