From 5ee70b723be7536533e5be73a3a5affae3dfe3c2 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Fri, 24 Jul 2026 11:12:23 +0800 Subject: [PATCH] Add TCP ping mode for all-server testing --- .../com/v2ray/ang/dto/TestServiceMessage.kt | 3 ++- .../com/v2ray/ang/service/CoreTestService.kt | 2 ++ .../ang/service/RealPingWorkerService.kt | 26 +++++++++++++++++-- .../com/v2ray/ang/ui/main/MainContract.kt | 1 + .../com/v2ray/ang/ui/main/MainImportMenu.kt | 6 ++++- .../com/v2ray/ang/ui/main/MainViewModel.kt | 8 +++--- .../com/v2ray/ang/util/NotificationHelper.kt | 3 ++- .../app/src/main/res/values-ar/strings.xml | 1 + .../app/src/main/res/values-bn/strings.xml | 1 + .../src/main/res/values-bqi-rIR/strings.xml | 1 + .../app/src/main/res/values-fa/strings.xml | 1 + .../app/src/main/res/values-ru/strings.xml | 1 + .../app/src/main/res/values-vi/strings.xml | 1 + .../src/main/res/values-zh-rCN/strings.xml | 1 + .../src/main/res/values-zh-rTW/strings.xml | 1 + V2rayNG/app/src/main/res/values/strings.xml | 1 + 16 files changed, 50 insertions(+), 8 deletions(-) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/TestServiceMessage.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/TestServiceMessage.kt index a9f4ce91..9dc901bc 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/TestServiceMessage.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/TestServiceMessage.kt @@ -5,6 +5,7 @@ import java.io.Serializable data class TestServiceMessage( val key: Int, val subscriptionId: String = "", - val serverGuids: List = emptyList() + val serverGuids: List = emptyList(), + val onlyTcp : Boolean = false ) : Serializable diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/CoreTestService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/CoreTestService.kt index b3d8382b..6acaf036 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/CoreTestService.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/CoreTestService.kt @@ -96,6 +96,7 @@ class CoreTestService : Service() { worker = RealPingWorkerService( context = this, guids = guidsList, + onlyTcp = message.onlyTcp, onEvent = { event -> handleWorkerEvent(event) { activeWorkers.remove(worker) } } ) activeWorkers.add(worker) @@ -112,6 +113,7 @@ class CoreTestService : Service() { NotificationHelper.updateNotification( channelType = NotificationChannelType.CORE_TEST, context = this, + title = getString(R.string.app_name), content = getString(R.string.connection_runing_task_left, event.text) ) MessageUtil.sendMsg2UI(this, AppConfig.MSG_MEASURE_CONFIG_NOTIFY, event.text) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/RealPingWorkerService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/RealPingWorkerService.kt index d70348f5..ed42ed38 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/RealPingWorkerService.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/RealPingWorkerService.kt @@ -27,11 +27,12 @@ import java.util.concurrent.atomic.AtomicInteger class RealPingWorkerService( private val context: Context, private val guids: List, + private val onlyTcp : Boolean = false, private val onEvent: (RealPingEvent) -> Unit = {} ) { private val job = SupervisorJob() private val concurrency = SettingsManager.getRealPingConcurrency() - private val dispatcher = Executors.newFixedThreadPool(concurrency).asCoroutineDispatcher() + private val dispatcher = Executors.newFixedThreadPool(if (onlyTcp) concurrency * 2 else concurrency).asCoroutineDispatcher() private val scope = CoroutineScope(job + dispatcher + CoroutineName("RealPingBatchWorker")) private val runningCount = AtomicInteger(0) @@ -43,7 +44,7 @@ class RealPingWorkerService( scope.launch { runningCount.incrementAndGet() try { - val result = startRealPing(guid) + val result = if (onlyTcp) startTcping(guid) else startRealPing(guid) onEvent(RealPingEvent.Result(guid, result)) } catch (_: Throwable) { // ignore @@ -104,4 +105,25 @@ class RealPingWorkerService( } return CoreNativeManager.measureOutboundDelay(configResult.content, SettingsManager.getDelayTestUrl()) } + + private fun startTcping(guid: String): Long { + val retFailure = -1L + + val config = MmkvManager.decodeServerConfig(guid) ?: return retFailure + if (!config.configType.isComplexType() + && config.configType != EConfigType.HYSTERIA2 + && config.configType != EConfigType.WIREGUARD + && config.alpn?.startsWith("h3") != true + && config.server.isNotNullEmpty() + && config.serverPort?.toIntOrNull() != null + ) { + val url = config.server.orEmpty() + val port = config.serverPort.orEmpty().toInt() + val tcpTime = SpeedtestManager.socketConnectTime(url, port, 1000) + + return tcpTime + } + + return retFailure + } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainContract.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainContract.kt index a968a2ae..4c504bf6 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainContract.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainContract.kt @@ -28,6 +28,7 @@ sealed interface MainAction { data object ToggleService : MainAction data object TestCurrentServer : MainAction data object TestAllServers : MainAction + data object TestRealAllServers : MainAction data object CancelTesting : MainAction data object RemoveAllServers : MainAction data object RemoveDuplicateServers : MainAction diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainImportMenu.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainImportMenu.kt index 9918242c..1ecd1c93 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainImportMenu.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainImportMenu.kt @@ -104,9 +104,13 @@ fun MoreMenuContent( onClick = { onAction(MainAction.SortByTestResults) } ) DropdownMenuItem( - text = { Text(stringResource(R.string.title_real_ping_all_server)) }, + text = { Text(stringResource(R.string.title_ping_all_server)) }, onClick = { onAction(MainAction.TestAllServers) } ) + DropdownMenuItem( + text = { Text(stringResource(R.string.title_real_ping_all_server)) }, + onClick = { onAction(MainAction.TestRealAllServers) } + ) DropdownMenuItem( text = { Text(stringResource(R.string.title_sub_update)) }, onClick = { onAction(MainAction.UpdateSubscriptions) } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainViewModel.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainViewModel.kt index bae8edb0..62f00ed7 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainViewModel.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainViewModel.kt @@ -162,7 +162,8 @@ class MainViewModel( when (action) { MainAction.Initialize -> initialize() MainAction.RefreshGroups -> setupGroupTab(forceRefresh = true) - MainAction.TestAllServers -> testAllRealPing() + MainAction.TestAllServers -> testAllRealPing(true) + MainAction.TestRealAllServers -> testAllRealPing() MainAction.CancelTesting -> cancelAllPing() MainAction.RemoveAllServers -> removeAllServerAsync() MainAction.RemoveDuplicateServers -> removeDuplicateServerAsync() @@ -671,7 +672,7 @@ class MainViewModel( } } - fun testAllRealPing() { + fun testAllRealPing(onlyTcp : Boolean = false) { dataSource.cancelAllPing() val groupId = uiState.value.selectedGroupId val servers = currentServers() @@ -693,7 +694,8 @@ class MainViewModel( TestServiceMessage( key = AppConfig.MSG_MEASURE_CONFIG_START, subscriptionId = groupId, - serverGuids = if (keywordFilter.isNotEmpty()) servers.map { it.guid } else emptyList() + serverGuids = if (keywordFilter.isNotEmpty()) servers.map { it.guid } else emptyList(), + onlyTcp = onlyTcp ) ) } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/util/NotificationHelper.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/util/NotificationHelper.kt index e40d4d8f..4c5788d7 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/util/NotificationHelper.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/util/NotificationHelper.kt @@ -55,13 +55,14 @@ object NotificationHelper { fun updateNotification( channelType: NotificationChannelType, context: Context, + title: String, content: String ) { val notificationManager = getNotificationManager(context) // Get or create builder from cache val builder = builderCache.getOrPut(channelType.notificationId) { - buildNotificationBuilder(channelType, context, "", content) + buildNotificationBuilder(channelType, context, title, content) } // Update only the content text (fast operation) diff --git a/V2rayNG/app/src/main/res/values-ar/strings.xml b/V2rayNG/app/src/main/res/values-ar/strings.xml index 1b497535..a4ff9eec 100644 --- a/V2rayNG/app/src/main/res/values-ar/strings.xml +++ b/V2rayNG/app/src/main/res/values-ar/strings.xml @@ -304,6 +304,7 @@ The configuration remarks exists and is unique فاصل التحديث غير صالح. الحد الأدنى هو 15 دقيقة. تحديث الاشتراك (أول خطوة) + Tcping لجميع الإعدادات اختبر جميع الإعدادات (3) Asset files الفرز حسب نتائج الاختبار (5) diff --git a/V2rayNG/app/src/main/res/values-bn/strings.xml b/V2rayNG/app/src/main/res/values-bn/strings.xml index 0be9ab1e..6118aea8 100644 --- a/V2rayNG/app/src/main/res/values-bn/strings.xml +++ b/V2rayNG/app/src/main/res/values-bn/strings.xml @@ -304,6 +304,7 @@ The configuration remarks exists and is unique আপডেটের বিরতি সঠিক নয়। সর্বনিম্ন ১৫ মিনিট। সাবস্ক্রিপশন আপডেট + সব কনফিগারেশন TCPing সব কনফিগারেশন প্রকৃত বিলম্ব Asset files টেস্ট ফলাফল দ্বারা সাজানো diff --git a/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml b/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml index c2db579c..bb1737ca 100644 --- a/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml +++ b/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml @@ -310,6 +310,7 @@ موتمعن بۊ ک نوم موستعار هڌس وو جۊرس نی فاسله ورۊ کردن نا موئتبر هڌ. هدقل مقدار 15 دؽقه هڌ. ورۊ کردن اشتراک بونکۊ سکویی + Tcping کانفیگا بونکۊ سکویی تئخیر واقعی کانفیگا بونکۊ سکویی فایلا بونچک جوقرافیایی ترتیب و ری نتیجه یل پینگ diff --git a/V2rayNG/app/src/main/res/values-fa/strings.xml b/V2rayNG/app/src/main/res/values-fa/strings.xml index dcdfaa1e..f776dfeb 100644 --- a/V2rayNG/app/src/main/res/values-fa/strings.xml +++ b/V2rayNG/app/src/main/res/values-fa/strings.xml @@ -301,6 +301,7 @@ لطفاً مطمئن شوید که نام مستعار وجود دارد و منحصر به فرد است بازه بروزرسانی نامعتبر است. حداقل مقدار 15 دقیقه است. به‌روزرسانی گروه فعلی اشتراک + TCPING کانفیگ های گروه فعلی تاخیر واقعی کانفیگ های گروه فعلی فایل های منبع جغرافیایی مرتب‌ سازی بر اساس نتایج آزمایش diff --git a/V2rayNG/app/src/main/res/values-ru/strings.xml b/V2rayNG/app/src/main/res/values-ru/strings.xml index 47a774f7..4b9a8912 100644 --- a/V2rayNG/app/src/main/res/values-ru/strings.xml +++ b/V2rayNG/app/src/main/res/values-ru/strings.xml @@ -316,6 +316,7 @@ Профиль должен быть уникальным Неправильный интервал обновления. Минимум 15 минут. Обновить подписку + Проверить профили Проверить задержку профилей Файлы ресурсов Сортировать по результатам теста diff --git a/V2rayNG/app/src/main/res/values-vi/strings.xml b/V2rayNG/app/src/main/res/values-vi/strings.xml index cc0fe944..26658443 100644 --- a/V2rayNG/app/src/main/res/values-vi/strings.xml +++ b/V2rayNG/app/src/main/res/values-vi/strings.xml @@ -304,6 +304,7 @@ The configuration remarks exists and is unique Khoảng thời gian cập nhật không hợp lệ. Giá trị tối thiểu là 15 phút. Cập nhật các gói đăng ký + Ping tất cả máy chủ Kiểm tra HTTP tất cả máy chủ Asset files Sắp xếp lại theo lần kiểm tra cuối cùng diff --git a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml index d53d1242..9fa7c0e0 100644 --- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -316,6 +316,7 @@ 请确保配置别名存在并唯一 更新间隔无效,最小值为 15 分钟。 更新订阅 + 测试配置 Tcping 测试配置真连接 资源文件 按测试结果排序 diff --git a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml index 03fc003f..590ec8af 100644 --- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -315,6 +315,7 @@ 请确保設定檔别名存在并唯一 更新間隔無效,最小值為 15 分鐘。 更新訂閱 + 偵測設定 Tcping 偵測設定真延遲 資源檔案 依偵測結果排序 diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml index 0cffd237..3b2df2a6 100644 --- a/V2rayNG/app/src/main/res/values/strings.xml +++ b/V2rayNG/app/src/main/res/values/strings.xml @@ -323,6 +323,7 @@ The config remarks exist and are unique Invalid update interval. Minimum is 15 minutes. Update subscription + Tcping config Real delay config Asset files Sorting by test results