diff --git a/android/app/src/main/java/org/flowseal/tgwsproxy/MainActivity.kt b/android/app/src/main/java/org/flowseal/tgwsproxy/MainActivity.kt
index 2a178b3..727be4f 100644
--- a/android/app/src/main/java/org/flowseal/tgwsproxy/MainActivity.kt
+++ b/android/app/src/main/java/org/flowseal/tgwsproxy/MainActivity.kt
@@ -108,6 +108,9 @@ class MainActivity : AppCompatActivity() {
binding.hostInput.setText(config.host)
binding.portInput.setText(config.portText)
binding.dcIpInput.setText(config.dcIpText)
+ binding.logMaxMbInput.setText(config.logMaxMbText)
+ binding.bufferKbInput.setText(config.bufferKbText)
+ binding.poolSizeInput.setText(config.poolSizeText)
binding.verboseSwitch.isChecked = config.verbose
}
@@ -116,6 +119,9 @@ class MainActivity : AppCompatActivity() {
host = binding.hostInput.text?.toString().orEmpty(),
portText = binding.portInput.text?.toString().orEmpty(),
dcIpText = binding.dcIpInput.text?.toString().orEmpty(),
+ logMaxMbText = binding.logMaxMbInput.text?.toString().orEmpty(),
+ bufferKbText = binding.bufferKbInput.text?.toString().orEmpty(),
+ poolSizeText = binding.poolSizeInput.text?.toString().orEmpty(),
verbose = binding.verboseSwitch.isChecked,
)
}
diff --git a/android/app/src/main/java/org/flowseal/tgwsproxy/ProxyConfig.kt b/android/app/src/main/java/org/flowseal/tgwsproxy/ProxyConfig.kt
index a8ffcde..39cf065 100644
--- a/android/app/src/main/java/org/flowseal/tgwsproxy/ProxyConfig.kt
+++ b/android/app/src/main/java/org/flowseal/tgwsproxy/ProxyConfig.kt
@@ -4,6 +4,9 @@ data class ProxyConfig(
val host: String = DEFAULT_HOST,
val portText: String = DEFAULT_PORT.toString(),
val dcIpText: String = DEFAULT_DC_IP_LINES.joinToString("\n"),
+ val logMaxMbText: String = formatDecimal(DEFAULT_LOG_MAX_MB),
+ val bufferKbText: String = DEFAULT_BUFFER_KB.toString(),
+ val poolSizeText: String = DEFAULT_POOL_SIZE.toString(),
val verbose: Boolean = false,
) {
fun validate(): ValidationResult {
@@ -37,11 +40,44 @@ data class ProxyConfig(
}
}
+ val logMaxMbValue = logMaxMbText.trim().toDoubleOrNull()
+ ?: return ValidationResult(
+ errorMessage = "Размер лог-файла должен быть числом."
+ )
+ if (logMaxMbValue <= 0.0) {
+ return ValidationResult(
+ errorMessage = "Размер лог-файла должен быть больше нуля."
+ )
+ }
+
+ val bufferKbValue = bufferKbText.trim().toIntOrNull()
+ ?: return ValidationResult(
+ errorMessage = "Буфер сокета должен быть целым числом."
+ )
+ if (bufferKbValue < 4) {
+ return ValidationResult(
+ errorMessage = "Буфер сокета должен быть не меньше 4 KB."
+ )
+ }
+
+ val poolSizeValue = poolSizeText.trim().toIntOrNull()
+ ?: return ValidationResult(
+ errorMessage = "Размер WS pool должен быть целым числом."
+ )
+ if (poolSizeValue < 0) {
+ return ValidationResult(
+ errorMessage = "Размер WS pool не может быть отрицательным."
+ )
+ }
+
return ValidationResult(
normalized = NormalizedProxyConfig(
host = hostValue,
port = portValue,
dcIpList = lines,
+ logMaxMb = logMaxMbValue,
+ bufferKb = bufferKbValue,
+ poolSize = poolSizeValue,
verbose = verbose,
)
)
@@ -50,11 +86,22 @@ data class ProxyConfig(
companion object {
const val DEFAULT_HOST = "127.0.0.1"
const val DEFAULT_PORT = 1080
+ const val DEFAULT_LOG_MAX_MB = 5.0
+ const val DEFAULT_BUFFER_KB = 256
+ const val DEFAULT_POOL_SIZE = 4
val DEFAULT_DC_IP_LINES = listOf(
"2:149.154.167.220",
"4:149.154.167.220",
)
+ fun formatDecimal(value: Double): String {
+ return if (value % 1.0 == 0.0) {
+ value.toInt().toString()
+ } else {
+ value.toString()
+ }
+ }
+
private fun isIpv4Address(value: String): Boolean {
val octets = value.split(".")
if (octets.size != 4) {
@@ -80,5 +127,8 @@ data class NormalizedProxyConfig(
val host: String,
val port: Int,
val dcIpList: List,
+ val logMaxMb: Double,
+ val bufferKb: Int,
+ val poolSize: Int,
val verbose: Boolean,
)
diff --git a/android/app/src/main/java/org/flowseal/tgwsproxy/ProxySettingsStore.kt b/android/app/src/main/java/org/flowseal/tgwsproxy/ProxySettingsStore.kt
index e93249d..9a08cc9 100644
--- a/android/app/src/main/java/org/flowseal/tgwsproxy/ProxySettingsStore.kt
+++ b/android/app/src/main/java/org/flowseal/tgwsproxy/ProxySettingsStore.kt
@@ -13,6 +13,20 @@ class ProxySettingsStore(context: Context) {
KEY_DC_IP_TEXT,
ProxyConfig.DEFAULT_DC_IP_LINES.joinToString("\n"),
).orEmpty(),
+ logMaxMbText = ProxyConfig.formatDecimal(
+ preferences.getFloat(
+ KEY_LOG_MAX_MB,
+ ProxyConfig.DEFAULT_LOG_MAX_MB.toFloat(),
+ ).toDouble()
+ ),
+ bufferKbText = preferences.getInt(
+ KEY_BUFFER_KB,
+ ProxyConfig.DEFAULT_BUFFER_KB,
+ ).toString(),
+ poolSizeText = preferences.getInt(
+ KEY_POOL_SIZE,
+ ProxyConfig.DEFAULT_POOL_SIZE,
+ ).toString(),
verbose = preferences.getBoolean(KEY_VERBOSE, false),
)
}
@@ -22,6 +36,9 @@ class ProxySettingsStore(context: Context) {
.putString(KEY_HOST, config.host)
.putInt(KEY_PORT, config.port)
.putString(KEY_DC_IP_TEXT, config.dcIpList.joinToString("\n"))
+ .putFloat(KEY_LOG_MAX_MB, config.logMaxMb.toFloat())
+ .putInt(KEY_BUFFER_KB, config.bufferKb)
+ .putInt(KEY_POOL_SIZE, config.poolSize)
.putBoolean(KEY_VERBOSE, config.verbose)
.apply()
}
@@ -31,6 +48,9 @@ class ProxySettingsStore(context: Context) {
private const val KEY_HOST = "host"
private const val KEY_PORT = "port"
private const val KEY_DC_IP_TEXT = "dc_ip_text"
+ private const val KEY_LOG_MAX_MB = "log_max_mb"
+ private const val KEY_BUFFER_KB = "buf_kb"
+ private const val KEY_POOL_SIZE = "pool_size"
private const val KEY_VERBOSE = "verbose"
}
}
diff --git a/android/app/src/main/java/org/flowseal/tgwsproxy/PythonProxyBridge.kt b/android/app/src/main/java/org/flowseal/tgwsproxy/PythonProxyBridge.kt
index 55ff549..e6e4ce9 100644
--- a/android/app/src/main/java/org/flowseal/tgwsproxy/PythonProxyBridge.kt
+++ b/android/app/src/main/java/org/flowseal/tgwsproxy/PythonProxyBridge.kt
@@ -17,6 +17,9 @@ object PythonProxyBridge {
config.host,
config.port,
config.dcIpList,
+ config.logMaxMb,
+ config.bufferKb,
+ config.poolSize,
config.verbose,
).toString()
}
diff --git a/android/app/src/main/python/android_proxy_bridge.py b/android/app/src/main/python/android_proxy_bridge.py
index 910d1fb..b83201e 100644
--- a/android/app/src/main/python/android_proxy_bridge.py
+++ b/android/app/src/main/python/android_proxy_bridge.py
@@ -41,7 +41,9 @@ def _normalize_dc_ip_list(dc_ip_list: Iterable[object]) -> list[str]:
def start_proxy(app_dir: str, host: str, port: int,
- dc_ip_list: Iterable[object], verbose: bool = False) -> str:
+ dc_ip_list: Iterable[object], log_max_mb: float = 5.0,
+ buf_kb: int = 256, pool_size: int = 4,
+ verbose: bool = False) -> str:
global _RUNTIME, _LAST_ERROR
with _RUNTIME_LOCK:
@@ -59,12 +61,15 @@ def start_proxy(app_dir: str, host: str, port: int,
on_error=_remember_error,
)
runtime.reset_log_file()
- runtime.setup_logging(verbose=verbose)
+ runtime.setup_logging(verbose=verbose, log_max_mb=float(log_max_mb))
config = {
"host": host,
"port": int(port),
"dc_ip": _normalize_dc_ip_list(dc_ip_list),
+ "log_max_mb": float(log_max_mb),
+ "buf_kb": int(buf_kb),
+ "pool_size": int(pool_size),
"verbose": bool(verbose),
}
runtime.save_config(config)
diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml
index ead3c2a..db5aed8 100644
--- a/android/app/src/main/res/layout/activity_main.xml
+++ b/android/app/src/main/res/layout/activity_main.xml
@@ -197,6 +197,48 @@
android:layout_marginTop="16dp"
android:text="@string/verbose_label" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Proxy host
Proxy port
DC to IP mappings (one DC:IP per line)
+ Max log size before rotation (MB)
+ Socket buffer size (KB)
+ WS pool size per DC
Verbose logging
Save Settings
Start Service
diff --git a/tests/test_android_proxy_bridge.py b/tests/test_android_proxy_bridge.py
index d7f159b..75cdb2b 100644
--- a/tests/test_android_proxy_bridge.py
+++ b/tests/test_android_proxy_bridge.py
@@ -73,6 +73,57 @@ class AndroidProxyBridgeTests(unittest.TestCase):
"4:149.154.167.220",
])
+ def test_start_proxy_saves_advanced_runtime_config(self):
+ captured = {}
+
+ class FakeRuntime:
+ def __init__(self, *args, **kwargs):
+ captured["runtime_init"] = kwargs
+ self.log_file = Path("/tmp/proxy.log")
+
+ def reset_log_file(self):
+ captured["reset_log_file"] = True
+
+ def setup_logging(self, verbose=False, log_max_mb=5):
+ captured["verbose"] = verbose
+ captured["log_max_mb"] = log_max_mb
+
+ def save_config(self, config):
+ captured["config"] = dict(config)
+
+ def start_proxy(self, config):
+ captured["start_proxy"] = dict(config)
+ return True
+
+ def is_proxy_running(self):
+ return True
+
+ def stop_proxy(self):
+ captured["stop_proxy"] = True
+
+ original_runtime = android_proxy_bridge.ProxyAppRuntime
+ try:
+ android_proxy_bridge.ProxyAppRuntime = FakeRuntime
+ log_path = android_proxy_bridge.start_proxy(
+ "/tmp/app",
+ "127.0.0.1",
+ 1080,
+ ["2:149.154.167.220"],
+ 7.0,
+ 512,
+ 6,
+ True,
+ )
+ finally:
+ android_proxy_bridge.ProxyAppRuntime = original_runtime
+
+ self.assertEqual(log_path, "/tmp/proxy.log")
+ self.assertEqual(captured["config"]["log_max_mb"], 7.0)
+ self.assertEqual(captured["config"]["buf_kb"], 512)
+ self.assertEqual(captured["config"]["pool_size"], 6)
+ self.assertEqual(captured["log_max_mb"], 7.0)
+ self.assertTrue(captured["verbose"])
+
if __name__ == "__main__":
unittest.main()