tauri_plugin_network_manager/
desktop.rs

1use std::collections::HashMap;
2use std::process::Command;
3use std::sync::mpsc;
4use tauri::{plugin::PluginApi, AppHandle, Runtime};
5use zbus::names::InterfaceName;
6use zbus::zvariant::Value;
7
8use crate::error::Result;
9use crate::models::{NetworkInfo, WiFiConnectionConfig, WiFiSecurityType, VSKNetworkManager};
10use crate::nm_helpers::NetworkManagerHelpers;
11
12impl<R: Runtime> VSKNetworkManager<'static, R> {
13    /// Get WiFi icon based on signal strength
14    fn get_wifi_icon(strength: u8) -> String {
15        match strength {
16            0..=25 => "network-wireless-signal-weak-symbolic".to_string(),
17            26..=50 => "network-wireless-signal-ok-symbolic".to_string(),
18            51..=75 => "network-wireless-signal-good-symbolic".to_string(),
19            76..=100 => "network-wireless-signal-excellent-symbolic".to_string(),
20            _ => "network-wireless-signal-none-symbolic".to_string(),
21        }
22    }
23
24    fn get_wired_icon(is_connected: bool) -> String {
25        if is_connected {
26            "network-wired-symbolic".to_string()
27        } else {
28            "network-offline-symbolic".to_string()
29        }
30    }
31
32    /// Create a new VSKNetworkManager instance
33    pub async fn new(app: AppHandle<R>) -> Result<Self> {
34        let connection = zbus::blocking::Connection::system()?;
35        let proxy = zbus::blocking::fdo::PropertiesProxy::builder(&connection)
36            .destination("org.freedesktop.NetworkManager")?
37            .path("/org/freedesktop/NetworkManager")?
38            .build()?;
39
40        Ok(Self {
41            connection,
42            proxy,
43            app,
44        })
45    }
46
47    pub fn get_current_network_state(&self) -> Result<NetworkInfo> {
48        // Get active connections
49        let active_connections_variant = self.proxy.get(
50            InterfaceName::from_static_str_unchecked("org.freedesktop.NetworkManager"),
51            "ActiveConnections",
52        )?;
53
54        // If no active connections, return default
55        match active_connections_variant.downcast_ref() {
56            Some(Value::Array(arr)) if !arr.is_empty() => {
57                // Get the first active connection path
58                match arr[0] {
59                    zbus::zvariant::Value::ObjectPath(ref path) => {
60                        // Get devices for this connection
61                        // Crear un proxy de propiedades para obtener las propiedades
62                        let properties_proxy =
63                            zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
64                                .destination("org.freedesktop.NetworkManager")?
65                                .path(path)?
66                                .build()?;
67
68                        let devices_variant = properties_proxy.get(
69                            InterfaceName::from_static_str_unchecked(
70                                "org.freedesktop.NetworkManager.Connection.Active",
71                            ),
72                            "Devices",
73                        )?;
74
75                        // Get the first device (if available)
76                        let device_path = match devices_variant.downcast_ref() {
77                            Some(Value::Array(device_arr)) if !device_arr.is_empty() => {
78                                match device_arr[0] {
79                                    zbus::zvariant::Value::ObjectPath(ref dev_path) => {
80                                        dev_path.clone()
81                                    }
82                                    _ => return Ok(NetworkInfo::default()),
83                                }
84                            }
85                            _ => return Ok(NetworkInfo::default()),
86                        };
87
88                        // Retrieve connection details
89                        // Crear un proxy de propiedades para el dispositivo
90                        let device_properties_proxy =
91                            zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
92                                .destination("org.freedesktop.NetworkManager")?
93                                .path(&device_path)?
94                                .build()?;
95
96                        let connection_type = device_properties_proxy.get(
97                            InterfaceName::from_static_str_unchecked(
98                                "org.freedesktop.NetworkManager.Device",
99                            ),
100                            "DeviceType",
101                        )?;
102
103                        let state_variant = properties_proxy.get(
104                            InterfaceName::from_static_str_unchecked(
105                                "org.freedesktop.NetworkManager.Connection.Active",
106                            ),
107                            "State",
108                        )?;
109
110                        let is_connected = match state_variant.downcast_ref() {
111                            Some(zbus::zvariant::Value::U32(state)) => *state == 2, // 2 = ACTIVATED
112                            _ => false,
113                        };
114
115                        // Determine connection type
116                        let connection_type_str = match connection_type.downcast_ref() {
117                            Some(zbus::zvariant::Value::U32(device_type)) => match device_type {
118                                1 => "Ethernet".to_string(),
119                                2 => "WiFi".to_string(),
120                                _ => "Unknown".to_string(),
121                            },
122                            _ => "Unknown".to_string(),
123                        };
124
125                        // Default network info
126                        let mut network_info = NetworkInfo {
127                            name: "Unknown".to_string(),
128                            ssid: "Unknown".to_string(),
129                            connection_type: connection_type_str.clone(),
130                            icon: "network-offline-symbolic".to_string(),
131                            ip_address: "0.0.0.0".to_string(),
132                            mac_address: "00:00:00:00:00:00".to_string(),
133                            signal_strength: 0,
134                            security_type: WiFiSecurityType::None,
135                            is_connected: is_connected && NetworkManagerHelpers::has_internet_connectivity(&self.proxy)?,
136                        };
137
138                        let hw_address_variant = device_properties_proxy.get(
139                            InterfaceName::from_static_str_unchecked(
140                                "org.freedesktop.NetworkManager.Device",
141                            ),
142                            "HwAddress",
143                        )?;
144
145                        network_info.mac_address = match hw_address_variant.downcast_ref() {
146                            Some(zbus::zvariant::Value::Str(s)) => s.to_string(),
147                            _ => "00:00:00:00:00:00".to_string(),
148                        };
149
150                        // For WiFi networks, get additional details
151                        if connection_type_str == "WiFi" {
152                            // Get active access point
153                            // Crear un proxy de propiedades para el dispositivo inalámbrico
154                            let wireless_properties_proxy =
155                                zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
156                                    .destination("org.freedesktop.NetworkManager")?
157                                    .path(&device_path)?
158                                    .build()?;
159
160                            let active_ap_path = wireless_properties_proxy.get(
161                                InterfaceName::from_static_str_unchecked(
162                                    "org.freedesktop.NetworkManager.Device.Wireless",
163                                ),
164                                "ActiveAccessPoint",
165                            )?;
166
167                            if let Some(zbus::zvariant::Value::ObjectPath(ap_path)) =
168                                active_ap_path.downcast_ref()
169                            {
170                                let _ap_proxy = zbus::blocking::Proxy::new(
171                                    &self.connection,
172                                    "org.freedesktop.NetworkManager",
173                                    ap_path,
174                                    "org.freedesktop.NetworkManager.AccessPoint",
175                                )?;
176
177                                // Get SSID
178                                // Crear un proxy de propiedades para el punto de acceso
179                                let ap_properties_proxy =
180                                    zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
181                                        .destination("org.freedesktop.NetworkManager")?
182                                        .path(ap_path)?
183                                        .build()?;
184
185                                let ssid_variant = ap_properties_proxy.get(
186                                    InterfaceName::from_static_str_unchecked(
187                                        "org.freedesktop.NetworkManager.AccessPoint",
188                                    ),
189                                    "Ssid",
190                                )?;
191
192                                network_info.ssid = match ssid_variant.downcast_ref() {
193                                    Some(zbus::zvariant::Value::Array(ssid_bytes)) => {
194                                        // Convertir el array de bytes a una cadena UTF-8
195                                        let bytes: Vec<u8> = ssid_bytes
196                                            .iter()
197                                            .filter_map(|v| {
198                                                if let zbus::zvariant::Value::U8(b) = v {
199                                                    Some(*b)
200                                                } else {
201                                                    None
202                                                }
203                                            })
204                                            .collect();
205
206                                        String::from_utf8_lossy(&bytes).to_string()
207                                    }
208                                    _ => "Unknown".to_string(),
209                                };
210                                network_info.name = network_info.ssid.clone();
211
212                                // Get signal strength
213                                let strength_variant = ap_properties_proxy.get(
214                                    InterfaceName::from_static_str_unchecked(
215                                        "org.freedesktop.NetworkManager.AccessPoint",
216                                    ),
217                                    "Strength",
218                                )?;
219
220                                network_info.signal_strength = match strength_variant.downcast_ref()
221                                {
222                                    Some(zbus::zvariant::Value::U8(s)) => *s,
223                                    _ => 0,
224                                };
225
226                                // Update icon based on signal strength
227                                network_info.icon =
228                                    Self::get_wifi_icon(network_info.signal_strength);
229
230                                // Determine security type using helper
231                                network_info.security_type = NetworkManagerHelpers::detect_security_type(&ap_properties_proxy)?;
232                            }
233                        } else {
234                            // This is a wired connection
235                            network_info.icon = Self::get_wired_icon(network_info.is_connected);
236                        }
237                        // Get IP configuration
238                        let ip4_config_path = device_properties_proxy.get(
239                            InterfaceName::from_static_str_unchecked(
240                                "org.freedesktop.NetworkManager.Device",
241                            ),
242                            "Ip4Config",
243                        )?;
244
245                        // Retrieve IP address if available
246                        if let Some(zbus::zvariant::Value::ObjectPath(config_path)) =
247                            ip4_config_path.downcast_ref()
248                        {
249                            // Crear un proxy de propiedades para la configuración IP
250                            let ip_config_properties_proxy =
251                                zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
252                                    .destination("org.freedesktop.NetworkManager")?
253                                    .path(config_path)?
254                                    .build()?;
255
256                            let addresses_variant = ip_config_properties_proxy.get(
257                                InterfaceName::from_static_str_unchecked(
258                                    "org.freedesktop.NetworkManager.IP4Config",
259                                ),
260                                "Addresses",
261                            )?;
262
263                            if let Some(Value::Array(addr_arr)) = addresses_variant.downcast_ref() {
264                                if let Some(Value::Array(ip_tuple)) = addr_arr.first() {
265                                    if ip_tuple.len() >= 1 {
266                                        if let Value::U32(ip_int) = &ip_tuple[0] {
267                                            use std::net::Ipv4Addr;
268                                            network_info.ip_address =
269                                                Ipv4Addr::from((*ip_int).to_be()).to_string();
270                                        }
271                                    }
272                                }
273                            }
274                        }
275
276                        Ok(network_info)
277                    }
278                    _ => Ok(NetworkInfo::default()),
279                }
280            }
281            _ => Ok(NetworkInfo::default()),
282        }
283    }
284
285    /// List available WiFi networks
286    pub fn list_wifi_networks(&self) -> Result<Vec<NetworkInfo>> {
287        // Get all devices
288        let devices_variant = self.proxy.get(
289            InterfaceName::from_static_str_unchecked("org.freedesktop.NetworkManager"),
290            "Devices",
291        )?;
292
293        let mut networks = Vec::new();
294        let current_network = self.get_current_network_state()?;
295
296        if let Some(zbus::zvariant::Value::Array(devices)) = devices_variant.downcast_ref() {
297            // Iterate over devices in the array
298            let device_values = devices.get();
299            for device in device_values {
300                if let zbus::zvariant::Value::ObjectPath(ref device_path) = device {
301                    // Create a device proxy
302                    let device_props =
303                        zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
304                            .destination("org.freedesktop.NetworkManager")?
305                            .path(device_path)?
306                            .build()?;
307
308                    // Check if this is a wireless device
309                    let device_type_variant = device_props.get(
310                        InterfaceName::from_static_str_unchecked(
311                            "org.freedesktop.NetworkManager.Device",
312                        ),
313                        "DeviceType",
314                    )?;
315
316                    // DeviceType 2 is WiFi
317                    if let Some(zbus::zvariant::Value::U32(device_type)) =
318                        device_type_variant.downcast_ref()
319                    {
320                        if device_type == &2u32 {
321                            // This is a WiFi device, get its access points
322                            let wireless_props =
323                                zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
324                                    .destination("org.freedesktop.NetworkManager")?
325                                    .path(device_path)?
326                                    .build()?;
327
328                            let access_points_variant = wireless_props.get(
329                                InterfaceName::from_static_str_unchecked(
330                                    "org.freedesktop.NetworkManager.Device.Wireless",
331                                ),
332                                "AccessPoints",
333                            )?;
334
335                            if let Some(zbus::zvariant::Value::Array(aps)) =
336                                access_points_variant.downcast_ref()
337                            {
338                                // Iterate over access points
339                                let ap_values = aps.get();
340                                for ap in ap_values {
341                                    if let zbus::zvariant::Value::ObjectPath(ref ap_path) = ap {
342                                        let ap_props = zbus::blocking::fdo::PropertiesProxy::builder(
343                                            &self.connection,
344                                        )
345                                        .destination("org.freedesktop.NetworkManager")?
346                                        .path(ap_path)?
347                                        .build()?;
348
349                                        // Obtener SSID
350                                        let ssid_variant = ap_props.get(
351                                            InterfaceName::from_static_str_unchecked(
352                                                "org.freedesktop.NetworkManager.AccessPoint",
353                                            ),
354                                            "Ssid",
355                                        )?;
356
357                                        let ssid = match ssid_variant.downcast_ref() {
358                                            Some(zbus::zvariant::Value::Array(ssid_bytes)) => {
359                                                // Convertir el array de bytes a una cadena UTF-8
360                                                let bytes: Vec<u8> = ssid_bytes
361                                                    .iter()
362                                                    .filter_map(|v| {
363                                                        if let zbus::zvariant::Value::U8(b) = v {
364                                                            Some(*b)
365                                                        } else {
366                                                            None
367                                                        }
368                                                    })
369                                                    .collect();
370
371                                                String::from_utf8_lossy(&bytes).to_string()
372                                            }
373                                            _ => "Unknown".to_string(),
374                                        };
375
376                                        // Obtener fuerza de señal
377                                        let strength_variant = ap_props.get(
378                                            InterfaceName::from_static_str_unchecked(
379                                                "org.freedesktop.NetworkManager.AccessPoint",
380                                            ),
381                                            "Strength",
382                                        )?;
383
384                                        let strength = match strength_variant.downcast_ref() {
385                                            Some(zbus::zvariant::Value::U8(s)) => *s,
386                                            _ => 0,
387                                        };
388
389                                        // Determine security type using helper
390                                        let security_type = NetworkManagerHelpers::detect_security_type(&ap_props)?;
391
392                                        let mac_address = match device_props.get(
393                                            InterfaceName::from_static_str_unchecked(
394                                                "org.freedesktop.NetworkManager.Device",
395                                            ),
396                                            "HwAddress",
397                                        )?.downcast_ref() {
398                                            Some(zbus::zvariant::Value::Str(s)) => s.to_string(),
399                                            _ => "00:00:00:00:00:00".to_string(),
400                                        };
401
402                                        let is_connected = current_network.ssid == ssid;
403
404                                        let network_info = NetworkInfo {
405                                            name: ssid.clone(),
406                                            ssid,
407                                            connection_type: "wifi".to_string(),
408                                            icon: Self::get_wifi_icon(strength),
409                                            ip_address: if is_connected {
410                                                current_network.ip_address.clone()
411                                            } else {
412                                                "0.0.0.0".to_string()
413                                            },
414                                            mac_address,
415                                            signal_strength: strength,
416                                            security_type,
417                                            is_connected,
418                                        };
419
420                                        if !networks.iter().any(|n: &NetworkInfo| n.ssid == network_info.ssid) {
421                                            networks.push(network_info);
422                                        }
423                                    }
424                                }
425                            }
426                        }
427                    }
428                }
429            }
430        }
431
432        // Sort networks by signal strength (descending)
433        networks.sort_by(|a, b| b.signal_strength.cmp(&a.signal_strength));
434
435        Ok(networks)
436    }
437
438    /// Connect to a WiFi network
439    pub async fn connect_to_wifi(&self, config: WiFiConnectionConfig) -> Result<()> {
440        // Log connection attempt
441        log::debug!("connect_to_wifi called: ssid='{}' security={:?} username={:?}",
442                  config.ssid, config.security_type, config.username);
443
444        // Create connection settings
445        let mut connection_settings = HashMap::new();
446        let mut wifi_settings = HashMap::new();
447        let mut security_settings = HashMap::new();
448
449        // Set connection name and type
450        let mut connection = HashMap::new();
451        connection.insert("id".to_string(), Value::from(config.ssid.clone()));
452        connection.insert("type".to_string(), Value::from("802-11-wireless"));
453        connection_settings.insert("connection".to_string(), connection);
454
455        // Set WiFi settings
456        wifi_settings.insert("ssid".to_string(), Value::from(config.ssid.clone()));
457        wifi_settings.insert("mode".to_string(), Value::from("infrastructure"));
458
459        // Set security settings based on security type
460        match config.security_type {
461            WiFiSecurityType::None => {
462                // No security settings needed
463            }
464            WiFiSecurityType::Wep => {
465                security_settings.insert("key-mgmt".to_string(), Value::from("none"));
466                if let Some(password) = config.password.clone() {
467                    security_settings.insert("wep-key0".to_string(), Value::from(password));
468                }
469            }
470            WiFiSecurityType::WpaPsk => {
471                security_settings.insert("key-mgmt".to_string(), Value::from("wpa-psk"));
472                if let Some(password) = config.password.clone() {
473                    security_settings.insert("psk".to_string(), Value::from(password));
474                }
475            }
476            WiFiSecurityType::WpaEap => {
477                security_settings.insert("key-mgmt".to_string(), Value::from("wpa-eap"));
478                if let Some(password) = config.password.clone() {
479                    security_settings.insert("password".to_string(), Value::from(password));
480                }
481                if let Some(username) = config.username.clone() {
482                    security_settings.insert("identity".to_string(), Value::from(username));
483                }
484            }
485            WiFiSecurityType::Wpa2Psk => {
486                security_settings.insert("key-mgmt".to_string(), Value::from("wpa-psk"));
487                security_settings.insert("proto".to_string(), Value::from("rsn"));
488                if let Some(password) = config.password.clone() {
489                    security_settings.insert("psk".to_string(), Value::from(password));
490                }
491            }
492            WiFiSecurityType::Wpa3Psk => {
493                security_settings.insert("key-mgmt".to_string(), Value::from("sae"));
494                if let Some(password) = config.password.clone() {
495                    security_settings.insert("psk".to_string(), Value::from(password));
496                }
497            }
498        }
499
500        connection_settings.insert("802-11-wireless".to_string(), wifi_settings);
501        connection_settings.insert("802-11-wireless-security".to_string(), security_settings);
502
503        // Log constructed settings for debugging
504        log::trace!("connection_settings: {:#?}", connection_settings);
505
506        // Crear un proxy para NetworkManager
507        let nm_proxy = zbus::blocking::Proxy::new(
508            &self.connection,
509            "org.freedesktop.NetworkManager",
510            "/org/freedesktop/NetworkManager",
511            "org.freedesktop.NetworkManager",
512        )?;
513
514        // Llamar al método AddAndActivateConnection (trace result)
515        let call_result: zbus::Result<(zbus::zvariant::OwnedObjectPath, zbus::zvariant::OwnedObjectPath)> = nm_proxy.call("AddAndActivateConnection", &(connection_settings, "/", "/"));
516
517        match call_result {
518            Ok((conn_path, active_path)) => {
519                log::info!(
520                    "AddAndActivateConnection succeeded for ssid='{}' conn='{}' active='{}'",
521                    config.ssid,
522                    conn_path.as_str(),
523                    active_path.as_str()
524                );
525            }
526            Err(e) => {
527                log::error!(
528                    "AddAndActivateConnection failed for ssid='{}': {:?}",
529                    config.ssid,
530                    e
531                );
532                return Err(e.into());
533            }
534        }
535
536        log::debug!("connect_to_wifi finished for ssid='{}'", config.ssid);
537
538        Ok(())
539    }
540
541    /// Toggle network state
542    pub fn toggle_network_state(&self, enabled: bool) -> Result<bool> {
543        let nm_proxy = zbus::blocking::Proxy::new(
544            &self.connection,
545            "org.freedesktop.NetworkManager",
546            "/org/freedesktop/NetworkManager",
547            "org.freedesktop.NetworkManager",
548        )?;
549
550        let state = if enabled { "on" } else { "off" };
551        let _output = Command::new("nmcli")
552            .arg("networking")
553            .arg(state)
554            .output()?;
555
556        let current_state: bool = nm_proxy.get_property("NetworkingEnabled")?;
557        Ok(current_state)
558    }
559
560    /// Get wireless enabled state
561    pub fn get_wireless_enabled(&self) -> Result<bool> {
562        let nm_proxy = zbus::blocking::Proxy::new(
563            &self.connection,
564            "org.freedesktop.NetworkManager",
565            "/org/freedesktop/NetworkManager",
566            "org.freedesktop.NetworkManager",
567        )?;
568        Ok(nm_proxy.get_property("WirelessEnabled")?)
569    }
570
571    /// Set wireless enabled state
572    pub fn set_wireless_enabled(&self, enabled: bool) -> Result<()> {
573        let nm_proxy = zbus::blocking::Proxy::new(
574            &self.connection,
575            "org.freedesktop.NetworkManager",
576            "/org/freedesktop/NetworkManager",
577            "org.freedesktop.NetworkManager",
578        )?;
579        nm_proxy.set_property("WirelessEnabled", enabled)?;
580        Ok(())
581    }
582
583    /// Check if wireless device is available
584    pub fn is_wireless_available(&self) -> Result<bool> {
585         // Get all devices
586        let devices_variant = self.proxy.get(
587            InterfaceName::from_static_str_unchecked("org.freedesktop.NetworkManager"),
588            "Devices",
589        )?;
590
591        if let Some(zbus::zvariant::Value::Array(devices)) = devices_variant.downcast_ref() {
592            let device_values = devices.get();
593            for device in device_values {
594                if let zbus::zvariant::Value::ObjectPath(ref device_path) = device {
595                     let device_props = zbus::blocking::fdo::PropertiesProxy::builder(&self.connection)
596                            .destination("org.freedesktop.NetworkManager")?
597                            .path(device_path)?
598                            .build()?;
599                    
600                    let device_type_variant = device_props.get(
601                        InterfaceName::from_static_str_unchecked("org.freedesktop.NetworkManager.Device"),
602                        "DeviceType",
603                    )?;
604                    
605                    if let Some(zbus::zvariant::Value::U32(device_type)) = device_type_variant.downcast_ref() {
606                        if device_type == &2u32 { // 2 = WiFi
607                            return Ok(true);
608                        }
609                    }
610                }
611            }
612        }
613        Ok(false)
614    }
615
616    /// Listen for network changes
617    pub fn listen_network_changes(&self) -> Result<mpsc::Receiver<NetworkInfo>> {
618        let (tx, rx) = mpsc::channel();
619        let connection_clone = self.connection.clone();
620        let app_handle = self.app.clone();
621
622        // Crear un hilo para escuchar los cambios de red
623        std::thread::spawn(move || {
624            match zbus::blocking::Connection::system() {
625                Ok(conn) => {
626                    // Proxy para el objeto raíz, interfaz DBus.Properties
627                    if let Ok(proxy) = zbus::blocking::Proxy::new(
628                        &conn,
629                        "org.freedesktop.NetworkManager",
630                        "/org/freedesktop/NetworkManager",
631                        "org.freedesktop.NetworkManager",
632                    ) {
633                        if let Ok(mut signal) = proxy.receive_signal("StateChanged") {
634                            while let Some(_msg) = signal.next() {
635                                let network_manager = VSKNetworkManager {
636                                    connection: connection_clone.clone(),
637                                    proxy: zbus::blocking::fdo::PropertiesProxy::builder(
638                                        &connection_clone,
639                                    )
640                                    .destination("org.freedesktop.NetworkManager")
641                                    .unwrap()
642                                    .path("/org/freedesktop/NetworkManager")
643                                    .unwrap()
644                                    .build()
645                                    .unwrap(),
646                                    app: app_handle.clone(),
647                                };
648
649                                if let Ok(network_info) =
650                                    network_manager.get_current_network_state()
651                                {
652                                    if tx.send(network_info).is_err() {
653                                        break;
654                                    }
655                                }
656                            }
657                        }
658                    }
659                }
660                Err(e) => {
661                    eprintln!(
662                        "Error al conectar con D-Bus para escuchar cambios de red: {:?}",
663                        e
664                    );
665                }
666            }
667        });
668
669        Ok(rx)
670    }
671
672    /// Disconnect from the current WiFi network
673    pub async fn disconnect_from_wifi(&self) -> Result<()> {
674        // Obtener el estado actual de la red para identificar la conexión activa
675        let _current_state = self.get_current_network_state()?;
676
677        // Crear un proxy para NetworkManager
678        let nm_proxy = zbus::blocking::Proxy::new(
679            &self.connection,
680            "org.freedesktop.NetworkManager",
681            "/org/freedesktop/NetworkManager",
682            "org.freedesktop.NetworkManager",
683        )?;
684
685        // Obtener las conexiones activas
686        let active_connections_variant: zbus::zvariant::OwnedValue = self.proxy.get(
687            InterfaceName::from_static_str_unchecked("org.freedesktop.NetworkManager"),
688            "ActiveConnections",
689        )?;
690
691        // Convertir el valor a un vector de ObjectPath
692        let active_connections = match active_connections_variant.downcast_ref() {
693            Some(zbus::zvariant::Value::Array(arr)) => arr
694                .iter()
695                .filter_map(|v| match v {
696                    zbus::zvariant::Value::ObjectPath(path) => {
697                        Some(zbus::zvariant::OwnedObjectPath::from(path.to_owned()))
698                    }
699                    _ => None,
700                })
701                .collect::<Vec<zbus::zvariant::OwnedObjectPath>>(),
702            _ => Vec::new(),
703        };
704
705        if !active_connections.is_empty() {
706            nm_proxy.call::<_, _, ()>("DeactivateConnection", &(active_connections[0].as_str()))?;
707            Ok(())
708        } else {
709            Ok(())
710        }
711    }
712
713    /// Get the list of saved WiFi networks
714    pub fn get_saved_wifi_networks(&self) -> Result<Vec<NetworkInfo>> {
715        // Crear un proxy para el servicio de configuración de NetworkManager
716        let settings_proxy = zbus::blocking::Proxy::new(
717            &self.connection,
718            "org.freedesktop.NetworkManager",
719            "/org/freedesktop/NetworkManager/Settings",
720            "org.freedesktop.NetworkManager.Settings",
721        )?;
722
723        // Obtener todas las conexiones guardadas
724        let connections: Vec<zbus::zvariant::OwnedObjectPath> =
725            settings_proxy.call("ListConnections", &())?;
726        let mut saved_networks = Vec::new();
727
728        // Procesar cada conexión guardada
729        for conn_path in connections {
730            // Crear un proxy para cada conexión
731            let conn_proxy = zbus::blocking::Proxy::new(
732                &self.connection,
733                "org.freedesktop.NetworkManager",
734                conn_path.as_str(),
735                "org.freedesktop.NetworkManager.Settings.Connection",
736            )?;
737
738            // Obtener la configuración de la conexión como un HashMap
739            let settings: std::collections::HashMap<String, zbus::zvariant::OwnedValue> =
740                conn_proxy.call("GetSettings", &())?;
741
742            // Verificar si es una conexión WiFi
743            if let Some(connection) = settings.get("connection") {
744                let connection_value = connection.to_owned();
745                let connection_dict =
746                    match <zbus::zvariant::Value<'_> as Clone>::clone(&connection_value)
747                        .downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>(
748                    ) {
749                        Some(dict) => dict,
750                        _ => continue,
751                    };
752
753                // Verificar el tipo de conexión
754                if let Some(conn_type) = connection_dict.get("type") {
755                    let conn_type_value = conn_type.to_owned();
756                    let conn_type_str =
757                        match <zbus::zvariant::Value<'_> as Clone>::clone(&conn_type_value)
758                            .downcast::<String>()
759                        {
760                            Some(s) => s,
761                            _ => continue,
762                        };
763
764                    // Si es una conexión WiFi, extraer la información
765                    if conn_type_str == "802-11-wireless" {
766                        let mut network_info = NetworkInfo::default();
767                        network_info.connection_type = "wifi".to_string();
768
769                        // Obtener el nombre de la conexión
770                        if let Some(id) = connection_dict.get("id") {
771                            let id_value = id.to_owned();
772                            if let Some(name) =
773                                <zbus::zvariant::Value<'_> as Clone>::clone(&id_value)
774                                    .downcast::<String>()
775                            {
776                                network_info.name = name;
777                            }
778                        }
779
780                        // Obtener el SSID
781                        if let Some(wireless) = settings.get("802-11-wireless") {
782                            let wireless_value = wireless.to_owned();
783                            let wireless_dict = match <zbus::zvariant::Value<'_> as Clone>::clone(&wireless_value).downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>() {
784                                Some(dict) => dict,
785                                _ => continue,
786                            };
787
788                            if let Some(ssid) = wireless_dict.get("ssid") {
789                                let ssid_value = ssid.to_owned();
790                                if let Some(ssid_bytes) =
791                                    <zbus::zvariant::Value<'_> as Clone>::clone(&ssid_value)
792                                        .downcast::<Vec<u8>>()
793                                {
794                                    if let Ok(ssid_str) = String::from_utf8(ssid_bytes) {
795                                        network_info.ssid = ssid_str;
796                                    }
797                                }
798                            }
799                        }
800
801                        // Determinar el tipo de seguridad
802                        if let Some(security) = settings.get("802-11-wireless-security") {
803                            let security_value = security.to_owned();
804                            let security_dict = match <zbus::zvariant::Value<'_> as Clone>::clone(&security_value).downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>() {
805                                Some(dict) => dict,
806                                _ => {
807                                    network_info.security_type = WiFiSecurityType::None;
808                                    saved_networks.push(network_info);
809                                    continue;
810                                },
811                            };
812
813                            if let Some(key_mgmt) = security_dict.get("key-mgmt") {
814                                let key_mgmt_value = key_mgmt.to_owned();
815                                if let Some(key_mgmt_str) =
816                                    <zbus::zvariant::Value<'_> as Clone>::clone(&key_mgmt_value)
817                                        .downcast::<String>()
818                                {
819                                    match key_mgmt_str.as_str() {
820                                        "none" => {
821                                            network_info.security_type = WiFiSecurityType::None
822                                        }
823                                        "wpa-psk" => {
824                                            network_info.security_type = WiFiSecurityType::WpaPsk
825                                        }
826                                        "wpa-eap" => {
827                                            network_info.security_type = WiFiSecurityType::WpaEap
828                                        }
829                                        _ => network_info.security_type = WiFiSecurityType::None,
830                                    }
831                                }
832                            }
833                        } else {
834                            network_info.security_type = WiFiSecurityType::None;
835                        }
836
837                        // Agregar a la lista de redes guardadas
838                        saved_networks.push(network_info);
839                    }
840                }
841            }
842        }
843
844        Ok(saved_networks)
845    }
846
847    /// Delete a saved WiFi connection by SSID
848    pub fn delete_wifi_connection(&self, ssid: &str) -> Result<bool> {
849        // Crear un proxy para el servicio de configuración de NetworkManager
850        let settings_proxy = zbus::blocking::Proxy::new(
851            &self.connection,
852            "org.freedesktop.NetworkManager",
853            "/org/freedesktop/NetworkManager/Settings",
854            "org.freedesktop.NetworkManager.Settings",
855        )?;
856
857        // Obtener todas las conexiones guardadas
858        let connections: Vec<zbus::zvariant::OwnedObjectPath> =
859            settings_proxy.call("ListConnections", &())?;
860
861        // Procesar cada conexión guardada
862        for conn_path in connections {
863            // Crear un proxy para cada conexión
864            let conn_proxy = zbus::blocking::Proxy::new(
865                &self.connection,
866                "org.freedesktop.NetworkManager",
867                conn_path.as_str(),
868                "org.freedesktop.NetworkManager.Settings.Connection",
869            )?;
870
871            // Obtener la configuración de la conexión como un HashMap
872            let settings: std::collections::HashMap<String, zbus::zvariant::OwnedValue> =
873                conn_proxy.call("GetSettings", &())?;
874
875            // Verificar si es una conexión WiFi
876            if let Some(connection) = settings.get("connection") {
877                let connection_value = connection.to_owned();
878                let connection_dict =
879                    match <zbus::zvariant::Value<'_> as Clone>::clone(&connection_value)
880                        .downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>(
881                    ) {
882                        Some(dict) => dict,
883                        _ => continue,
884                    };
885
886                // Verificar el tipo de conexión
887                if let Some(conn_type) = connection_dict.get("type") {
888                    let conn_type_value = conn_type.to_owned();
889                    let conn_type_str =
890                        match <zbus::zvariant::Value<'_> as Clone>::clone(&conn_type_value)
891                            .downcast::<String>()
892                        {
893                            Some(s) => s,
894                            _ => continue,
895                        };
896
897                    // Si es una conexión WiFi, verificar el SSID
898                    if conn_type_str == "802-11-wireless" {
899                        if let Some(wireless) = settings.get("802-11-wireless") {
900                            let wireless_value = wireless.to_owned();
901                            let wireless_dict = match <zbus::zvariant::Value<'_> as Clone>::clone(&wireless_value).downcast::<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>() {
902                                Some(dict) => dict,
903                                _ => continue,
904                            };
905
906                            if let Some(ssid_value) = wireless_dict.get("ssid") {
907                                let ssid_owned = ssid_value.to_owned();
908                                if let Some(ssid_bytes) =
909                                    <zbus::zvariant::Value<'_> as Clone>::clone(&ssid_owned)
910                                        .downcast::<Vec<u8>>()
911                                {
912                                    if let Ok(conn_ssid_str) = String::from_utf8(ssid_bytes) {
913                                        // Si el SSID coincide, eliminar la conexión
914                                        if conn_ssid_str == ssid {
915                                            conn_proxy.call::<_, _, ()>("Delete", &())?;
916                                            return Ok(true);
917                                        }
918                                    }
919                                }
920                            }
921                        }
922                    }
923                }
924            }
925        }
926
927        // No se encontró ninguna conexión con el SSID especificado
928        Ok(false)
929    }
930}
931
932/// Initialize the network manager plugin
933pub async fn init(
934    app: &AppHandle<tauri::Wry>,
935    _api: PluginApi<tauri::Wry, ()>,
936) -> Result<VSKNetworkManager<'static, tauri::Wry>> {
937    Ok(VSKNetworkManager::new(app.clone()).await?)
938}