counter
This commit is contained in:
@@ -27,6 +27,10 @@ import uniffi.netrunner_client.SessionManager
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
|
||||
private const val TAG = "VPN_DEBUG"
|
||||
|
||||
@Parcelize
|
||||
@@ -224,10 +228,10 @@ class TunVpnService : VpnService() {
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
||||
@TauriPlugin
|
||||
class VpnPlugin(private val activity: Activity) : Plugin(activity) {
|
||||
private var pendingArgs: VpnArgs? = null
|
||||
private var statsJob: Job? = null // Переменная для управления корутиной статистики
|
||||
|
||||
private val statusReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
@@ -246,7 +250,6 @@ class VpnPlugin(private val activity: Activity) : Plugin(activity) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun updateBlocklistIfNeeded() {
|
||||
try {
|
||||
val cachePath = activity.cacheDir.absolutePath
|
||||
@@ -318,7 +321,6 @@ class VpnPlugin(private val activity: Activity) : Plugin(activity) {
|
||||
}
|
||||
} catch (e: Exception) { false }
|
||||
|
||||
// Если интерфейс поднят ИЛИ сервис числится в запущенных — значит мы connected
|
||||
val isRunning = hasTun || isVpnServiceRunning() || TunVpnService.isServiceRunning
|
||||
return if (isRunning) "connected" else "idle"
|
||||
}
|
||||
@@ -363,7 +365,51 @@ class VpnPlugin(private val activity: Activity) : Plugin(activity) {
|
||||
invoke.resolve(JSObject().apply { put("status", status) })
|
||||
}
|
||||
|
||||
// --- НОВЫЙ БЛОК: УПРАВЛЕНИЕ КОРОТУИНОЙ СТАТИСТИКИ ---
|
||||
|
||||
private fun startStatsLoop() {
|
||||
// Защита от запуска нескольких корутин одновременно
|
||||
if (statsJob?.isActive == true) return
|
||||
|
||||
Log.d(TAG, "Starting traffic stats loop")
|
||||
statsJob = CoroutineScope(Dispatchers.IO).launch {
|
||||
while (isActive) {
|
||||
try {
|
||||
val stats = SessionManager().getTrafficStats()
|
||||
|
||||
val result = JSObject().apply {
|
||||
put("rxBytes", stats.rxBytes.toLong())
|
||||
put("txBytes", stats.txBytes.toLong())
|
||||
put("rxPackets", stats.rxPackets.toLong())
|
||||
put("txPackets", stats.txPackets.toLong())
|
||||
}
|
||||
|
||||
// Отправляем данные на фронтенд
|
||||
trigger("traffic-stats", result)
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Stats loop error", e)
|
||||
}
|
||||
|
||||
delay(1000) // Пауза в 1 секунду
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopStatsLoop() {
|
||||
Log.d(TAG, "Stopping traffic stats loop")
|
||||
statsJob?.cancel()
|
||||
statsJob = null
|
||||
}
|
||||
|
||||
// Обновленный метод updateStatus
|
||||
private fun updateStatus(status: String) {
|
||||
if (status == "connected") {
|
||||
startStatsLoop()
|
||||
} else {
|
||||
stopStatsLoop()
|
||||
}
|
||||
|
||||
trigger("status-change", JSObject().apply { put("status", status) })
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,13 @@ export interface TunnelConfig {
|
||||
mtu: number;
|
||||
}
|
||||
|
||||
export interface TrafficStatsResponse {
|
||||
rxBytes: number;
|
||||
txBytes: number;
|
||||
rxPackets: number;
|
||||
txPackets: number;
|
||||
}
|
||||
|
||||
export async function startVpn(config: TunnelConfig, ip: string, port: number) {
|
||||
return await invoke("plugin:vpn|start_vpn", {
|
||||
config,
|
||||
@@ -38,3 +45,12 @@ export const setupVpnStatusListener = async (callback: (p: any) => void) => {
|
||||
callback(payload);
|
||||
});
|
||||
};
|
||||
|
||||
export const setupTrafficStatsListener = async (
|
||||
callback: (stats: TrafficStatsResponse) => void,
|
||||
) => {
|
||||
return await addPluginListener("vpn", "traffic-stats", (payload) => {
|
||||
console.log(">>> [SUCCESS] Пришло через мобильный листенер:", payload);
|
||||
callback(payload as TrafficStatsResponse);
|
||||
});
|
||||
};
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-get-traffic-stats"
|
||||
description = "Enables the get_traffic_stats command without any pre-configured scope."
|
||||
commands.allow = ["get_traffic_stats"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-get-traffic-stats"
|
||||
description = "Denies the get_traffic_stats command without any pre-configured scope."
|
||||
commands.deny = ["get_traffic_stats"]
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-traffic-stats"
|
||||
description = "Enables the traffic_stats command without any pre-configured scope."
|
||||
commands.allow = ["traffic_stats"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-traffic-stats"
|
||||
description = "Denies the traffic_stats command without any pre-configured scope."
|
||||
commands.deny = ["traffic_stats"]
|
||||
@@ -36,6 +36,32 @@ Denies the check_actual_vpn_status command without any pre-configured scope.
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:allow-get-traffic-stats`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the get_traffic_stats command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:deny-get-traffic-stats`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the get_traffic_stats command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:allow-registerListener`
|
||||
|
||||
</td>
|
||||
@@ -114,6 +140,32 @@ Denies the stop_vpn command without any pre-configured scope.
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:allow-traffic-stats`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the traffic_stats command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:deny-traffic-stats`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the traffic_stats command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:allow-unregisterListener`
|
||||
|
||||
</td>
|
||||
|
||||
@@ -3,7 +3,7 @@ identifier = "allow-vpn-control"
|
||||
description = "Allows Vpn Control"
|
||||
|
||||
[permission.commands]
|
||||
allow = ["start_vpn", "stop_vpn", "check_actual_vpn_status", "registerListener", "unregisterListener"]
|
||||
allow = ["start_vpn", "stop_vpn", "get_traffic_stats", "check_actual_vpn_status", "registerListener", "unregisterListener"]
|
||||
|
||||
[permission.events]
|
||||
allow = ["status-change"]
|
||||
@@ -306,6 +306,18 @@
|
||||
"const": "deny-check-actual-vpn-status",
|
||||
"markdownDescription": "Denies the check_actual_vpn_status command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the get_traffic_stats command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-get-traffic-stats",
|
||||
"markdownDescription": "Enables the get_traffic_stats command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the get_traffic_stats command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-get-traffic-stats",
|
||||
"markdownDescription": "Denies the get_traffic_stats command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the registerListener command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -342,6 +354,18 @@
|
||||
"const": "deny-stop-vpn",
|
||||
"markdownDescription": "Denies the stop_vpn command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the traffic_stats command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-traffic-stats",
|
||||
"markdownDescription": "Enables the traffic_stats command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the traffic_stats command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-traffic-stats",
|
||||
"markdownDescription": "Denies the traffic_stats command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the unregisterListener command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use crate::{models::*, Vpn, VpnInterface};
|
||||
use crate::{models::*, Vpn};
|
||||
use tauri::{command, AppHandle, Manager, Runtime};
|
||||
|
||||
#[command]
|
||||
|
||||
@@ -53,7 +53,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
commands::start_vpn,
|
||||
commands::stop_vpn,
|
||||
commands::check_actual_vpn_status
|
||||
commands::check_actual_vpn_status,
|
||||
])
|
||||
.setup(|app, api| {
|
||||
#[cfg(mobile)]
|
||||
|
||||
@@ -25,3 +25,12 @@ pub struct StopVpnRequest {}
|
||||
pub struct StatusResponse {
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")] // Чтобы в JS поля были rxBytes, txBytes и т.д.
|
||||
pub struct TrafficStatsResponse {
|
||||
pub rx_bytes: u64,
|
||||
pub tx_bytes: u64,
|
||||
pub rx_packets: u64,
|
||||
pub tx_packets: u64,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user