desktop counter

This commit is contained in:
2026-04-01 18:43:20 +07:00
parent bd51ac5ddf
commit b81dc3f756
5 changed files with 88 additions and 47 deletions
-1
View File
@@ -1 +0,0 @@
-1
View File
@@ -1,4 +1,3 @@
mod core;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
@@ -1,5 +1,3 @@
// src-tauri/src/plugins/vpn-plugin/build.rs
const COMMANDS: &[&str] = &[
"start_vpn",
"stop_vpn",
+60 -15
View File
@@ -1,33 +1,45 @@
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::{Arc, Mutex}; // Добавили Arc
use crate::models::*;
use crate::VpnInterface;
use netrunner_client::Session;
use netrunner_client::SessionManager;
use serde::de::DeserializeOwned;
// ВАЖНО: Добавляем Emitter для возможности вызова .emit()
use tauri::Manager; // Важно для app.manage()
use tauri::{plugin::PluginApi, AppHandle, Emitter, Runtime};
pub fn init<R: Runtime, C: DeserializeOwned>(
app: &AppHandle<R>,
_api: PluginApi<R, C>,
) -> crate::Result<Vpn<R>> {
Ok(Vpn {
let vpn = Vpn {
app: app.clone(),
active_session: Mutex::new(None),
})
// Оборачиваем Mutex в Arc, чтобы структуру Vpn можно было клонировать и шарить
active_session: Arc::new(Mutex::new(None)),
};
// 🛑 САМОЕ ВАЖНОЕ: Регистрируем стейт в Tauri, чтобы app.state() больше не падал!
app.manage(vpn.clone());
Ok(vpn)
}
pub struct Vpn<R: Runtime> {
app: AppHandle<R>,
active_session: Mutex<Option<Arc<Session>>>,
active_session: Arc<Mutex<Option<Arc<Session>>>>,
}
impl<R: Runtime> Clone for Vpn<R> {
fn clone(&self) -> Self {
Self {
app: self.app.clone(),
active_session: self.active_session.clone(),
}
}
}
impl<R: Runtime> VpnInterface<R> for Vpn<R> {
fn start_vpn(&self, _config: TunnelConfig, ip: String, port: i32) -> crate::Result<()> {
// 1. Сразу уведомляем фронт о начале подключения
// Имя события совпадает с тем, что мы слушаем в useEffect
let _ = self.app.emit(
"status-change",
StatusResponse {
@@ -35,14 +47,16 @@ impl<R: Runtime> VpnInterface<R> for Vpn<R> {
},
);
// Запуск сессии (здесь может быть паника, если нет прав админа!)
let session = SessionManager.spawn_session(format!("{}:{}", ip, port), None, ".".into());
// Обрати внимание: SessionManager.spawn_session -> SessionManager::new().spawn_session
let session =
SessionManager::new().spawn_session(format!("{}:{}", ip, port), None, ".".into());
// Сохраняем сессию
let mut lock = self.active_session.lock().unwrap();
*lock = Some(session);
{
let mut lock = self.active_session.lock().unwrap();
*lock = Some(session);
}
// 2. Успешное подключение
let _ = self.app.emit(
"status-change",
StatusResponse {
@@ -50,6 +64,38 @@ impl<R: Runtime> VpnInterface<R> for Vpn<R> {
},
);
// --- ФОНОВЫЙ ЦИКЛ СТАТИСТИКИ (Оптимизированный) ---
let app_handle = self.app.clone();
// Клонируем умный указатель (Arc), чтобы отдать его внутрь потока
let session_ref = self.active_session.clone();
std::thread::spawn(move || {
loop {
std::thread::sleep(std::time::Duration::from_secs(1));
// Теперь мы НЕ обращаемся к app_handle.state(), а проверяем локальную ссылку!
// Это полностью исключает дедлоки стейта Tauri.
if session_ref.lock().unwrap().is_none() {
eprintln!("--- [DEBUG] VPN Session ended. Stopping desktop stats loop. ---");
break;
}
let stats = SessionManager::new().get_traffic_stats();
let _ = app_handle.emit(
"traffic-stats",
TrafficStatsResponse {
rx_bytes: stats.rx_bytes,
tx_bytes: stats.tx_bytes,
rx_packets: stats.rx_packets,
tx_packets: stats.tx_packets,
},
);
}
});
// -----------------------------------------------------------------
Ok(())
}
@@ -58,7 +104,6 @@ impl<R: Runtime> VpnInterface<R> for Vpn<R> {
if let Some(session) = lock.take() {
session.stop();
// 3. Уведомляем об отключении
let _ = self.app.emit(
"status-change",
StatusResponse {