tauri_plugin_network_manager/
lib.rs

1use commands::{
2    connect_to_wifi, delete_wifi_connection, disconnect_from_wifi, get_network_state,
3    get_saved_wifi_networks, list_wifi_networks, toggle_network_state,
4};
5pub use models::{NetworkInfo, WiFiConnectionConfig, WiFiSecurityType};
6use serde::{Deserialize, Serialize};
7use std::result::Result;
8use std::sync::{Arc, RwLock};
9use tauri::{
10    plugin::{Builder, TauriPlugin},
11    AppHandle, Emitter, Manager, Runtime,
12};
13
14#[cfg(desktop)]
15pub mod desktop;
16
17mod commands;
18pub mod error;
19pub mod models;
20
21pub use crate::error::{NetworkError, Result as NetworkResult};
22
23#[derive(Default)]
24pub struct NetworkManagerState<R: Runtime> {
25    pub manager: Arc<RwLock<Option<crate::models::VSKNetworkManager<'static, R>>>>,
26}
27
28pub fn spawn_network_change_emitter<R: tauri::Runtime>(
29    app: AppHandle<R>,
30    network_manager: crate::models::VSKNetworkManager<'static, R>,
31) {
32    let rx = match network_manager.listen_network_changes() {
33        Ok(rx) => rx,
34        Err(e) => {
35            eprintln!("No se pudo escuchar cambios de red: {:?}", e);
36            return;
37        }
38    };
39
40    std::thread::spawn(move || {
41        for network_info in rx {
42            let _ = app.emit("network-changed", &network_info);
43        }
44    });
45}
46
47impl<R: Runtime> NetworkManagerState<R> {
48    pub fn new(manager: Option<crate::models::VSKNetworkManager<'static, R>>) -> Self {
49        Self {
50            manager: Arc::new(RwLock::new(manager)),
51        }
52    }
53
54    pub fn list_wifi_networks(&self) -> Result<Vec<NetworkInfo>, NetworkError> {
55        let manager = self.manager.read().map_err(|_| NetworkError::LockError)?;
56        match manager.as_ref() {
57            Some(manager) => manager.list_wifi_networks(),
58            _none => Err(NetworkError::NotInitialized),
59        }
60    }
61
62    pub async fn connect_to_wifi(&self, config: WiFiConnectionConfig) -> Result<(), NetworkError> {
63        let manager = self.manager.read().map_err(|_| NetworkError::LockError)?;
64        match manager.as_ref() {
65            Some(manager) => manager.connect_to_wifi(config).await,
66            _none => Err(NetworkError::NotInitialized),
67        }
68    }
69
70    pub async fn disconnect_from_wifi(&self) -> Result<(), NetworkError> {
71        let manager = self.manager.read().map_err(|_| NetworkError::LockError)?;
72        match manager.as_ref() {
73            Some(manager) => manager.disconnect_from_wifi().await,
74            _none => Err(NetworkError::NotInitialized),
75        }
76    }
77
78    pub fn get_saved_wifi_networks(&self) -> Result<Vec<NetworkInfo>, NetworkError> {
79        let manager = self.manager.read().map_err(|_| NetworkError::LockError)?;
80        match manager.as_ref() {
81            Some(manager) => manager.get_saved_wifi_networks(),
82            _none => Err(NetworkError::NotInitialized),
83        }
84    }
85
86    pub fn delete_wifi_connection(&self, ssid: &str) -> Result<bool, NetworkError> {
87        let manager = self.manager.read().map_err(|_| NetworkError::LockError)?;
88        match manager.as_ref() {
89            Some(manager) => manager.delete_wifi_connection(ssid),
90            _none => Err(NetworkError::NotInitialized),
91        }
92    }
93
94    pub fn toggle_network_state(&self, enabled: bool) -> Result<bool, NetworkError> {
95        let manager = self.manager.read().map_err(|_| NetworkError::LockError)?;
96        match manager.as_ref() {
97            Some(manager) => manager.toggle_network_state(enabled),
98            _none => Err(NetworkError::NotInitialized),
99        }
100    }
101}
102
103#[derive(Serialize, Deserialize)]
104struct NetworkRequest {
105    ssid: String,
106    password: Option<String>,
107    security_type: WiFiSecurityType,
108    username: Option<String>,
109}
110
111/// Initializes the plugin.
112pub fn init() -> TauriPlugin<tauri::Wry> {
113    Builder::new("network-manager")
114        .invoke_handler(tauri::generate_handler![
115            get_network_state,
116            list_wifi_networks,
117            connect_to_wifi,
118            disconnect_from_wifi,
119            get_saved_wifi_networks,
120            delete_wifi_connection,
121            toggle_network_state,
122        ])
123        .setup(|app, _api| -> Result<(), Box<dyn std::error::Error>> {
124            #[cfg(desktop)]
125            // Removed tokio runtime initialization
126            let rt = tokio::runtime::Builder::new_multi_thread()
127                .enable_all()
128                .build()?;
129            let network_manager = rt.block_on(async { crate::desktop::init(&app, _api).await })?;
130
131            app.manage(NetworkManagerState::<tauri::Wry>::new(Some(
132                network_manager,
133            )));
134
135            app.state::<NetworkManagerState<tauri::Wry>>()
136                .manager
137                .read()
138                .map_err(|_| NetworkError::LockError)?
139                .as_ref()
140                .map(|manager| {
141                    // Clone the manager with a 'static lifetime
142                    let manager_static: crate::models::VSKNetworkManager<'static, tauri::Wry> =
143                        crate::models::VSKNetworkManager {
144                            connection: manager.connection.clone(),
145                            proxy: manager.proxy.clone(),
146                            app: app.clone(),
147                        };
148                    spawn_network_change_emitter(app.clone(), manager_static);
149                });
150
151            Ok(())
152        })
153        .build()
154}
155
156/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the network-manager APIs.
157pub trait NetworkManagerExt<R: Runtime> {
158    fn network_manager(&self) -> Option<crate::models::VSKNetworkManager<'static, R>>;
159}
160
161impl<R: Runtime + Clone, T: Manager<R>> NetworkManagerExt<R> for T {
162    fn network_manager(&self) -> Option<crate::models::VSKNetworkManager<'static, R>> {
163        self.try_state::<NetworkManagerState<R>>()
164            .and_then(|state| {
165                state.manager.read().ok().and_then(|m| {
166                    m.as_ref().map(|x| crate::models::VSKNetworkManager {
167                        connection: x.connection.clone(),
168                        proxy: x.proxy.clone(),
169                        app: self.app_handle().clone(),
170                    })
171                })
172            })
173    }
174}