Skip to content

Commit 909e2ab

Browse files
committed
refactor(network): Use nmrs for WiFi connections
Replace D-Bus channel flow with direct nmrs API calls for WiFi connections. Provides typed error handling and simplifies code. - Add nmrs 1.3.0 dependency - Use `nmrs.connect()` for open and secured networks - Add `ConnectionError` variants for better error messages - Remove request/sender channel boilerplate
1 parent 44ec34f commit 909e2ab

File tree

3 files changed

+143
-67
lines changed

3 files changed

+143
-67
lines changed

Cargo.lock

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cosmic-applet-network/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ nm-secret-agent-manager = { git = "https://github.com/pop-os/dbus-settings-bindi
3131
indexmap = "2.13.0"
3232
secure-string = "0.3.0"
3333
uuid = { version = "1.19.0", features = ["v4"] }
34+
nmrs = "1.3.5"
3435

3536

3637
[dependencies.cosmic-settings-network-manager-subscription]

cosmic-applet-network/src/app.rs

Lines changed: 112 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use cosmic_settings_network_manager_subscription::{
1111
use indexmap::IndexMap;
1212
use rustc_hash::FxHashSet;
1313
use secure_string::SecureString;
14+
use nmrs::{ConnectionError, EapMethod, EapOptions, Phase2, WifiSecurity};
1415
use std::{
1516
borrow::Cow,
1617
collections::{BTreeMap, BTreeSet},
@@ -162,6 +163,7 @@ struct CosmicNetworkApplet {
162163
nm_task: Option<tokio::sync::oneshot::Sender<()>>,
163164
secret_tx: Option<tokio::sync::mpsc::Sender<nm_secret_agent::Request>>,
164165
nm_state: MyNetworkState,
166+
nm: Option<nmrs::NetworkManager>,
165167

166168
// UI state
167169
show_visible_networks: bool,
@@ -502,6 +504,7 @@ pub(crate) enum Message {
502504
ConnectVPNWithPassword,
503505
VPNPasswordUpdate(SecureString),
504506
CancelVPNConnection,
507+
NmrsReady(Option<nmrs::NetworkManager>),
505508
}
506509

507510
#[derive(Debug, Clone)]
@@ -841,56 +844,39 @@ impl cosmic::Application for CosmicNetworkApplet {
841844
}
842845
}
843846
Message::SelectWirelessAccessPoint(access_point) => {
844-
let Some(tx) = self.nm_sender.as_ref() else {
845-
return Task::none();
847+
let Some(nm) = self.nm.clone() else {
848+
return cosmic::task::message(Message::Error(
849+
"Network manager not initialized".to_string()
850+
)).map(cosmic::Action::App);
846851
};
847-
852+
853+
// Open networks - connect immediately
848854
if matches!(access_point.network_type, NetworkType::Open) {
849-
if let Err(err) =
850-
tx.unbounded_send(network_manager::Request::SelectAccessPoint(
851-
access_point.ssid.clone(),
852-
access_point.hw_address,
853-
access_point.network_type,
854-
self.secret_tx.clone(),
855-
))
856-
{
857-
if err.is_disconnected() {
858-
return system_conn().map(cosmic::Action::App);
859-
}
860-
861-
tracing::error!("{err:?}");
862-
}
855+
let ssid = access_point.ssid.to_string();
863856
self.new_connection = Some(NewConnectionState::Waiting(access_point));
864-
} else {
865-
if self
866-
.nm_state
867-
.nm_state
868-
.known_access_points
869-
.contains(&access_point)
870-
{
871-
if let Err(err) =
872-
tx.unbounded_send(network_manager::Request::SelectAccessPoint(
873-
access_point.ssid.clone(),
874-
access_point.hw_address,
875-
access_point.network_type,
876-
self.secret_tx.clone(),
877-
))
878-
{
879-
if err.is_disconnected() {
880-
return system_conn().map(cosmic::Action::App);
857+
858+
return cosmic::task::future(async move {
859+
match nm.connect(&ssid, WifiSecurity::Open).await {
860+
Ok(()) => {
861+
tracing::info!("Connected to open network {}", ssid);
862+
Message::Refresh
863+
}
864+
Err(e) => {
865+
tracing::error!("Failed to connect to {}: {}", ssid, e);
866+
Message::Error(format!("Failed to connect to '{}': {}", ssid, e))
881867
}
882-
883-
tracing::error!("{err:?}");
884868
}
885-
}
886-
self.new_connection = Some(NewConnectionState::EnterPassword {
887-
access_point,
888-
description: None,
889-
identity: String::new(),
890-
password: String::new().into(),
891-
password_hidden: true,
892-
});
869+
}).map(cosmic::Action::App);
893870
}
871+
872+
// Secured networks - show password dialog
873+
self.new_connection = Some(NewConnectionState::EnterPassword {
874+
access_point,
875+
description: None,
876+
identity: String::new(),
877+
password: String::new().into(),
878+
password_hidden: true,
879+
});
894880
}
895881
Message::ToggleVisibleNetworks => {
896882
self.new_connection = None;
@@ -1046,35 +1032,73 @@ impl cosmic::Application for CosmicNetworkApplet {
10461032
}
10471033
}
10481034
Message::ConnectWithPassword => {
1049-
// save password
1050-
let Some(tx) = self.nm_sender.as_ref() else {
1051-
return Task::none();
1052-
};
1053-
1054-
if let Some(NewConnectionState::EnterPassword {
1035+
let Some(NewConnectionState::EnterPassword {
10551036
password,
10561037
access_point,
10571038
identity,
10581039
..
1059-
}) = self.new_connection.take()
1060-
{
1061-
let is_enterprise: bool = matches!(access_point.network_type, NetworkType::EAP);
1062-
1063-
if let Err(err) = tx.unbounded_send(network_manager::Request::Authenticate {
1064-
ssid: access_point.ssid.to_string(),
1065-
identity: is_enterprise.then(|| identity.clone()),
1066-
password,
1067-
hw_address: access_point.hw_address,
1068-
secret_tx: self.secret_tx.clone(),
1069-
}) {
1070-
if err.is_disconnected() {
1071-
return system_conn().map(cosmic::Action::App);
1040+
}) = self.new_connection.take() else {
1041+
return Task::none();
1042+
};
1043+
1044+
let Some(nm) = self.nm.clone() else {
1045+
return cosmic::task::message(Message::Error(
1046+
"Network manager not initialized".to_string()
1047+
)).map(cosmic::Action::App);
1048+
};
1049+
1050+
let ssid = access_point.ssid.to_string();
1051+
let password_str = password.unsecure().to_string();
1052+
1053+
self.new_connection = Some(NewConnectionState::Waiting(access_point.clone()));
1054+
1055+
return cosmic::task::future(async move {
1056+
let security = match access_point.network_type {
1057+
NetworkType::Open => WifiSecurity::Open,
1058+
NetworkType::EAP => {
1059+
WifiSecurity::WpaEap {
1060+
opts: EapOptions {
1061+
identity: identity.clone(),
1062+
password: password_str,
1063+
anonymous_identity: None,
1064+
domain_suffix_match: None,
1065+
ca_cert_path: None,
1066+
system_ca_certs: true,
1067+
method: EapMethod::Peap,
1068+
phase2: Phase2::Mschapv2,
1069+
}
1070+
}
1071+
}
1072+
_ => {
1073+
// All other types (including secured networks) use WPA-PSK
1074+
WifiSecurity::WpaPsk {
1075+
psk: password_str,
1076+
}
1077+
}
1078+
};
1079+
1080+
match nm.connect(&ssid, security).await {
1081+
Ok(()) => {
1082+
tracing::info!("Connected to {}", ssid);
1083+
Message::Refresh
1084+
}
1085+
Err(e) => {
1086+
tracing::error!("Connection to {} failed: {}", ssid, e);
1087+
let error_msg = match e {
1088+
ConnectionError::AuthFailed =>
1089+
format!("Wrong password for '{}'", ssid),
1090+
ConnectionError::NotFound =>
1091+
format!("Network '{}' out of range", ssid),
1092+
ConnectionError::Timeout =>
1093+
format!("Connection to '{}' timed out", ssid),
1094+
ConnectionError::DhcpFailed =>
1095+
format!("Connected but failed to get IP address"),
1096+
_ => format!("Failed to connect: {}", e),
1097+
};
1098+
Message::Error(error_msg)
10721099
}
1073-
tracing::error!("Failed to authenticate with network manager");
10741100
}
1075-
self.new_connection
1076-
.replace(NewConnectionState::Waiting(access_point));
1077-
}
1101+
}).map(cosmic::Action::App);
10781102
}
10791103
Message::ConnectionSettings(btree_map) => {
10801104
self.nm_state.ssid_to_uuid = btree_map;
@@ -1250,9 +1274,24 @@ impl cosmic::Application for CosmicNetworkApplet {
12501274
} => {}
12511275
},
12521276
Message::NetworkManagerConnect(connection) => {
1277+
// Initialize nmrs in a separate task
1278+
let init_task = cosmic::task::future(async {
1279+
match nmrs::NetworkManager::new().await {
1280+
Ok(nm) => {
1281+
tracing::info!("nmrs NetworkManager initialized");
1282+
Message::NmrsReady(Some(nm))
1283+
}
1284+
Err(e) => {
1285+
tracing::warn!("Failed to initialize nmrs: {}", e);
1286+
Message::NmrsReady(None)
1287+
}
1288+
}
1289+
});
1290+
12531291
return cosmic::task::batch(vec![
12541292
self.connect(connection.clone()),
12551293
connection_settings(connection),
1294+
init_task.map(cosmic::Action::App),
12561295
]);
12571296
}
12581297
Message::PasswordUpdate(entered_pw) => {
@@ -1376,6 +1415,12 @@ impl cosmic::Application for CosmicNetworkApplet {
13761415
Message::CancelVPNConnection => {
13771416
self.nm_state.requested_vpn = None;
13781417
}
1418+
Message::NmrsReady(nm) => {
1419+
self.nm = nm;
1420+
if self.nm.is_some() {
1421+
tracing::info!("nmrs ready for WiFi connections");
1422+
}
1423+
}
13791424
}
13801425
Task::none()
13811426
}

0 commit comments

Comments
 (0)