Unstable sorting should be slightly faster than stable sorting, and if the vector was built asynchronously then preserving the initial order doesn't matter too much. Continue to use stable sorting where the vector is not built asynchronously, or if the vector is partially sorted (e.g. when new elements are pushed to a sorted vector).
172 lines
5.5 KiB
Rust
172 lines
5.5 KiB
Rust
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
use cosmic_dbus_networkmanager::{
|
|
active_connection::ActiveConnection, device::SpecificDevice,
|
|
interface::enums::ActiveConnectionState,
|
|
};
|
|
use std::net::Ipv4Addr;
|
|
|
|
use super::hw_address::HwAddress;
|
|
|
|
pub async fn active_connections(
|
|
active_connections: Vec<ActiveConnection<'_>>,
|
|
) -> zbus::Result<Vec<ActiveConnectionInfo>> {
|
|
let mut info = Vec::<ActiveConnectionInfo>::with_capacity(active_connections.len());
|
|
for connection in active_connections {
|
|
let ipv4 = connection
|
|
.ip4_config()
|
|
.await?
|
|
.address_data()
|
|
.await
|
|
.unwrap_or_default();
|
|
let addresses: Vec<_> = ipv4.iter().map(|d| d.address).collect();
|
|
let state = connection
|
|
.state()
|
|
.await
|
|
.unwrap_or(ActiveConnectionState::Unknown);
|
|
|
|
if connection.vpn().await.unwrap_or_default() {
|
|
info.push(ActiveConnectionInfo::Vpn {
|
|
name: connection.id().await?,
|
|
ip_addresses: addresses.clone(),
|
|
});
|
|
continue;
|
|
}
|
|
for device in connection.devices().await.unwrap_or_default() {
|
|
match device
|
|
.downcast_to_device()
|
|
.await
|
|
.ok()
|
|
.and_then(|inner| inner)
|
|
{
|
|
Some(SpecificDevice::Wired(wired_device)) => {
|
|
info.push(ActiveConnectionInfo::Wired {
|
|
name: connection.id().await?,
|
|
hw_address: HwAddress::from_str(&wired_device.hw_address().await?)
|
|
.unwrap_or_default(),
|
|
speed: wired_device.speed().await?,
|
|
ip_addresses: addresses.clone(),
|
|
});
|
|
}
|
|
Some(SpecificDevice::Wireless(wireless_device)) => {
|
|
if let Ok(access_point) = wireless_device.active_access_point().await {
|
|
info.push(ActiveConnectionInfo::WiFi {
|
|
name: String::from_utf8_lossy(&access_point.ssid().await?).into_owned(),
|
|
ip_addresses: addresses.clone(),
|
|
hw_address: HwAddress::from_str(&wireless_device.hw_address().await?)
|
|
.unwrap_or_default(),
|
|
state,
|
|
strength: access_point.strength().await.unwrap_or_default(),
|
|
});
|
|
}
|
|
}
|
|
Some(SpecificDevice::WireGuard(_)) => {
|
|
info.push(ActiveConnectionInfo::Vpn {
|
|
name: connection.id().await?,
|
|
ip_addresses: addresses.clone(),
|
|
});
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
info.sort_unstable();
|
|
Ok(info)
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum ActiveConnectionInfo {
|
|
Wired {
|
|
name: String,
|
|
hw_address: HwAddress,
|
|
speed: u32,
|
|
ip_addresses: Vec<Ipv4Addr>,
|
|
},
|
|
WiFi {
|
|
name: String,
|
|
ip_addresses: Vec<Ipv4Addr>,
|
|
hw_address: HwAddress,
|
|
state: ActiveConnectionState,
|
|
strength: u8,
|
|
},
|
|
Vpn {
|
|
name: String,
|
|
ip_addresses: Vec<Ipv4Addr>,
|
|
},
|
|
}
|
|
|
|
impl ActiveConnectionInfo {
|
|
pub fn name(&self) -> String {
|
|
match &self {
|
|
Self::Wired { name, .. } | Self::WiFi { name, .. } | Self::Vpn { name, .. } => {
|
|
name.clone()
|
|
}
|
|
}
|
|
}
|
|
pub fn hw_address(&self) -> HwAddress {
|
|
match &self {
|
|
Self::Wired { hw_address, .. } | Self::WiFi { hw_address, .. } => *hw_address,
|
|
Self::Vpn { .. } => HwAddress::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::cmp::Ord for ActiveConnectionInfo {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
match (self, other) {
|
|
(Self::Vpn { .. }, Self::Wired { .. } | Self::WiFi { .. })
|
|
| (Self::Wired { .. }, Self::WiFi { .. }) => std::cmp::Ordering::Greater,
|
|
|
|
(Self::WiFi { .. }, Self::Wired { .. } | Self::Vpn { .. })
|
|
| (Self::Wired { .. }, Self::Vpn { .. }) => std::cmp::Ordering::Less,
|
|
|
|
(Self::Vpn { name: n1, .. }, Self::Vpn { name: n2, .. })
|
|
| (Self::Wired { name: n1, .. }, Self::Wired { name: n2, .. })
|
|
| (Self::WiFi { name: n1, .. }, Self::WiFi { name: n2, .. }) => n1.cmp(n2),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::cmp::Eq for ActiveConnectionInfo {}
|
|
|
|
impl std::cmp::PartialOrd for ActiveConnectionInfo {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl std::cmp::PartialEq for ActiveConnectionInfo {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(
|
|
Self::Wired {
|
|
name: n1,
|
|
hw_address: a1,
|
|
..
|
|
},
|
|
Self::Wired {
|
|
name: n2,
|
|
hw_address: a2,
|
|
..
|
|
},
|
|
)
|
|
| (
|
|
Self::WiFi {
|
|
name: n1,
|
|
hw_address: a1,
|
|
..
|
|
},
|
|
Self::WiFi {
|
|
name: n2,
|
|
hw_address: a2,
|
|
..
|
|
},
|
|
) => n1 == n2 && a1 == a2,
|
|
|
|
(Self::Vpn { name: n1, .. }, Self::Vpn { name: n2, .. }) => n1 == n2,
|
|
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|