From b9f1e834739e1d7978343f83136e05c089ccfe83 Mon Sep 17 00:00:00 2001 From: problematicconsumer Date: Thu, 14 Dec 2023 12:12:12 +0330 Subject: [PATCH] Add android stats channel --- .../com/hiddify/hiddify/MainActivity.kt | 1 + .../com/hiddify/hiddify/StatsChannel.kt | 64 +++++++++++++++++++ .../service/platform_singbox_service.dart | 13 +++- 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 android/app/src/main/kotlin/com/hiddify/hiddify/StatsChannel.kt diff --git a/android/app/src/main/kotlin/com/hiddify/hiddify/MainActivity.kt b/android/app/src/main/kotlin/com/hiddify/hiddify/MainActivity.kt index f605144cd..47a452d66 100644 --- a/android/app/src/main/kotlin/com/hiddify/hiddify/MainActivity.kt +++ b/android/app/src/main/kotlin/com/hiddify/hiddify/MainActivity.kt @@ -49,6 +49,7 @@ class MainActivity : FlutterFragmentActivity(), ServiceConnection.Callback { flutterEngine.plugins.add(EventHandler()) flutterEngine.plugins.add(LogHandler()) flutterEngine.plugins.add(GroupsChannel(lifecycleScope)) + flutterEngine.plugins.add(StatsChannel(lifecycleScope)) } fun reconnect() { diff --git a/android/app/src/main/kotlin/com/hiddify/hiddify/StatsChannel.kt b/android/app/src/main/kotlin/com/hiddify/hiddify/StatsChannel.kt new file mode 100644 index 000000000..1ee592990 --- /dev/null +++ b/android/app/src/main/kotlin/com/hiddify/hiddify/StatsChannel.kt @@ -0,0 +1,64 @@ +package com.hiddify.hiddify + +import android.util.Log +import com.hiddify.hiddify.utils.CommandClient +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.JSONMethodCodec +import io.nekohasekai.libbox.StatusMessage +import kotlinx.coroutines.CoroutineScope + +class StatsChannel(private val scope: CoroutineScope) : FlutterPlugin, CommandClient.Handler{ + companion object { + const val TAG = "A/StatsChannel" + const val STATS_CHANNEL = "com.hiddify.app/stats" + } + + private val commandClient = + CommandClient(scope, CommandClient.ConnectionType.Status, this) + + private var statsChannel: EventChannel? = null + private var statsEvent: EventChannel.EventSink? = null + + override fun updateStatus(status: StatusMessage) { + MainActivity.instance.runOnUiThread { + val map = listOf( + Pair("connections-in", status.connectionsIn), + Pair("connections-out", status.connectionsOut), + Pair("uplink", status.uplink), + Pair("downlink", status.downlink), + Pair("uplink-total", status.uplinkTotal), + Pair("downlink-total", status.downlinkTotal) + ).associate { it.first to it.second } + statsEvent?.success(map) + } + } + + override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + statsChannel = EventChannel( + flutterPluginBinding.binaryMessenger, + STATS_CHANNEL, + JSONMethodCodec.INSTANCE + ) + + statsChannel!!.setStreamHandler(object : EventChannel.StreamHandler { + override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { + statsEvent = events + Log.d(TAG, "connecting stats command client") + commandClient.connect() + } + + override fun onCancel(arguments: Any?) { + statsEvent = null + Log.d(TAG, "disconnecting stats command client") + commandClient.disconnect() + } + }) + } + + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { + statsEvent = null + commandClient.disconnect() + statsChannel?.setStreamHandler(null) + } +} \ No newline at end of file diff --git a/lib/singbox/service/platform_singbox_service.dart b/lib/singbox/service/platform_singbox_service.dart index 7ed3b1317..536128a7b 100644 --- a/lib/singbox/service/platform_singbox_service.dart +++ b/lib/singbox/service/platform_singbox_service.dart @@ -149,8 +149,17 @@ class PlatformSingboxService with InfraLogger implements SingboxService { @override Stream watchStats() { - // TODO: implement watchStats - return const Stream.empty(); + const channel = EventChannel("com.hiddify.app/stats", JSONMethodCodec()); + loggy.debug("watching stats"); + return channel.receiveBroadcastStream().map( + (event) { + if (event case Map _) { + return SingboxStats.fromJson(event); + } + loggy.error("[stats client] unexpected type, msg: $event"); + throw "invalid type"; + }, + ); } @override