From 13ccc03676e40059913a50d537a7e59c627f91f2 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 4 Jan 2023 22:12:46 -0500 Subject: [PATCH 01/11] wip: network applet more like mockup --- Cargo.lock | 31 +- cosmic-applet-network/Cargo.toml | 2 +- .../i18n/en/cosmic_applet_network.ftl | 9 + cosmic-applet-network/src/app.rs | 404 ++++++++++++++---- .../src/network_manager/current_networks.rs | 69 ++- 5 files changed, 376 insertions(+), 139 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 128e67ad..632d1e82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -668,7 +668,7 @@ dependencies = [ [[package]] name = "cosmic-panel-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-panel#9502913468dc7bf1cc17da6c1fcf1e274f43a769" +source = "git+https://github.com/pop-os/cosmic-panel#bab60b3883bd90b71b1be8bdf771fa11be0cf1dc" dependencies = [ "anyhow", "ron", @@ -1996,7 +1996,7 @@ dependencies = [ [[package]] name = "iced" version = "0.6.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "iced_core", "iced_futures", @@ -2013,7 +2013,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.6.2" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "bitflags", "palette", @@ -2023,7 +2023,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "futures", "log", @@ -2035,7 +2035,7 @@ dependencies = [ [[package]] name = "iced_glow" version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "bytemuck", "euclid", @@ -2050,7 +2050,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.5.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "bitflags", "bytemuck", @@ -2070,7 +2070,7 @@ dependencies = [ [[package]] name = "iced_lazy" version = "0.3.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "iced_native", "ouroboros 0.13.0", @@ -2079,7 +2079,7 @@ dependencies = [ [[package]] name = "iced_native" version = "0.7.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "iced_core", "iced_futures", @@ -2093,7 +2093,7 @@ dependencies = [ [[package]] name = "iced_sctk" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "enum-repr", "futures", @@ -2112,7 +2112,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "iced_core", "once_cell", @@ -2122,7 +2122,7 @@ dependencies = [ [[package]] name = "iced_swbuf" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "cosmic-text", "iced_graphics", @@ -2137,7 +2137,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.7.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "bitflags", "bytemuck", @@ -2327,7 +2327,7 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#444e389496bb92a928b7731175f00f51ec4f0caa" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" dependencies = [ "apply", "cosmic-panel-config", @@ -2336,7 +2336,6 @@ dependencies = [ "freedesktop-icons", "iced", "iced_core", - "iced_glow", "iced_lazy", "iced_native", "iced_style", @@ -3953,9 +3952,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8" dependencies = [ "autocfg", "bytes", diff --git a/cosmic-applet-network/Cargo.toml b/cosmic-applet-network/Cargo.toml index 18e681db..a1b75f8e 100644 --- a/cosmic-applet-network/Cargo.toml +++ b/cosmic-applet-network/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-or-later" once_cell = "1.16.0" cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", branch = "deps" } futures-util = "0.3.21" -libcosmic = { git = "https://github.com/pop-os/libcosmic/", branch = "master", default-features = false, features = ["wayland", "applet"] } +libcosmic = { git = "https://github.com/pop-os/libcosmic/", branch = "master", default-features = false, features = ["wayland", "applet", "tokio"] } sctk = { package = "smithay-client-toolkit", git = "https://github.com/Smithay/client-toolkit", rev = "3776d4a" } futures = "0.3" zbus = { version = "3.6.2", no-default-features = true } diff --git a/cosmic-applet-network/i18n/en/cosmic_applet_network.ftl b/cosmic-applet-network/i18n/en/cosmic_applet_network.ftl index e19faeed..1a107ca3 100644 --- a/cosmic-applet-network/i18n/en/cosmic_applet_network.ftl +++ b/cosmic-applet-network/i18n/en/cosmic_applet_network.ftl @@ -5,3 +5,12 @@ ipv4 = IPv4 Address ipv6 = IPv6 Address mac = MAC megabits-per-second = Mbps +connected = Connected +connecting = Connecting +connect = Connect +cancel = Cancel +visible-wireless-networks = Visible Wireless Networks +enter-password = Enter the password or encryption key +router-wps-button = You can also connect by pressing the "WIPS" button on the router +unable-to-connect = Unable to connect to network +check-wifi-connection = Make sure Wi-Fi is connected to the internet and the password is correct \ No newline at end of file diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index 92949f8b..b81506d7 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -6,15 +6,31 @@ use cosmic::{ popup::{destroy_popup, get_popup}, SurfaceIdWrapper, }, - widget::{column, container, row, scrollable, text}, + widget::{column, container, row, scrollable, text, text_input}, Alignment, Application, Color, Command, Length, Subscription, }, - iced_native::window, - iced_style::{application, svg}, + iced_native::{ + alignment::{Horizontal, Vertical}, + layout::Limits, + renderer::BorderRadius, + subscription, window, + }, + iced_style::{application, button::StyleSheet, svg}, theme::{Button, Svg}, widget::{button, horizontal_rule, icon, list_column, toggler}, Element, Theme, }; +use cosmic::{ + iced_style, + widget::segmented_button::{ + self, + cosmic::{ + horizontal_segmented_selection, horizontal_view_switcher, vertical_segmented_selection, + vertical_view_switcher, + }, + }, +}; +use cosmic_dbus_networkmanager::access_point; use futures::channel::mpsc::UnboundedSender; use crate::{ @@ -30,7 +46,29 @@ pub fn run() -> cosmic::iced::Result { CosmicNetworkApplet::run(helper.window_settings()) } -#[derive(Clone, Default)] +enum NewConnectionState { + EnterPassword { + access_point: AccessPoint, + password: String, + }, + Waiting(AccessPoint), + Failure(AccessPoint), +} + +impl Into for NewConnectionState { + fn into(self) -> AccessPoint { + match self { + NewConnectionState::EnterPassword { + access_point, + password, + } => access_point, + NewConnectionState::Waiting(access_point) => access_point, + NewConnectionState::Failure(access_point) => access_point, + } + } +} + +#[derive(Default)] struct CosmicNetworkApplet { icon_name: String, theme: Theme, @@ -43,6 +81,8 @@ struct CosmicNetworkApplet { wireless_access_points: Vec, active_conns: Vec, nm_sender: Option>, + show_visible_networks: bool, + new_connection: Option, } impl CosmicNetworkApplet { @@ -72,10 +112,14 @@ enum Message { TogglePopup, ToggleAirplaneMode(bool), ToggleWiFi(bool), + ToggleVisibleNetworks, Errored(String), Ignore, NetworkManagerEvent(NetworkManagerEvent), - SelectWirelessAccessPoint(String), + SelectWirelessAccessPoint(AccessPoint), + CancelNewConnection, + Password(String), + SubmitPassword, } impl Application for CosmicNetworkApplet { @@ -109,13 +153,18 @@ impl Application for CosmicNetworkApplet { let new_id = window::Id::new(self.id_ctr); self.popup.replace(new_id); - let popup_settings = self.applet_helper.get_popup_settings( + let mut popup_settings = self.applet_helper.get_popup_settings( window::Id::new(0), new_id, None, None, None, ); + popup_settings.positioner.size_limits = Limits::NONE + .min_height(1) + .min_width(1) + .max_height(600) + .max_width(600); return get_popup(popup_settings); } } @@ -166,20 +215,65 @@ impl Application for CosmicNetworkApplet { if success { self.wireless_access_points = wireless_access_points; self.active_conns = active_conns; + self.wifi = wifi_enabled; self.update_icon_name(); } } }, - Message::SelectWirelessAccessPoint(ssid) => { - if let Some(tx) = self.nm_sender.as_ref() { - let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint(ssid)); + Message::SelectWirelessAccessPoint(access_point) => { + // if let Some(tx) = self.nm_sender.as_ref() { + // let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint( + // access_point.ssid.clone(), + // )); + // } + self.new_connection + .replace(NewConnectionState::EnterPassword { + access_point, + password: String::new(), + }); + } + Message::ToggleVisibleNetworks => { + self.new_connection.take(); + self.show_visible_networks = !self.show_visible_networks; + } + Message::Password(entered_pw) => { + dbg!(&entered_pw); + + match &mut self.new_connection { + Some(NewConnectionState::EnterPassword { password, .. }) => { + *password = entered_pw; + } + _ => {} } } + Message::SubmitPassword => { + // TODO setup connection + match self.new_connection.take() { + Some(new_connection) => { + self.new_connection + .replace(NewConnectionState::Failure(new_connection.into())); + } + None => {} + } + } + Message::CancelNewConnection => { + self.new_connection.take(); + } } Command::none() } fn view(&self, id: SurfaceIdWrapper) -> Element { + let button_style = Button::Custom { + active: |t| iced_style::button::Appearance { + border_radius: BorderRadius::from(0.0), + ..t.active(&Button::Text) + }, + hover: |t| iced_style::button::Appearance { + border_radius: BorderRadius::from(0.0), + ..t.hovered(&Button::Text) + }, + }; match id { SurfaceIdWrapper::LayerSurface(_) => unimplemented!(), SurfaceIdWrapper::Window(_) => self @@ -188,39 +282,23 @@ impl Application for CosmicNetworkApplet { .on_press(Message::TogglePopup) .into(), SurfaceIdWrapper::Popup(_) => { - let name = text(fl!("network")).size(18); - let icon = icon(&*self.icon_name, 24) - .style(Svg::Custom(|theme| svg::Appearance { - color: Some(theme.palette().text), - })) - .width(Length::Units(24)) - .height(Length::Units(24)); - let mut list_col = list_column(); - + let mut list_col = column![]; for conn in &self.active_conns { let el = match conn { ActiveConnectionInfo::Vpn { name, ip_addresses } => { let mut ipv4 = column![]; - let mut ipv6 = column![]; for addr in ip_addresses { match addr { std::net::IpAddr::V4(a) => { - ipv4 = ipv4.push(text(format!( - "{}: {}", - fl!("ipv4"), - a.to_string() - ))); - } - std::net::IpAddr::V6(a) => { - ipv6 = ipv6.push(text(format!( - "{}: {}", - fl!("ipv6"), - a.to_string() - ))); + ipv4 = ipv4.push( + text(format!("{}: {}", fl!("ipv4"), a.to_string())) + .size(12), + ); } + std::net::IpAddr::V6(a) => {} } } - column![text(name), ipv4, ipv6].spacing(4) + column![text(name), ipv4].spacing(4) } ActiveConnectionInfo::Wired { name, @@ -229,23 +307,15 @@ impl Application for CosmicNetworkApplet { ip_addresses, } => { let mut ipv4 = column![]; - let mut ipv6 = column![]; for addr in ip_addresses { match addr { std::net::IpAddr::V4(a) => { - ipv4 = ipv4.push(text(format!( - "{}: {}", - fl!("ipv4"), - a.to_string() - ))); - } - std::net::IpAddr::V6(a) => { - ipv6 = ipv6.push(text(format!( - "{}: {}", - fl!("ipv6"), - a.to_string() - ))); + ipv4 = ipv4.push( + text(format!("{}: {}", fl!("ipv4"), a.to_string())) + .size(12), + ); } + std::net::IpAddr::V6(a) => {} } } column![ @@ -255,27 +325,51 @@ impl Application for CosmicNetworkApplet { ] .spacing(16), ipv4, - ipv6, - text(format!("{}: {hw_address}", fl!("mac"))), ] .spacing(4) } ActiveConnectionInfo::WiFi { - name, hw_address, .. - } => column![row![ - text(name), - text(format!("{}: {hw_address}", fl!("mac"))) - ] - .spacing(12)] - .spacing(4), + name, ip_addresses, .. + } => { + let mut ipv4 = column![]; + for addr in ip_addresses { + match addr { + std::net::IpAddr::V4(a) => { + ipv4 = ipv4.push( + text(format!("{}: {}", fl!("ipv4"), a.to_string())) + .size(12), + ); + } + std::net::IpAddr::V6(a) => {} + } + } + column![button(Button::Secondary) + .custom(vec![ + icon("network-wireless-symbolic", 24) + .style(Svg::Custom(|theme| svg::Appearance { + color: Some(theme.palette().text), + })) + .width(Length::Units(24)) + .height(Length::Units(24)) + .into(), + column![text(name).size(14), ipv4,].into(), + text(format!("{}", fl!("connected"))) + .size(14) + .width(Length::Fill) + .height(Length::Units(24)) + .horizontal_alignment(Horizontal::Right) + .vertical_alignment(Vertical::Center) + .into() + ]) + .padding([8, 24]) + .style(button_style.clone()) + .on_press(Message::Ignore)] + } }; - list_col = list_col.add(el); + list_col = list_col.push(el); } let mut content = column![ - row![icon, name].spacing(8).width(Length::Fill), - list_col, - horizontal_rule(1), container( toggler(fl!("airplane-mode"), self.airplane_mode, |m| { Message::ToggleAirplaneMode(m) @@ -289,36 +383,178 @@ impl Application for CosmicNetworkApplet { .width(Length::Fill) ) .padding([0, 12]), + horizontal_rule(1), + list_col, ] .align_items(Alignment::Center) .spacing(8) - .padding(8); - if self.wifi { - let mut list_col = list_column(); - for ap in &self.wireless_access_points { - let button = self - .active_conns - .iter() - .find_map(|conn| match conn { - ActiveConnectionInfo::WiFi { name, .. } if name == &ap.ssid => { - Some( - button(Button::Primary) - .text(&ap.ssid) - .on_press(Message::Ignore) - .width(Length::Fill), - ) - } - _ => None, - }) - .unwrap_or_else(|| { - button(Button::Text) - .text(&ap.ssid) - .on_press(Message::SelectWirelessAccessPoint(ap.ssid.clone())) - .width(Length::Fill) - }); - list_col = list_col.add(button); + .padding([8, 0]); + let dropdown_icon = if self.show_visible_networks { + "go-down-symbolic" + } else { + "go-next-symbolic" + }; + let available_connections_btn = button(Button::Secondary) + .custom( + vec![ + text(fl!("visible-wireless-networks")) + .size(14) + .width(Length::Fill) + .height(Length::Units(24)) + .vertical_alignment(Vertical::Center) + .into(), + container( + icon(dropdown_icon, 14) + .style(Svg::Custom(|theme| svg::Appearance { + color: Some(theme.palette().text), + })) + .width(Length::Units(14)) + .height(Length::Units(14)), + ) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .width(Length::Units(24)) + .height(Length::Units(24)) + .into(), + ] + .into(), + ) + .padding([8, 24]) + .style(button_style.clone()) + .on_press(Message::ToggleVisibleNetworks); + content = content.push(available_connections_btn); + if self.show_visible_networks { + if let Some(new_conn_state) = self.new_connection.as_ref() { + match new_conn_state { + NewConnectionState::EnterPassword { + access_point, + password, + } => { + let id = row![ + icon("network-wireless-symbolic", 24) + .style(Svg::Custom(|theme| svg::Appearance { + color: Some(theme.palette().text), + })) + .width(Length::Units(24)) + .height(Length::Units(24)), + text(&access_point.ssid).size(14), + ] + .align_items(Alignment::Center) + .width(Length::Fill) + .padding([0, 24]) + .spacing(12); + content = content.push(id); + let col = column![ + text(fl!("enter-password")), + text_input("", password, Message::Password) + .on_submit(Message::SubmitPassword) + .password(), + container(text(fl!("router-wps-button"))).padding(8), + row![ + button(Button::Secondary) + .custom(vec![container(text(fl!("cancel"))) + .padding([0, 24]) + .into()]) + .on_press(Message::CancelNewConnection), + button(Button::Secondary).custom(vec![container(text( + fl!("connect") + )) + .padding([0, 24]) + .into()]) + ] + .spacing(24) + ] + .spacing(8) + .padding([0, 48]) + .align_items(Alignment::Center); + content = content.push(col); + } + NewConnectionState::Waiting(access_point) => { + let connecting = row![ + icon("network-wireless-symbolic", 24) + .style(Svg::Custom(|theme| svg::Appearance { + color: Some(theme.palette().text), + })) + .width(Length::Units(24)) + .height(Length::Units(24)), + text(format!("{}", fl!("connecting"))) + .size(14) + .width(Length::Fill) + .height(Length::Units(24)) + .horizontal_alignment(Horizontal::Right) + .vertical_alignment(Vertical::Center) + ]; + content = content.push(connecting); + } + NewConnectionState::Failure(access_point) => { + let id = row![ + icon("network-wireless-symbolic", 24) + .style(Svg::Custom(|theme| svg::Appearance { + color: Some(theme.palette().text), + })) + .width(Length::Units(24)) + .height(Length::Units(24)), + text(&access_point.ssid).size(14), + ] + .align_items(Alignment::Center) + .width(Length::Fill) + .padding([0, 24]) + .spacing(8); + content = content.push(id); + let col = column![ + text(fl!("unable-to-connect")), + text(fl!("check-wifi-connection")), + row![ + button(Button::Secondary) + .custom(vec![container(text("Cancel")) + .padding([0, 24]) + .into()]) + .on_press(Message::CancelNewConnection), + button(Button::Secondary) + .custom(vec![container(text("Connect")) + .padding([0, 24]) + .into()]) + .on_press(Message::SelectWirelessAccessPoint( + access_point.clone() + )) + ] + .spacing(24) + ] + .spacing(16) + .padding([0, 48]) + .align_items(Alignment::Center); + content = content.push(col); + } + } + } else if self.wifi { + let mut list_col = column![]; + for ap in &self.wireless_access_points { + if self.active_conns.iter().any(|a| ap.ssid == a.name()) { + continue; + } + let button = button(button_style) + .custom(vec![row![ + icon("network-wireless-symbolic", 16) + .style(Svg::Custom(|theme| svg::Appearance { + color: Some(theme.palette().text), + })) + .width(Length::Units(16)) + .height(Length::Units(16)), + text(&ap.ssid) + .size(14) + .height(Length::Units(24)) + .vertical_alignment(Vertical::Center) + ] + .align_items(Alignment::Center) + .spacing(12) + .into()]) + .on_press(Message::SelectWirelessAccessPoint(ap.clone())) + .width(Length::Fill) + .padding([8, 24]); + list_col = list_col.push(button); + } + content = content.push(scrollable(list_col).height(Length::Units(300))); } - content = content.push(scrollable(list_col).height(Length::Units(300))); } self.applet_helper.popup_container(content).into() } diff --git a/cosmic-applet-network/src/network_manager/current_networks.rs b/cosmic-applet-network/src/network_manager/current_networks.rs index de714af6..a32bf354 100644 --- a/cosmic-applet-network/src/network_manager/current_networks.rs +++ b/cosmic-applet-network/src/network_manager/current_networks.rs @@ -39,6 +39,25 @@ pub async fn active_connections( continue; } for device in connection.devices().await.unwrap_or_default() { + let mut ip_addresses = Vec::new(); + for address_data in connection + .ip4_config() + .await? + .address_data() + .await + .unwrap_or_default() + { + ip_addresses.push(IpAddr::V4(address_data.address)); + } + for address_data in connection + .ip6_config() + .await? + .address_data() + .await + .unwrap_or_default() + { + ip_addresses.push(IpAddr::V6(address_data.address)); + } match device .downcast_to_device() .await @@ -46,25 +65,6 @@ pub async fn active_connections( .and_then(|inner| inner) { Some(SpecificDevice::Wired(wired_device)) => { - let mut ip_addresses = Vec::new(); - for address_data in device - .ip4_config() - .await? - .address_data() - .await - .unwrap_or_default() - { - ip_addresses.push(IpAddr::V4(address_data.address)); - } - for address_data in device - .ip6_config() - .await? - .address_data() - .await - .unwrap_or_default() - { - ip_addresses.push(IpAddr::V6(address_data.address)); - } info.push(ActiveConnectionInfo::Wired { name: connection.id().await?, hw_address: wired_device.hw_address().await?, @@ -76,6 +76,7 @@ pub async fn active_connections( 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, hw_address: wireless_device.hw_address().await?, flags: access_point.flags().await?, rsn_flags: access_point.rsn_flags().await?, @@ -84,25 +85,6 @@ pub async fn active_connections( } } Some(SpecificDevice::WireGuard(_)) => { - let mut ip_addresses = Vec::new(); - for address_data in connection - .ip4_config() - .await? - .address_data() - .await - .unwrap_or_default() - { - ip_addresses.push(IpAddr::V4(address_data.address)); - } - for address_data in connection - .ip6_config() - .await? - .address_data() - .await - .unwrap_or_default() - { - ip_addresses.push(IpAddr::V6(address_data.address)); - } info.push(ActiveConnectionInfo::Vpn { name: connection.id().await?, ip_addresses, @@ -135,6 +117,7 @@ pub enum ActiveConnectionInfo { }, WiFi { name: String, + ip_addresses: Vec, hw_address: String, flags: ApFlags, rsn_flags: ApSecurityFlags, @@ -145,3 +128,13 @@ pub enum ActiveConnectionInfo { ip_addresses: Vec, }, } + +impl ActiveConnectionInfo { + pub fn name(&self) -> String { + match &self { + ActiveConnectionInfo::Wired { name, .. } => name.clone(), + ActiveConnectionInfo::WiFi { name, .. } => name.clone(), + ActiveConnectionInfo::Vpn { name, .. } => name.clone(), + } + } +} From c10087a55d5f6c7bb632bc4ba085043ea7ad2d28 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Sat, 7 Jan 2023 00:21:16 -0500 Subject: [PATCH 02/11] feat: more improvements to network applet --- Cargo.lock | 261 +++++++++++++----- Cargo.toml | 3 - cosmic-applet-network/Cargo.toml | 5 +- cosmic-applet-network/src/app.rs | 141 ++++++---- .../src/network_manager/available_wifi.rs | 20 +- .../src/network_manager/mod.rs | 61 +++- 6 files changed, 363 insertions(+), 128 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 632d1e82..f13c5529 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" [[package]] name = "ab_glyph" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcdbc68024b653943864d436fe8a24b028095bc1cf91a8926f8241e4aaffe59" +checksum = "e5568a4aa5ba8adf5175c5c460b030e27d8893412976cc37bef0e4fbc16cfbba" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -208,9 +208,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "async-trait" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" +checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282" dependencies = [ "proc-macro2", "quote", @@ -551,7 +551,7 @@ dependencies = [ "rust-embed", "smithay-client-toolkit", "tokio", - "zbus", + "zbus 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -560,7 +560,7 @@ version = "0.1.0" dependencies = [ "libcosmic", "smithay-client-toolkit", - "zbus", + "zbus 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -581,7 +581,7 @@ dependencies = [ "slotmap", "smithay-client-toolkit", "tokio", - "zbus", + "zbus 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -605,7 +605,7 @@ dependencies = [ "nix 0.26.1", "smithay-client-toolkit", "tokio", - "zbus", + "zbus 3.7.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", ] [[package]] @@ -655,20 +655,20 @@ dependencies = [ [[package]] name = "cosmic-dbus-networkmanager" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings?branch=deps#af1cc089ec08f4cb37d7d9448523963bf05995c6" +source = "git+https://github.com/pop-os/dbus-settings-bindings?branch=main#5adeb6dc11fd11d26d09ec35c25b93866bb21d31" dependencies = [ "bitflags", "derive_builder", "procfs", "time 0.3.17", - "zbus", - "zvariant 3.9.0", + "zbus 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zvariant 3.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cosmic-panel-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-panel#bab60b3883bd90b71b1be8bdf771fa11be0cf1dc" +source = "git+https://github.com/pop-os/cosmic-panel#b4e60dc30bb798d59cc57957291609e794d38821" dependencies = [ "anyhow", "ron", @@ -1556,6 +1556,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "getrandom" version = "0.2.8" @@ -1996,7 +2006,7 @@ dependencies = [ [[package]] name = "iced" version = "0.6.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "iced_core", "iced_futures", @@ -2004,7 +2014,7 @@ dependencies = [ "iced_graphics", "iced_native", "iced_sctk", - "iced_swbuf", + "iced_softbuffer", "iced_wgpu", "image", "thiserror", @@ -2013,7 +2023,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.6.2" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "bitflags", "palette", @@ -2023,7 +2033,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "futures", "log", @@ -2035,7 +2045,7 @@ dependencies = [ [[package]] name = "iced_glow" version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "bytemuck", "euclid", @@ -2050,7 +2060,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.5.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "bitflags", "bytemuck", @@ -2070,7 +2080,7 @@ dependencies = [ [[package]] name = "iced_lazy" version = "0.3.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "iced_native", "ouroboros 0.13.0", @@ -2079,7 +2089,7 @@ dependencies = [ [[package]] name = "iced_native" version = "0.7.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "iced_core", "iced_futures", @@ -2093,7 +2103,7 @@ dependencies = [ [[package]] name = "iced_sctk" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "enum-repr", "futures", @@ -2110,19 +2120,9 @@ dependencies = [ ] [[package]] -name = "iced_style" -version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" -dependencies = [ - "iced_core", - "once_cell", - "palette", -] - -[[package]] -name = "iced_swbuf" +name = "iced_softbuffer" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "cosmic-text", "iced_graphics", @@ -2134,10 +2134,20 @@ dependencies = [ "softbuffer", ] +[[package]] +name = "iced_style" +version = "0.5.1" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" +dependencies = [ + "iced_core", + "once_cell", + "palette", +] + [[package]] name = "iced_wgpu" version = "0.7.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "bitflags", "bytemuck", @@ -2327,7 +2337,7 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#357de5e9be4110fa3762cd7ec057760353505620" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5224c9b75c000fcf92a1851391fe1dc82486610a" dependencies = [ "apply", "cosmic-panel-config", @@ -2470,7 +2480,7 @@ version = "3.0.3" source = "git+https://github.com/pop-os/logind-zbus?branch=main#0789bde15b61b3f65b1e028841eeb5411f66f474" dependencies = [ "serde", - "zbus", + "zbus 3.7.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", ] [[package]] @@ -2841,11 +2851,11 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.17.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18904d3c65493a9f0d7542293d1a7f69bfdc309a6b9ef4f46dc3e58b0577edc5" +checksum = "2a5f3c7ca08b6879e7965fb25e24d1f5eeb32ea73f9ad99b3854778a38c57e93" dependencies = [ - "ttf-parser 0.17.1", + "ttf-parser 0.18.0", ] [[package]] @@ -3690,12 +3700,17 @@ dependencies = [ [[package]] name = "softbuffer" -version = "0.1.1" -source = "git+https://github.com/rust-windowing/softbuffer?rev=d5bb2c1#d5bb2c1c78811854d11225ff7cc29f0062781333" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3177eca2c15033e254b9b70c4915150200b1cf6fa777de18be9977ae5850077f" dependencies = [ + "bytemuck", + "cfg_aliases", "cocoa", "core-graphics", + "fastrand", "foreign-types", + "log", "nix 0.26.1", "objc", "raw-window-handle", @@ -3708,6 +3723,7 @@ dependencies = [ "web-sys", "windows-sys 0.42.0", "x11-dl", + "x11rb", ] [[package]] @@ -3952,9 +3968,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.23.1" +version = "1.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38a54aca0c15d014013256222ba0ebed095673f89345dd79119d912eb561b7a8" +checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae" dependencies = [ "autocfg", "bytes", @@ -4035,6 +4051,12 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff" +[[package]] +name = "ttf-parser" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf554b6e535f9a160b2ed4ea83f99000f21cbc0a693df26e258eaf2c226a151" + [[package]] name = "twox-hash" version = "1.6.3" @@ -4598,6 +4620,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "winapi-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -4715,6 +4746,31 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "x11rb" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf3c79412dd91bae7a7366b8ad1565a85e35dd049affc3a6a2c549e97419617" +dependencies = [ + "gethostname", + "libc", + "libloading", + "nix 0.25.1", + "once_cell", + "winapi", + "winapi-wsapoll", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0b1513b141123073ce54d5bb1d33f801f17508fbd61e02060b1214e96d39c56" +dependencies = [ + "nix 0.25.1", +] + [[package]] name = "xcursor" version = "0.3.4" @@ -4736,7 +4792,7 @@ dependencies = [ [[package]] name = "xdg-shell-wrapper-config" version = "0.1.0" -source = "git+https://github.com/pop-os/xdg-shell-wrapper#82ce268c9c560be3728190a2255c849d3bae77e7" +source = "git+https://github.com/pop-os/xdg-shell-wrapper#95f6a663e383d3f6f13f689f9e9d7e691b9fe28b" dependencies = [ "serde", "wayland-protocols-wlr", @@ -4784,8 +4840,9 @@ checksum = "c03b3e19c937b5b9bd8e52b1c88f30cce5c0d33d676cf174866175bb794ff658" [[package]] name = "zbus" -version = "3.6.2" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#0b623738048395cdf398c18be24c9f00d8fdab58" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "379d587c0ccb632d1179cf44082653f682842f0535f0fdfaefffc34849cc855e" dependencies = [ "async-broadcast", "async-executor", @@ -4816,15 +4873,65 @@ dependencies = [ "tracing", "uds_windows", "winapi", - "zbus_macros", - "zbus_names", - "zvariant 3.10.0", + "zbus_macros 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zbus_names 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zvariant 3.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zbus" +version = "3.7.0" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", + "byteorder", + "derivative", + "dirs 4.0.0", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.25.1", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "zbus_macros 3.7.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", + "zbus_names 2.5.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", + "zvariant 3.10.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", ] [[package]] name = "zbus_macros" -version = "3.6.2" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#0b623738048395cdf398c18be24c9f00d8fdab58" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66492a2e90c0df7190583eccb8424aa12eb7ff06edea415a4fff6688fae18cf8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "zbus_macros" +version = "3.7.0" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4836,11 +4943,22 @@ dependencies = [ [[package]] name = "zbus_names" version = "2.5.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#0b623738048395cdf398c18be24c9f00d8fdab58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f34f314916bd89bdb9934154627fab152f4f28acdda03e7c4c68181b214fe7e3" dependencies = [ "serde", "static_assertions", - "zvariant 3.10.0", + "zvariant 3.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zbus_names" +version = "2.5.0" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" +dependencies = [ + "serde", + "static_assertions", + "zvariant 3.10.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", ] [[package]] @@ -4849,37 +4967,38 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c110ba09c9b3a43edd4803d570df0da2414fed6e822e22b976a4e3ef50860701" -[[package]] -name = "zvariant" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f8c89c183461e11867ded456db252eae90874bc6769b7adbea464caa777e51" -dependencies = [ - "byteorder", - "libc", - "serde", - "static_assertions", - "zvariant_derive 3.9.0", -] - [[package]] name = "zvariant" version = "3.10.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#0b623738048395cdf398c18be24c9f00d8fdab58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576cc41e65c7f283e5460f5818073e68fb1f1631502b969ef228c2e03c862efb" dependencies = [ "byteorder", "enumflags2", "libc", "serde", "static_assertions", - "zvariant_derive 3.10.0", + "zvariant_derive 3.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zvariant" +version = "3.10.0" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive 3.10.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", ] [[package]] name = "zvariant_derive" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "155247a5d1ab55e335421c104ccd95d64f17cebbd02f50cdbc1c33385f9c4d81" +checksum = "0fd4aafc0dee96ae7242a24249ce9babf21e1562822f03df650d4e68c20e41ed" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4890,7 +5009,7 @@ dependencies = [ [[package]] name = "zvariant_derive" version = "3.10.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#0b623738048395cdf398c18be24c9f00d8fdab58" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 98eaaa3b..5d506a12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,5 @@ members = [ "cosmic-applet-workspaces", ] -[patch.crates-io] -zbus = {git = "https://gitlab.freedesktop.org/dbus/zbus", branch = "main"} - [profile.release] lto = "fat" diff --git a/cosmic-applet-network/Cargo.toml b/cosmic-applet-network/Cargo.toml index a1b75f8e..7b610e40 100644 --- a/cosmic-applet-network/Cargo.toml +++ b/cosmic-applet-network/Cargo.toml @@ -6,12 +6,13 @@ license = "GPL-3.0-or-later" [dependencies] once_cell = "1.16.0" -cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", branch = "deps" } +cosmic-dbus-networkmanager = { git = "https://github.com/pop-os/dbus-settings-bindings", branch = "main" } +# cosmic-dbus-networkmanager = { path = "../../../dbus-settings-bindings/networkmanager" } futures-util = "0.3.21" libcosmic = { git = "https://github.com/pop-os/libcosmic/", branch = "master", default-features = false, features = ["wayland", "applet", "tokio"] } sctk = { package = "smithay-client-toolkit", git = "https://github.com/Smithay/client-toolkit", rev = "3776d4a" } futures = "0.3" -zbus = { version = "3.6.2", no-default-features = true } +zbus = { version = "3.7", no-default-features = true } log = "0.4" pretty_env_logger = "0.4" # Application i18n diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index b81506d7..bd4c13a5 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -30,7 +30,7 @@ use cosmic::{ }, }, }; -use cosmic_dbus_networkmanager::access_point; +use cosmic_dbus_networkmanager::{access_point, interface::enums::DeviceState}; use futures::channel::mpsc::UnboundedSender; use crate::{ @@ -80,6 +80,7 @@ struct CosmicNetworkApplet { wifi: bool, wireless_access_points: Vec, active_conns: Vec, + known_access_points: Vec, nm_sender: Option>, show_visible_networks: bool, new_connection: Option, @@ -109,6 +110,7 @@ impl CosmicNetworkApplet { #[derive(Debug, Clone)] enum Message { + ActivateKnownWifi(String), TogglePopup, ToggleAirplaneMode(bool), ToggleWiFi(bool), @@ -185,6 +187,7 @@ impl Application for CosmicNetworkApplet { sender, wireless_access_points, active_conns, + known_access_points, wifi_enabled, airplane_mode, } => { @@ -194,6 +197,7 @@ impl Application for CosmicNetworkApplet { self.wifi = wifi_enabled; self.airplane_mode = airplane_mode; self.update_icon_name(); + self.known_access_points = known_access_points; } NetworkManagerEvent::WiFiEnabled(enabled) => { self.wifi = enabled; @@ -222,11 +226,6 @@ impl Application for CosmicNetworkApplet { } }, Message::SelectWirelessAccessPoint(access_point) => { - // if let Some(tx) = self.nm_sender.as_ref() { - // let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint( - // access_point.ssid.clone(), - // )); - // } self.new_connection .replace(NewConnectionState::EnterPassword { access_point, @@ -237,26 +236,28 @@ impl Application for CosmicNetworkApplet { self.new_connection.take(); self.show_visible_networks = !self.show_visible_networks; } - Message::Password(entered_pw) => { - dbg!(&entered_pw); - - match &mut self.new_connection { - Some(NewConnectionState::EnterPassword { password, .. }) => { - *password = entered_pw; - } - _ => {} + Message::Password(entered_pw) => match &mut self.new_connection { + Some(NewConnectionState::EnterPassword { password, .. }) => { + *password = entered_pw; } - } + _ => {} + }, Message::SubmitPassword => { // TODO setup connection match self.new_connection.take() { Some(new_connection) => { - self.new_connection - .replace(NewConnectionState::Failure(new_connection.into())); + let ap: AccessPoint = new_connection.into(); + if let Some(tx) = self.nm_sender.as_ref() { + let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint( + ap.ssid.clone(), + )); + } + self.new_connection.replace(NewConnectionState::Failure(ap)); } None => {} } } + Message::ActivateKnownWifi(ssid) => {} Message::CancelNewConnection => { self.new_connection.take(); } @@ -282,9 +283,10 @@ impl Application for CosmicNetworkApplet { .on_press(Message::TogglePopup) .into(), SurfaceIdWrapper::Popup(_) => { - let mut list_col = column![]; + let mut vpn_ethernet_col = column![]; + let mut known_wifi = column![]; for conn in &self.active_conns { - let el = match conn { + match conn { ActiveConnectionInfo::Vpn { name, ip_addresses } => { let mut ipv4 = column![]; for addr in ip_addresses { @@ -295,10 +297,11 @@ impl Application for CosmicNetworkApplet { .size(12), ); } - std::net::IpAddr::V6(a) => {} + std::net::IpAddr::V6(_) => {} } } - column![text(name), ipv4].spacing(4) + vpn_ethernet_col = + vpn_ethernet_col.push(column![text(name), ipv4].spacing(4)); } ActiveConnectionInfo::Wired { name, @@ -318,15 +321,17 @@ impl Application for CosmicNetworkApplet { std::net::IpAddr::V6(a) => {} } } - column![ - row![ - text(name), - text(format!("{speed} {}", fl!("megabits-per-second"))) + vpn_ethernet_col = vpn_ethernet_col.push( + column![ + row![ + text(name), + text(format!("{speed} {}", fl!("megabits-per-second"))) + ] + .spacing(16), + ipv4, ] - .spacing(16), - ipv4, - ] - .spacing(4) + .spacing(4), + ); } ActiveConnectionInfo::WiFi { name, ip_addresses, .. @@ -340,10 +345,10 @@ impl Application for CosmicNetworkApplet { .size(12), ); } - std::net::IpAddr::V6(a) => {} + std::net::IpAddr::V6(_) => {} } } - column![button(Button::Secondary) + known_wifi = known_wifi.push(column![button(Button::Secondary) .custom(vec![ icon("network-wireless-symbolic", 24) .style(Svg::Custom(|theme| svg::Appearance { @@ -362,14 +367,46 @@ impl Application for CosmicNetworkApplet { .into() ]) .padding([8, 24]) - .style(button_style.clone()) - .on_press(Message::Ignore)] + .style(button_style.clone())]); } }; - list_col = list_col.push(el); + } + for known in &self.known_access_points { + let mut btn = button(Button::Secondary) + .custom(vec![ + icon("network-wireless-symbolic", 24) + .style(Svg::Custom(|theme| svg::Appearance { + color: Some(theme.palette().text), + })) + .width(Length::Units(24)) + .height(Length::Units(24)) + .into(), + text(&known.ssid).size(14).into(), + ]) + .padding([8, 24]) + .width(Length::Fill) + .style(button_style.clone()); + let btn = match known.state { + // DeviceState::Prepare => todo!(), + // DeviceState::Config => todo!(), + // DeviceState::NeedAuth => todo!(), + // DeviceState::IpConfig => todo!(), + // DeviceState::IpCheck => todo!(), + // DeviceState::Secondaries => todo!(), + DeviceState::Failed + | DeviceState::Unknown + | DeviceState::Unmanaged + | DeviceState::Disconnected + | DeviceState::NeedAuth => { + btn.on_press(Message::ActivateKnownWifi(known.ssid.clone())) + } + _ => btn, + }; + known_wifi = known_wifi.push(row![btn].align_items(Alignment::Center)); } let mut content = column![ + vpn_ethernet_col, container( toggler(fl!("airplane-mode"), self.airplane_mode, |m| { Message::ToggleAirplaneMode(m) @@ -384,7 +421,7 @@ impl Application for CosmicNetworkApplet { ) .padding([0, 12]), horizontal_rule(1), - list_col, + known_wifi, ] .align_items(Alignment::Center) .spacing(8) @@ -456,11 +493,11 @@ impl Application for CosmicNetworkApplet { .padding([0, 24]) .into()]) .on_press(Message::CancelNewConnection), - button(Button::Secondary).custom(vec![container(text( - fl!("connect") - )) - .padding([0, 24]) - .into()]) + button(Button::Secondary) + .custom(vec![container(text(fl!("connect"))) + .padding([0, 24]) + .into()]) + .on_press(Message::SubmitPassword) ] .spacing(24) ] @@ -470,19 +507,27 @@ impl Application for CosmicNetworkApplet { content = content.push(col); } NewConnectionState::Waiting(access_point) => { - let connecting = row![ + let id = row![ icon("network-wireless-symbolic", 24) .style(Svg::Custom(|theme| svg::Appearance { color: Some(theme.palette().text), })) .width(Length::Units(24)) .height(Length::Units(24)), - text(format!("{}", fl!("connecting"))) - .size(14) - .width(Length::Fill) - .height(Length::Units(24)) - .horizontal_alignment(Horizontal::Right) - .vertical_alignment(Vertical::Center) + text(&access_point.ssid).size(14), + ] + .align_items(Alignment::Center) + .width(Length::Fill) + .padding([0, 24]) + .spacing(12); + let connecting = row![ + id, + icon("process-working-symbolic", 24) + .style(Svg::Custom(|theme| svg::Appearance { + color: Some(theme.palette().text), + })) + .width(Length::Units(24)) + .height(Length::Units(24)), ]; content = content.push(connecting); } @@ -499,7 +544,7 @@ impl Application for CosmicNetworkApplet { .align_items(Alignment::Center) .width(Length::Fill) .padding([0, 24]) - .spacing(8); + .spacing(12); content = content.push(id); let col = column![ text(fl!("unable-to-connect")), diff --git a/cosmic-applet-network/src/network_manager/available_wifi.rs b/cosmic-applet-network/src/network_manager/available_wifi.rs index d1018822..7f9f5c83 100644 --- a/cosmic-applet-network/src/network_manager/available_wifi.rs +++ b/cosmic-applet-network/src/network_manager/available_wifi.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later -use cosmic_dbus_networkmanager::device::wireless::WirelessDevice; +use cosmic_dbus_networkmanager::{device::wireless::WirelessDevice, interface::enums::DeviceState}; use futures_util::StreamExt; use itertools::Itertools; @@ -16,17 +16,32 @@ pub async fn handle_wireless_device(device: WirelessDevice<'_>) -> zbus::Result< } } let access_points = device.get_access_points().await?; + let state: DeviceState = device + .upcast() + .await + .and_then(|dev| dev.cached_state()) + .unwrap_or_default() + .map(|s| s.into()) + .unwrap_or_else(|| DeviceState::Unknown); // Sort by strength and remove duplicates let mut aps = HashMap::::new(); for ap in access_points { let ssid = String::from_utf8_lossy(&ap.ssid().await?.clone()).into_owned(); let strength = ap.strength().await?; + if let Some(access_point) = aps.get(&ssid) { if access_point.strength > strength { continue; } } - aps.insert(ssid.clone(), AccessPoint { ssid, strength }); + aps.insert( + ssid.clone(), + AccessPoint { + ssid, + strength, + state: state, + }, + ); } let aps = aps .into_iter() @@ -40,4 +55,5 @@ pub async fn handle_wireless_device(device: WirelessDevice<'_>) -> zbus::Result< pub struct AccessPoint { pub ssid: String, pub strength: u8, + pub state: DeviceState, } diff --git a/cosmic-applet-network/src/network_manager/mod.rs b/cosmic-applet-network/src/network_manager/mod.rs index 615467f3..5d0c8951 100644 --- a/cosmic-applet-network/src/network_manager/mod.rs +++ b/cosmic-applet-network/src/network_manager/mod.rs @@ -5,10 +5,17 @@ use std::{fmt::Debug, hash::Hash, time::Duration}; use cosmic::iced::{self, subscription}; use cosmic_dbus_networkmanager::{ - device::SpecificDevice, interface::enums::DeviceType, nm::NetworkManager, + device::SpecificDevice, + interface::{enums::DeviceType, settings::connection::ConnectionSettingsProxy}, + nm::NetworkManager, + settings::{ + connection::{ConnectionSettings, Secrets, Settings}, + NetworkManagerSettings, + }, }; use futures::{ channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, + future::ok, FutureExt, StreamExt, }; use zbus::Connection; @@ -49,6 +56,12 @@ async fn start_listening( Ok(n) => n, Err(_) => return (None, State::Finished), }; + let s = match NetworkManagerSettings::new(&conn).await { + Ok(s) => s, + Err(_) => return (None, State::Finished), + }; + let known_conns = s.list_connections().await.unwrap_or_default(); + let (tx, rx) = unbounded(); let mut active_conns = active_connections( network_manager @@ -85,8 +98,30 @@ async fn start_listening( let mut wireless_access_points = Vec::with_capacity(wireless_access_point_futures.len()); for f in wireless_access_point_futures { - wireless_access_points.append(&mut f.await); + let mut access_points = f.await; + wireless_access_points.append(&mut access_points); } + let mut known_ssid = Vec::with_capacity(known_conns.len()); + for c in known_conns { + let s = c.get_settings().await.unwrap(); + let s = Settings::new(s); + if let Some(cur_ssid) = s + .wifi + .clone() + .and_then(|w| w.ssid) + .and_then(|ssid| String::from_utf8(ssid).ok()) + { + known_ssid.push(cur_ssid); + } + } + let known_access_points: Vec<_> = wireless_access_points + .iter() + .filter(|a| { + known_ssid.contains(&a.ssid) + && !active_conns.iter().any(|ac| ac.name() == a.ssid) + }) + .cloned() + .collect(); wireless_access_points.sort_by(|a, b| b.strength.cmp(&a.strength)); drop(network_manager); return ( @@ -97,6 +132,7 @@ async fn start_listening( wireless_access_points, wifi_enabled, airplane_mode: false, + known_access_points, active_conns, }, )), @@ -108,6 +144,7 @@ async fn start_listening( Ok(n) => n, Err(_) => return (None, State::Finished), }; + let mut active_conns_changed = tokio::time::sleep(Duration::from_secs(5)) .then(|_| async { network_manager.receive_active_connections_changed().await }) .await; @@ -153,7 +190,26 @@ async fn start_listening( Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => { 'device_loop: for device in network_manager.devices().await.ok().unwrap_or_default() { if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) { + let connection_settings = NetworkManagerSettings::new(&conn).await.unwrap(); + for conn in connection_settings.list_connections().await.unwrap() { + let s = conn.get_settings().await.unwrap(); + let s = Settings::new(s); + + let cur_ssid = s + .wifi + .clone() + .and_then(|w| w.ssid) + .and_then(|ssid| String::from_utf8(ssid).ok()); + if cur_ssid.as_ref() == Some(&ssid) { + // dbg!(s); + // dbg!(conn.get_secrets("connection").await); + // dbg!(Secrets::new(&conn).await); + // dbg!(psk); + // connection update can be used to set password + } + } for conn in device.available_connections().await.unwrap_or_default() { + // network_manager.activate_connection(conn, device.clone()); // dbg!(&conn.path()); // TODO activate connection } @@ -225,6 +281,7 @@ pub enum NetworkManagerEvent { sender: UnboundedSender, wireless_access_points: Vec, active_conns: Vec, + known_access_points: Vec, wifi_enabled: bool, airplane_mode: bool, }, From 833e68d63b54a2dc9865d21a6f107b6b17801414 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 9 Jan 2023 15:04:36 -0500 Subject: [PATCH 03/11] refactor: simplify state updates from network manager subscription --- cosmic-applet-network/Cargo.toml | 7 +- cosmic-applet-network/src/app.rs | 75 ++-- .../src/network_manager/mod.rs | 322 ++++++++++-------- 3 files changed, 230 insertions(+), 174 deletions(-) diff --git a/cosmic-applet-network/Cargo.toml b/cosmic-applet-network/Cargo.toml index 7b610e40..52278aed 100644 --- a/cosmic-applet-network/Cargo.toml +++ b/cosmic-applet-network/Cargo.toml @@ -15,10 +15,11 @@ futures = "0.3" zbus = { version = "3.7", no-default-features = true } log = "0.4" pretty_env_logger = "0.4" +itertools = "0.10.3" +slotmap = "1.0.6" +tokio = { version = "1.15.0", features = ["full"] } +anyhow = "1.0" # Application i18n i18n-embed = { version = "0.13.4", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.6.4" rust-embed = "6.3.0" -itertools = "0.10.3" -slotmap = "1.0.6" -tokio = { version = "1.15.0", features = ["full"] } diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index bd4c13a5..a9adde1d 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -1,3 +1,4 @@ +use cosmic::iced_style; use cosmic::{ applet::CosmicAppletHelper, iced::{ @@ -20,19 +21,10 @@ use cosmic::{ widget::{button, horizontal_rule, icon, list_column, toggler}, Element, Theme, }; -use cosmic::{ - iced_style, - widget::segmented_button::{ - self, - cosmic::{ - horizontal_segmented_selection, horizontal_view_switcher, vertical_segmented_selection, - vertical_view_switcher, - }, - }, -}; use cosmic_dbus_networkmanager::{access_point, interface::enums::DeviceState}; use futures::channel::mpsc::UnboundedSender; +use crate::network_manager::NetworkManagerState; use crate::{ config, fl, network_manager::{ @@ -174,7 +166,9 @@ impl Application for CosmicNetworkApplet { Message::Ignore => {} Message::ToggleAirplaneMode(enabled) => { self.airplane_mode = enabled; - // TODO apply changes + if let Some(tx) = self.nm_sender.as_mut() { + let _ = tx.unbounded_send(NetworkManagerRequest::SetAirplaneMode(enabled)); + } } Message::ToggleWiFi(enabled) => { self.wifi = enabled; @@ -185,11 +179,14 @@ impl Application for CosmicNetworkApplet { Message::NetworkManagerEvent(event) => match event { NetworkManagerEvent::Init { sender, - wireless_access_points, - active_conns, - known_access_points, - wifi_enabled, - airplane_mode, + state: + NetworkManagerState { + wireless_access_points, + active_conns, + known_access_points, + wifi_enabled, + airplane_mode, + }, } => { self.nm_sender.replace(sender); self.wireless_access_points = wireless_access_points; @@ -210,16 +207,22 @@ impl Application for CosmicNetworkApplet { self.update_icon_name(); } NetworkManagerEvent::RequestResponse { - wireless_access_points, - active_conns, - wifi_enabled, + state: + NetworkManagerState { + wireless_access_points, + active_conns, + known_access_points, + wifi_enabled, + airplane_mode, + }, success, .. } => { if success { self.wireless_access_points = wireless_access_points; self.active_conns = active_conns; - + self.known_access_points = known_access_points; + self.airplane_mode = airplane_mode; self.wifi = wifi_enabled; self.update_icon_name(); } @@ -243,19 +246,27 @@ impl Application for CosmicNetworkApplet { _ => {} }, Message::SubmitPassword => { - // TODO setup connection + // save password + let tx = if let Some(tx) = self.nm_sender.as_ref() { + tx + } else { + return Command::none(); + }; + match self.new_connection.take() { - Some(new_connection) => { - let ap: AccessPoint = new_connection.into(); - if let Some(tx) = self.nm_sender.as_ref() { - let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint( - ap.ssid.clone(), - )); - } - self.new_connection.replace(NewConnectionState::Failure(ap)); + Some(NewConnectionState::EnterPassword { + password, + access_point, + }) => { + let _ = tx.unbounded_send(NetworkManagerRequest::Password( + access_point.ssid.clone(), + password.to_string(), + )); + self.new_connection + .replace(NewConnectionState::Failure(access_point.clone())); } - None => {} - } + _ => {} + }; } Message::ActivateKnownWifi(ssid) => {} Message::CancelNewConnection => { @@ -386,7 +397,7 @@ impl Application for CosmicNetworkApplet { .padding([8, 24]) .width(Length::Fill) .style(button_style.clone()); - let btn = match known.state { + btn = match known.state { // DeviceState::Prepare => todo!(), // DeviceState::Config => todo!(), // DeviceState::NeedAuth => todo!(), diff --git a/cosmic-applet-network/src/network_manager/mod.rs b/cosmic-applet-network/src/network_manager/mod.rs index 5d0c8951..d3521b2f 100644 --- a/cosmic-applet-network/src/network_manager/mod.rs +++ b/cosmic-applet-network/src/network_manager/mod.rs @@ -1,13 +1,13 @@ pub mod available_wifi; pub mod current_networks; -use std::{fmt::Debug, hash::Hash, time::Duration}; +use std::{collections::HashMap, fmt::Debug, hash::Hash, time::Duration}; use cosmic::iced::{self, subscription}; use cosmic_dbus_networkmanager::{ device::SpecificDevice, interface::{enums::DeviceType, settings::connection::ConnectionSettingsProxy}, - nm::NetworkManager, + nm::{self, NetworkManager}, settings::{ connection::{ConnectionSettings, Secrets, Settings}, NetworkManagerSettings, @@ -18,7 +18,11 @@ use futures::{ future::ok, FutureExt, StreamExt, }; -use zbus::Connection; +use tokio::process::Command; +use zbus::{ + zvariant::{self, Value}, + Connection, +}; use self::{ available_wifi::{handle_wireless_device, AccessPoint}, @@ -52,88 +56,15 @@ async fn start_listening( Ok(c) => c, Err(_) => return (None, State::Finished), }; - let network_manager = match NetworkManager::new(&conn).await { - Ok(n) => n, - Err(_) => return (None, State::Finished), - }; - let s = match NetworkManagerSettings::new(&conn).await { - Ok(s) => s, - Err(_) => return (None, State::Finished), - }; - let known_conns = s.list_connections().await.unwrap_or_default(); let (tx, rx) = unbounded(); - let mut active_conns = active_connections( - network_manager - .active_connections() - .await - .unwrap_or_default(), - ) - .await - .unwrap_or_default(); - active_conns.sort_by(|a, b| { - let helper = |conn: &ActiveConnectionInfo| match conn { - ActiveConnectionInfo::Vpn { name, .. } => format!("0{name}"), - ActiveConnectionInfo::Wired { name, .. } => format!("1{name}"), - ActiveConnectionInfo::WiFi { name, .. } => format!("2{name}"), - }; - helper(a).cmp(&helper(b)) - }); - let wifi_enabled = network_manager.wireless_enabled().await.unwrap_or_default(); - let devices = network_manager.devices().await.ok().unwrap_or_default(); - let wireless_access_point_futures: Vec<_> = devices - .into_iter() - .map(|device| async move { - if let Ok(Some(SpecificDevice::Wireless(wireless_device))) = - device.downcast_to_device().await - { - handle_wireless_device(wireless_device) - .await - .unwrap_or_default() - } else { - Vec::new() - } - }) - .collect(); - let mut wireless_access_points = - Vec::with_capacity(wireless_access_point_futures.len()); - for f in wireless_access_point_futures { - let mut access_points = f.await; - wireless_access_points.append(&mut access_points); - } - let mut known_ssid = Vec::with_capacity(known_conns.len()); - for c in known_conns { - let s = c.get_settings().await.unwrap(); - let s = Settings::new(s); - if let Some(cur_ssid) = s - .wifi - .clone() - .and_then(|w| w.ssid) - .and_then(|ssid| String::from_utf8(ssid).ok()) - { - known_ssid.push(cur_ssid); - } - } - let known_access_points: Vec<_> = wireless_access_points - .iter() - .filter(|a| { - known_ssid.contains(&a.ssid) - && !active_conns.iter().any(|ac| ac.name() == a.ssid) - }) - .cloned() - .collect(); - wireless_access_points.sort_by(|a, b| b.strength.cmp(&a.strength)); - drop(network_manager); + let nm_state = NetworkManagerState::new(&conn).await.unwrap_or_default(); return ( Some(( id, NetworkManagerEvent::Init { sender: tx, - wireless_access_points, - wifi_enabled, - airplane_mode: false, - known_access_points, - active_conns, + state: nm_state, }, )), State::Waiting(conn, rx), @@ -156,63 +87,83 @@ async fn start_listening( let (update, should_exit) = futures::select! { req = req => { match req { - Some(NetworkManagerRequest::SetAirplaneMode(state)) => { - // TODO set airplane mode - let _ = network_manager.set_wireless_enabled(state).await; - (None, false) + Some(NetworkManagerRequest::SetAirplaneMode(airplane_mode)) => { + // wifi + let mut success = network_manager.set_wireless_enabled(!airplane_mode).await.is_ok(); + // bluetooth + success = success && Command::new("rfkill") + .arg(if airplane_mode { "block" } else { "unblock" }) + .arg("bluetooth") + .output() + .await + .is_ok(); + let response = NetworkManagerEvent::RequestResponse { + req: NetworkManagerRequest::SetAirplaneMode(airplane_mode), + success: true, + state: NetworkManagerState::new(&conn).await.unwrap_or_default(), + }; + (Some((id, response)), false) } Some(NetworkManagerRequest::SetWiFi(enabled)) => { let success = network_manager.set_wireless_enabled(enabled).await.is_ok(); - let active_conns = active_connections(network_manager.active_connections().await.unwrap_or_default()).await.unwrap_or_default(); - let devices = network_manager.devices().await.ok().unwrap_or_default(); - let wireless_access_point_futures: Vec<_> = devices.into_iter().map(|device| async move { - if let Ok(Some(SpecificDevice::Wireless(wireless_device))) = - device.downcast_to_device().await - { - handle_wireless_device(wireless_device).await.unwrap_or_default() - } else { - Vec::new() - } - }).collect(); - let mut wireless_access_points = Vec::with_capacity(wireless_access_point_futures.len()); - for f in wireless_access_point_futures { - wireless_access_points.append(&mut f.await); - } - (Some((id, NetworkManagerEvent::RequestResponse { - req: NetworkManagerRequest::SetWiFi(enabled), + let response = NetworkManagerEvent::RequestResponse { + req: NetworkManagerRequest::SetAirplaneMode(enabled), success, - active_conns, - wireless_access_points, - wifi_enabled: enabled, - airplane_mode: false, - })), false) + state: NetworkManagerState::new(&conn).await.unwrap_or_default(), + }; + (Some((id, response)), false) + } + Some(NetworkManagerRequest::Password(ssid, password)) => { + let s = match NetworkManagerSettings::new(&conn).await { + Ok(s) => s, + Err(_) => return (None, State::Finished), + }; + + // TODO more convenient methods of managing settings + for c in s.list_connections().await.unwrap_or_default() { + let mut settings = match c.get_settings().await.ok() { + Some(s) => s, + None => continue, + }; + dbg!(&settings); + let cur_ssid = settings + .get("802-11-wireless") + .and_then(|w| w.get("ssid")) + .cloned() + .and_then(|ssid| ssid.try_into().ok()) + .and_then(|ssid| String::from_utf8(ssid).ok()); + dbg!(&cur_ssid); + if cur_ssid.as_ref() != Some(&ssid) { + break; + } + + let mut secrets = match + c.get_secrets("802-11-wireless-security") + .await { + Ok(s) => s, + _ => continue, + }; + if let Some(s) = secrets.get_mut("802-11-wireless-security") { + s.insert("psk".into(), Value::Str(password.into()).to_owned()); + drop(s); + settings.extend(secrets.into_iter()); + let settings: HashMap<_, _> = settings.iter().map(|(k, v)| { + let map = (k.as_str(), v.iter() + .map(|(k, v)| (k.as_str(), v.into())) + .collect::>()); + map + }).collect(); + dbg!(settings.clone()); + dbg!(c.update(settings).await); + break; + } + } + + (None, false) } Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => { 'device_loop: for device in network_manager.devices().await.ok().unwrap_or_default() { if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) { - let connection_settings = NetworkManagerSettings::new(&conn).await.unwrap(); - for conn in connection_settings.list_connections().await.unwrap() { - let s = conn.get_settings().await.unwrap(); - let s = Settings::new(s); - - let cur_ssid = s - .wifi - .clone() - .and_then(|w| w.ssid) - .and_then(|ssid| String::from_utf8(ssid).ok()); - if cur_ssid.as_ref() == Some(&ssid) { - // dbg!(s); - // dbg!(conn.get_secrets("connection").await); - // dbg!(Secrets::new(&conn).await); - // dbg!(psk); - // connection update can be used to set password - } - } - for conn in device.available_connections().await.unwrap_or_default() { - // network_manager.activate_connection(conn, device.clone()); - // dbg!(&conn.path()); - // TODO activate connection - } } } (None, false) @@ -273,27 +224,120 @@ pub enum NetworkManagerRequest { SetAirplaneMode(bool), SetWiFi(bool), SelectAccessPoint(String), + Password(String, String), } #[derive(Debug, Clone)] pub enum NetworkManagerEvent { - Init { - sender: UnboundedSender, - wireless_access_points: Vec, - active_conns: Vec, - known_access_points: Vec, - wifi_enabled: bool, - airplane_mode: bool, - }, RequestResponse { req: NetworkManagerRequest, - wireless_access_points: Vec, - active_conns: Vec, - wifi_enabled: bool, - airplane_mode: bool, + state: NetworkManagerState, success: bool, }, + Init { + sender: UnboundedSender, + state: NetworkManagerState, + }, WiFiEnabled(bool), WirelessAccessPoints(Vec), ActiveConns(Vec), } + +#[derive(Debug, Clone, Default)] +pub struct NetworkManagerState { + pub wireless_access_points: Vec, + pub active_conns: Vec, + pub known_access_points: Vec, + pub wifi_enabled: bool, + pub airplane_mode: bool, +} + +impl NetworkManagerState { + pub async fn new(conn: &Connection) -> anyhow::Result { + let network_manager = NetworkManager::new(&conn).await?; + let mut _self = Self::default(); + + // airplane mode + let airplaine_mode = Command::new("rfkill") + .arg("list") + .arg("bluetooth") + .output() + .await?; + let airplane_mode = std::str::from_utf8(&airplaine_mode.stdout).unwrap_or_default(); + let bluetooth_disabled = airplane_mode.contains("Soft blocked: yes"); + + if !network_manager.wireless_enabled().await.unwrap_or_default() { + _self.airplane_mode = bluetooth_disabled; + return Ok(_self); + } else { + _self.wifi_enabled = true; + }; + + let s = NetworkManagerSettings::new(&conn).await?; + + let known_conns = s.list_connections().await.unwrap_or_default(); + + let mut active_conns = active_connections( + network_manager + .active_connections() + .await + .unwrap_or_default(), + ) + .await + .unwrap_or_default(); + active_conns.sort_by(|a, b| { + let helper = |conn: &ActiveConnectionInfo| match conn { + ActiveConnectionInfo::Vpn { name, .. } => format!("0{name}"), + ActiveConnectionInfo::Wired { name, .. } => format!("1{name}"), + ActiveConnectionInfo::WiFi { name, .. } => format!("2{name}"), + }; + helper(a).cmp(&helper(b)) + }); + let devices = network_manager.devices().await.ok().unwrap_or_default(); + let wireless_access_point_futures: Vec<_> = devices + .into_iter() + .map(|device| async move { + if let Ok(Some(SpecificDevice::Wireless(wireless_device))) = + device.downcast_to_device().await + { + handle_wireless_device(wireless_device) + .await + .unwrap_or_default() + } else { + Vec::new() + } + }) + .collect(); + let mut wireless_access_points = Vec::with_capacity(wireless_access_point_futures.len()); + for f in wireless_access_point_futures { + let mut access_points = f.await; + wireless_access_points.append(&mut access_points); + } + let mut known_ssid = Vec::with_capacity(known_conns.len()); + for c in known_conns { + let s = c.get_settings().await.unwrap(); + let s = Settings::new(s); + if let Some(cur_ssid) = s + .wifi + .clone() + .and_then(|w| w.ssid) + .and_then(|ssid| String::from_utf8(ssid).ok()) + { + known_ssid.push(cur_ssid); + } + } + let known_access_points: Vec<_> = wireless_access_points + .iter() + .filter(|a| { + known_ssid.contains(&a.ssid) && !active_conns.iter().any(|ac| ac.name() == a.ssid) + }) + .cloned() + .collect(); + wireless_access_points.sort_by(|a, b| b.strength.cmp(&a.strength)); + + _self.wireless_access_points = wireless_access_points; + _self.active_conns = active_conns; + _self.known_access_points = known_access_points; + Ok(_self) + } +} From d377e8055cd07651fb44a1dda25246f509b3eec7 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 9 Jan 2023 16:15:48 -0500 Subject: [PATCH 04/11] feat: handle passwords --- .../src/network_manager/mod.rs | 65 +++++++++++++++---- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/cosmic-applet-network/src/network_manager/mod.rs b/cosmic-applet-network/src/network_manager/mod.rs index d3521b2f..c79c748f 100644 --- a/cosmic-applet-network/src/network_manager/mod.rs +++ b/cosmic-applet-network/src/network_manager/mod.rs @@ -1,7 +1,7 @@ pub mod available_wifi; pub mod current_networks; -use std::{collections::HashMap, fmt::Debug, hash::Hash, time::Duration}; +use std::{collections::HashMap, fmt::Debug, hash::Hash, ops::Deref, time::Duration}; use cosmic::iced::{self, subscription}; use cosmic_dbus_networkmanager::{ @@ -20,7 +20,7 @@ use futures::{ }; use tokio::process::Command; use zbus::{ - zvariant::{self, Value}, + zvariant::{self, ObjectPath, Value}, Connection, }; @@ -119,22 +119,25 @@ async fn start_listening( Err(_) => return (None, State::Finished), }; + let mut status = (None, false); + + // First try known connections // TODO more convenient methods of managing settings for c in s.list_connections().await.unwrap_or_default() { let mut settings = match c.get_settings().await.ok() { Some(s) => s, None => continue, }; - dbg!(&settings); + let cur_ssid = settings .get("802-11-wireless") .and_then(|w| w.get("ssid")) .cloned() .and_then(|ssid| ssid.try_into().ok()) .and_then(|ssid| String::from_utf8(ssid).ok()); - dbg!(&cur_ssid); + if cur_ssid.as_ref() != Some(&ssid) { - break; + continue; } let mut secrets = match @@ -144,7 +147,7 @@ async fn start_listening( _ => continue, }; if let Some(s) = secrets.get_mut("802-11-wireless-security") { - s.insert("psk".into(), Value::Str(password.into()).to_owned()); + s.insert("psk".into(), Value::Str(password.clone().into()).to_owned()); drop(s); settings.extend(secrets.into_iter()); let settings: HashMap<_, _> = settings.iter().map(|(k, v)| { @@ -154,18 +157,58 @@ async fn start_listening( map }).collect(); dbg!(settings.clone()); - dbg!(c.update(settings).await); + let updated = c.update(settings).await.is_ok(); + if updated { + let success = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await.is_ok(); + status = (Some((id, NetworkManagerEvent::RequestResponse { + req: NetworkManagerRequest::Password(ssid.clone(), password.clone()), + success, + state: NetworkManagerState::new(&conn).await.unwrap_or_default(), + })), false); + } + break; } } - (None, false) - } - Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => { - 'device_loop: for device in network_manager.devices().await.ok().unwrap_or_default() { + // create a connection + for device in network_manager.devices().await.ok().unwrap_or_default() { if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) { + let conn_settings: HashMap<&str, HashMap<&str, zvariant::Value>> = HashMap::from([ + ("802-11-wireless".into(), HashMap::from([ + ("ssid".into(), Value::Str(ssid.as_str().into())), + ])), + ("connection".into(), HashMap::from([ + ("id".into(), Value::Str(ssid.as_str().into())), + ("type".into(), Value::Str("802-11-wireless".into())), + ])), + ("802-11-wireless-security".into(), HashMap::from([ + ("psk".into(), Value::Str(password.as_str().into())), + ])) + ]); + let success = network_manager.add_and_activate_connection(conn_settings, device.path(), &ObjectPath::try_from("/").unwrap()).await.is_ok(); + status = (Some((id, NetworkManagerEvent::RequestResponse { + req: NetworkManagerRequest::Password(ssid.clone(), password.clone()), + success, + state: NetworkManagerState::new(&conn).await.unwrap_or_default(), + })), false); + + break; } } + + if status.0.is_none() { + (Some((id, NetworkManagerEvent::RequestResponse { + req: NetworkManagerRequest::Password(ssid, password), + success: false, + state: NetworkManagerState::new(&conn).await.unwrap_or_default(), + })), false); + } + + status + } + Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => { + (None, false) } None => { From cdca1d96acc4b4ae5cac1cf2b7f3d5ab7b20c673 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 9 Jan 2023 16:34:29 -0500 Subject: [PATCH 05/11] feat: select access point --- .../src/network_manager/mod.rs | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/cosmic-applet-network/src/network_manager/mod.rs b/cosmic-applet-network/src/network_manager/mod.rs index c79c748f..7ec8e998 100644 --- a/cosmic-applet-network/src/network_manager/mod.rs +++ b/cosmic-applet-network/src/network_manager/mod.rs @@ -198,7 +198,7 @@ async fn start_listening( } if status.0.is_none() { - (Some((id, NetworkManagerEvent::RequestResponse { + status = (Some((id, NetworkManagerEvent::RequestResponse { req: NetworkManagerRequest::Password(ssid, password), success: false, state: NetworkManagerState::new(&conn).await.unwrap_or_default(), @@ -208,8 +208,47 @@ async fn start_listening( status } Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => { + let s = match NetworkManagerSettings::new(&conn).await { + Ok(s) => s, + Err(_) => return (None, State::Finished), + }; + // find known connection with matching ssid and activate + let mut status = (None, false); - (None, false) + for c in s.list_connections().await.unwrap_or_default() { + let settings = match c.get_settings().await.ok() { + Some(s) => s, + None => continue, + }; + + let cur_ssid = settings + .get("802-11-wireless") + .and_then(|w| w.get("ssid")) + .cloned() + .and_then(|ssid| ssid.try_into().ok()) + .and_then(|ssid| String::from_utf8(ssid).ok()); + + if cur_ssid.as_ref() != Some(&ssid) { + continue; + } + + let success = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await.is_ok(); + status = (Some((id, NetworkManagerEvent::RequestResponse { + req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()), + success, + state: NetworkManagerState::new(&conn).await.unwrap_or_default(), + })), false); + + break; + } + if status.0.is_none() { + status = (Some((id, NetworkManagerEvent::RequestResponse { + req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()), + success: false, + state: NetworkManagerState::new(&conn).await.unwrap_or_default(), + })), false); + } + status } None => { (None, true) From 6b5ce0f35f11a81a9b5cc8e8cf673871d2e30da9 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 9 Jan 2023 22:43:35 -0500 Subject: [PATCH 06/11] wip: handle state after activating connections --- cosmic-applet-network/src/app.rs | 56 +++++- .../src/network_manager/available_wifi.rs | 1 - .../src/network_manager/mod.rs | 161 ++++++++++++++---- 3 files changed, 184 insertions(+), 34 deletions(-) diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index a9adde1d..2c478105 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -38,6 +38,7 @@ pub fn run() -> cosmic::iced::Result { CosmicNetworkApplet::run(helper.window_settings()) } +#[derive(Debug)] enum NewConnectionState { EnterPassword { access_point: AccessPoint, @@ -216,19 +217,61 @@ impl Application for CosmicNetworkApplet { airplane_mode, }, success, - .. + req, } => { if success { + match req { + NetworkManagerRequest::SetAirplaneMode(_) + | NetworkManagerRequest::SetWiFi(_) => {} + NetworkManagerRequest::SelectAccessPoint(_) + | NetworkManagerRequest::Password(_, _) => { + self.new_connection.take(); + self.show_visible_networks = false; + } + } self.wireless_access_points = wireless_access_points; self.active_conns = active_conns; self.known_access_points = known_access_points; self.airplane_mode = airplane_mode; self.wifi = wifi_enabled; self.update_icon_name(); + } else { + match req { + NetworkManagerRequest::SetAirplaneMode(_) + | NetworkManagerRequest::SetWiFi(_) => {} + NetworkManagerRequest::SelectAccessPoint(_) => { + if let Some(NewConnectionState::Waiting(access_point)) = + self.new_connection.as_ref() + { + self.new_connection + .replace(NewConnectionState::Failure(access_point.clone())); + } + } + NetworkManagerRequest::Password(_, _) => { + if let Some(NewConnectionState::EnterPassword { + access_point, + .. + }) = self.new_connection.as_ref() + { + self.new_connection + .replace(NewConnectionState::Failure(access_point.clone())); + } + } + } } } }, Message::SelectWirelessAccessPoint(access_point) => { + let tx = if let Some(tx) = self.nm_sender.as_ref() { + tx + } else { + return Command::none(); + }; + + let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint( + access_point.ssid.clone(), + )); + self.new_connection .replace(NewConnectionState::EnterPassword { access_point, @@ -263,12 +306,19 @@ impl Application for CosmicNetworkApplet { password.to_string(), )); self.new_connection - .replace(NewConnectionState::Failure(access_point.clone())); + .replace(NewConnectionState::Waiting(access_point.clone())); } _ => {} }; } - Message::ActivateKnownWifi(ssid) => {} + Message::ActivateKnownWifi(ssid) => { + let tx = if let Some(tx) = self.nm_sender.as_ref() { + tx + } else { + return Command::none(); + }; + let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint(ssid)); + } Message::CancelNewConnection => { self.new_connection.take(); } diff --git a/cosmic-applet-network/src/network_manager/available_wifi.rs b/cosmic-applet-network/src/network_manager/available_wifi.rs index 7f9f5c83..62e90e86 100644 --- a/cosmic-applet-network/src/network_manager/available_wifi.rs +++ b/cosmic-applet-network/src/network_manager/available_wifi.rs @@ -28,7 +28,6 @@ pub async fn handle_wireless_device(device: WirelessDevice<'_>) -> zbus::Result< for ap in access_points { let ssid = String::from_utf8_lossy(&ap.ssid().await?.clone()).into_owned(); let strength = ap.strength().await?; - if let Some(access_point) = aps.get(&ssid) { if access_point.strength > strength { continue; diff --git a/cosmic-applet-network/src/network_manager/mod.rs b/cosmic-applet-network/src/network_manager/mod.rs index 7ec8e998..330fff38 100644 --- a/cosmic-applet-network/src/network_manager/mod.rs +++ b/cosmic-applet-network/src/network_manager/mod.rs @@ -5,8 +5,12 @@ use std::{collections::HashMap, fmt::Debug, hash::Hash, ops::Deref, time::Durati use cosmic::iced::{self, subscription}; use cosmic_dbus_networkmanager::{ + active_connection::ActiveConnection, device::SpecificDevice, - interface::{enums::DeviceType, settings::connection::ConnectionSettingsProxy}, + interface::{ + active_connection::ActiveConnectionProxy, enums, enums::DeviceType, + settings::connection::ConnectionSettingsProxy, + }, nm::{self, NetworkManager}, settings::{ connection::{ConnectionSettings, Secrets, Settings}, @@ -46,7 +50,7 @@ pub enum State { Finished, } -async fn start_listening( +async fn start_listening( id: I, state: State, ) -> (Option<(I, NetworkManagerEvent)>, State) { @@ -135,7 +139,6 @@ async fn start_listening( .cloned() .and_then(|ssid| ssid.try_into().ok()) .and_then(|ssid| String::from_utf8(ssid).ok()); - if cur_ssid.as_ref() != Some(&ssid) { continue; } @@ -144,7 +147,10 @@ async fn start_listening( c.get_secrets("802-11-wireless-security") .await { Ok(s) => s, - _ => continue, + _ => HashMap::from([("802-11-wireless-security".into(), HashMap::from([ + ("psk".into(), Value::Str(password.as_str().into()).to_owned()), + ("key-mgmt".into(), Value::Str("wpa-psk".into()).to_owned()) + ]))]), }; if let Some(s) = secrets.get_mut("802-11-wireless-security") { s.insert("psk".into(), Value::Str(password.clone().into()).to_owned()); @@ -156,10 +162,22 @@ async fn start_listening( .collect::>()); map }).collect(); - dbg!(settings.clone()); - let updated = c.update(settings).await.is_ok(); - if updated { - let success = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await.is_ok(); + let updated = c.update(settings).await; + if updated.is_ok() { + let success = if let Ok(path) = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await { + // let active_conn = ActiveConnection::from(ActiveConnectionProxy::from(conn.1)); + let dummy = ActiveConnectionProxy::new(&conn).await.unwrap(); + let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); + let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); + let s = if let enums::ActiveConnectionState::Activating = state { + enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default()) + } else { + state + }; + matches!(s, enums::ActiveConnectionState::Activated) + } else { + false + }; status = (Some((id, NetworkManagerEvent::RequestResponse { req: NetworkManagerRequest::Password(ssid.clone(), password.clone()), success, @@ -172,28 +190,43 @@ async fn start_listening( } // create a connection - for device in network_manager.devices().await.ok().unwrap_or_default() { - if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) { - let conn_settings: HashMap<&str, HashMap<&str, zvariant::Value>> = HashMap::from([ - ("802-11-wireless".into(), HashMap::from([ - ("ssid".into(), Value::Str(ssid.as_str().into())), - ])), - ("connection".into(), HashMap::from([ - ("id".into(), Value::Str(ssid.as_str().into())), - ("type".into(), Value::Str("802-11-wireless".into())), - ])), - ("802-11-wireless-security".into(), HashMap::from([ - ("psk".into(), Value::Str(password.as_str().into())), - ])) - ]); - let success = network_manager.add_and_activate_connection(conn_settings, device.path(), &ObjectPath::try_from("/").unwrap()).await.is_ok(); - status = (Some((id, NetworkManagerEvent::RequestResponse { - req: NetworkManagerRequest::Password(ssid.clone(), password.clone()), - success, - state: NetworkManagerState::new(&conn).await.unwrap_or_default(), - })), false); + if status.0.is_none() { + for device in network_manager.devices().await.ok().unwrap_or_default() { + if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) { + let conn_settings: HashMap<&str, HashMap<&str, zvariant::Value>> = HashMap::from([ + ("802-11-wireless".into(), HashMap::from([ + ("ssid".into(), Value::Array(ssid.as_bytes().into())), + ])), + ("connection".into(), HashMap::from([ + ("id".into(), Value::Str(ssid.as_str().into())), + ("type".into(), Value::Str("802-11-wireless".into())), + ])), + ("802-11-wireless-security".into(), HashMap::from([ + ("psk".into(), Value::Str(password.as_str().into())), + ("key-mgmt".into(), Value::Str("wpa-psk".into())) + ])) + ]); + let success = if let Ok((_, path)) = network_manager.add_and_activate_connection(conn_settings, device.path(), &ObjectPath::try_from("/").unwrap()).await { + let dummy = ActiveConnectionProxy::new(&conn).await.unwrap(); + let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); + let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); + let s = if let enums::ActiveConnectionState::Activating = state { + enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default()) + } else { + state + }; + matches!(s, enums::ActiveConnectionState::Activated) + } else { + false + }; + status = (Some((id, NetworkManagerEvent::RequestResponse { + req: NetworkManagerRequest::Password(ssid.clone(), password.clone()), + success, + state: NetworkManagerState::new(&conn).await.unwrap_or_default(), + })), false); - break; + break; + } } } @@ -215,6 +248,9 @@ async fn start_listening( // find known connection with matching ssid and activate let mut status = (None, false); + let devices = network_manager.devices().await.ok().unwrap_or_default(); + + for c in s.list_connections().await.unwrap_or_default() { let settings = match c.get_settings().await.ok() { Some(s) => s, @@ -232,7 +268,20 @@ async fn start_listening( continue; } - let success = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await.is_ok(); + let success = if let Ok(path) = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await { + let dummy = ActiveConnectionProxy::new(&conn).await.unwrap(); + let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); + let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); + let s = if let enums::ActiveConnectionState::Activating = state { + enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default()) + } else { + state + }; + matches!(s, enums::ActiveConnectionState::Activated) + } else { + false + }; + // dbg!(&success); status = (Some((id, NetworkManagerEvent::RequestResponse { req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()), success, @@ -241,6 +290,58 @@ async fn start_listening( break; } + // dbg!(&status); + let mut ap = None; + + for d in &devices { + if let Ok(Some(SpecificDevice::Wireless(wireless_device))) = + d.downcast_to_device().await { + for a in wireless_device.access_points().await.ok().unwrap_or_default() { + if String::from_utf8(a.ssid().await.unwrap_or_default()).unwrap_or_default() == ssid { + ap = Some(a); + break; + } + } + } + }; + if status.0.is_none() { + + for device in network_manager.devices().await.ok().unwrap_or_default() { + if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) { + let conn_settings: HashMap<&str, HashMap<&str, zvariant::Value>> = HashMap::from([ + ("802-11-wireless".into(), HashMap::from([ + ("ssid".into(), Value::Array(ssid.as_bytes().into())), + ])), + ("connection".into(), HashMap::from([ + ("id".into(), Value::Str(ssid.as_str().into())), + ("type".into(), Value::Str("802-11-wireless".into())), + ])), + ]); + let success = if let Ok((_, path)) = network_manager.add_and_activate_connection(conn_settings, device.path(), &ap.as_ref().map(|ap| ap.path().clone()).unwrap_or_else(||ObjectPath::try_from("/").unwrap().into_owned())).await { + let dummy = ActiveConnectionProxy::new(&conn).await.unwrap(); + let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); + let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); + let s = if let enums::ActiveConnectionState::Activating = state { + enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default()) + } else { + state + }; + matches!(s, enums::ActiveConnectionState::Activated) + } else { + false + }; + status = (Some((id, NetworkManagerEvent::RequestResponse { + req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()), + success, + state: NetworkManagerState::new(&conn).await.unwrap_or_default(), + })), false); + + break; + } + } + } + // dbg!(&status); + if status.0.is_none() { status = (Some((id, NetworkManagerEvent::RequestResponse { req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()), From e43fe95b999876af56124001749dbe92d2b0aa96 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 9 Jan 2023 23:08:56 -0500 Subject: [PATCH 07/11] fix: use timeouts --- .../src/network_manager/mod.rs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/cosmic-applet-network/src/network_manager/mod.rs b/cosmic-applet-network/src/network_manager/mod.rs index 330fff38..6ea50ac0 100644 --- a/cosmic-applet-network/src/network_manager/mod.rs +++ b/cosmic-applet-network/src/network_manager/mod.rs @@ -22,7 +22,7 @@ use futures::{ future::ok, FutureExt, StreamExt, }; -use tokio::process::Command; +use tokio::{process::Command, time::timeout}; use zbus::{ zvariant::{self, ObjectPath, Value}, Connection, @@ -170,7 +170,11 @@ async fn start_listening( let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); let s = if let enums::ActiveConnectionState::Activating = state { - enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default()) + if let Ok(Some(s)) = timeout(Duration::from_secs(5), active.receive_state_changed().await.next()).await { + s.get().await.unwrap_or_default().into() + } else { + state + } } else { state }; @@ -211,7 +215,11 @@ async fn start_listening( let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); let s = if let enums::ActiveConnectionState::Activating = state { - enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default()) + if let Ok(Some(s)) = timeout(Duration::from_secs(5), active.receive_state_changed().await.next()).await { + s.get().await.unwrap_or_default().into() + } else { + state + } } else { state }; @@ -273,7 +281,11 @@ async fn start_listening( let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); let s = if let enums::ActiveConnectionState::Activating = state { - enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default()) + if let Ok(Some(s)) = timeout(Duration::from_secs(1), active.receive_state_changed().await.next()).await { + s.get().await.unwrap_or_default().into() + } else { + state + } } else { state }; @@ -322,7 +334,11 @@ async fn start_listening( let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); let s = if let enums::ActiveConnectionState::Activating = state { - enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default()) + if let Ok(Some(s)) = timeout(Duration::from_secs(1), active.receive_state_changed().await.next()).await { + s.get().await.unwrap_or_default().into() + } else { + state + } } else { state }; From d35732d120b1a158c19cdd78da92f942cd81a096 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 10 Jan 2023 13:19:59 -0500 Subject: [PATCH 08/11] refactor nm state --- Cargo.lock | 75 +++++++-------- cosmic-applet-network/src/app.rs | 91 ++++++++----------- .../src/network_manager/mod.rs | 6 ++ 3 files changed, 84 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f13c5529..e2042f86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -567,6 +567,7 @@ dependencies = [ name = "cosmic-applet-network" version = "0.1.0" dependencies = [ + "anyhow", "cosmic-dbus-networkmanager", "futures", "futures-util", @@ -655,7 +656,7 @@ dependencies = [ [[package]] name = "cosmic-dbus-networkmanager" version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings?branch=main#5adeb6dc11fd11d26d09ec35c25b93866bb21d31" +source = "git+https://github.com/pop-os/dbus-settings-bindings?branch=main#95f6d5e9ac86dfa5902ac74dee85b1a8cfc035fd" dependencies = [ "bitflags", "derive_builder", @@ -821,9 +822,9 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "cxx" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" +checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" dependencies = [ "cc", "cxxbridge-flags", @@ -833,9 +834,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70" dependencies = [ "cc", "codespan-reporting", @@ -848,15 +849,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" +checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" [[package]] name = "cxxbridge-macro" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" +checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" dependencies = [ "proc-macro2", "quote", @@ -1849,9 +1850,9 @@ dependencies = [ [[package]] name = "half" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c467d36af040b7b2681f5fddd27427f6da8d3d072f575a265e181d2f8e8d157" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" dependencies = [ "crunchy", ] @@ -1912,9 +1913,9 @@ dependencies = [ [[package]] name = "i18n-config" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62affcd43abfb51f3cbd8736f9407908dc5b44fc558a9be07460bbfd104d983" +checksum = "3d9f93ceee6543011739bc81699b5e0cf1f23f3a80364649b6d80de8636bc8df" dependencies = [ "log", "serde", @@ -1926,9 +1927,9 @@ dependencies = [ [[package]] name = "i18n-embed" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f21ed76e44de8ac3dfa36bb37ab2e6480be0dc75c612474949be1f3cb2c253" +checksum = "79ff7e6b37b61834ec97fc945d391315188d8bb87aa1d48f10f295e73a5f5bec" dependencies = [ "fluent", "fluent-langneg", @@ -1947,9 +1948,9 @@ dependencies = [ [[package]] name = "i18n-embed-fl" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420a9718ef9d0ab727840a398e25408ea0daff9ba3c681707ba05485face98e" +checksum = "a425b9bbdc2e4cd797a2a79528662cb61894bd36db582e48da2c56c28eb727cd" dependencies = [ "dashmap", "find-crate", @@ -2373,9 +2374,9 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "libpulse-binding" -version = "2.26.0" +version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17be42160017e0ae993c03bfdab4ecb6f82ce3f8d515bd8da8fdf18d10703663" +checksum = "1745b20bfc194ac12ef828f144f0ec2d4a7fe993281fa3567a0bd4969aee6890" dependencies = [ "bitflags", "libc", @@ -2387,9 +2388,9 @@ dependencies = [ [[package]] name = "libpulse-glib-binding" -version = "2.25.1" +version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0e7a964c9f7e95d4f073affc19adfda009fa0d55e8831dbb66c78be1d0e6e5" +checksum = "d39d9166164cf39b619f6a029ffafac958e718a10dabdc35bcebf8f69b5fa3cf" dependencies = [ "glib", "glib-sys", @@ -2399,9 +2400,9 @@ dependencies = [ [[package]] name = "libpulse-mainloop-glib-sys" -version = "1.19.2" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f61c4064926cc77ea14bb206a21ce1d5a06e175e5c0ce078804bb6c4527b28" +checksum = "9b97cd2ed4e84e54f3825b85648ec8637bec273ea7fcb981032b0a575dfef697" dependencies = [ "glib-sys", "libpulse-sys", @@ -2410,9 +2411,9 @@ dependencies = [ [[package]] name = "libpulse-sys" -version = "1.19.3" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991e6bd0efe2a36e6534e136e7996925e4c1a8e35b7807fe533f2beffff27c30" +checksum = "2191e6880818d1df4cf72eac8e91dce7a5a52ba0da4b2a5cdafabc22b937eadb" dependencies = [ "libc", "num-derive", @@ -2855,7 +2856,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a5f3c7ca08b6879e7965fb25e24d1f5eeb32ea73f9ad99b3854778a38c57e93" dependencies = [ - "ttf-parser 0.18.0", + "ttf-parser 0.18.1", ] [[package]] @@ -3274,9 +3275,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -4053,9 +4054,9 @@ checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff" [[package]] name = "ttf-parser" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf554b6e535f9a160b2ed4ea83f99000f21cbc0a693df26e258eaf2c226a151" +checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" [[package]] name = "twox-hash" @@ -4079,9 +4080,9 @@ dependencies = [ [[package]] name = "typed-arena" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" @@ -4881,7 +4882,7 @@ dependencies = [ [[package]] name = "zbus" version = "3.7.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" dependencies = [ "async-broadcast", "async-executor", @@ -4931,7 +4932,7 @@ dependencies = [ [[package]] name = "zbus_macros" version = "3.7.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -4954,7 +4955,7 @@ dependencies = [ [[package]] name = "zbus_names" version = "2.5.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" dependencies = [ "serde", "static_assertions", @@ -4984,7 +4985,7 @@ dependencies = [ [[package]] name = "zvariant" version = "3.10.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" dependencies = [ "byteorder", "enumflags2", @@ -5009,7 +5010,7 @@ dependencies = [ [[package]] name = "zvariant_derive" version = "3.10.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#e90e72eb2d0d5f77144bf40baa7337de89932a53" +source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index 2c478105..53b32726 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -68,12 +68,8 @@ struct CosmicNetworkApplet { popup: Option, id_ctr: u32, applet_helper: CosmicAppletHelper, - // STATE - airplane_mode: bool, - wifi: bool, - wireless_access_points: Vec, - active_conns: Vec, - known_access_points: Vec, + nm_state: NetworkManagerState, + // UI state nm_sender: Option>, show_visible_networks: bool, new_connection: Option, @@ -82,6 +78,7 @@ struct CosmicNetworkApplet { impl CosmicNetworkApplet { fn update_icon_name(&mut self) { self.icon_name = self + .nm_state .active_conns .iter() .fold("network-offline-symbolic", |icon_name, conn| { @@ -166,56 +163,42 @@ impl Application for CosmicNetworkApplet { Message::Errored(_) => todo!(), Message::Ignore => {} Message::ToggleAirplaneMode(enabled) => { - self.airplane_mode = enabled; + self.nm_state.airplane_mode = enabled; if let Some(tx) = self.nm_sender.as_mut() { let _ = tx.unbounded_send(NetworkManagerRequest::SetAirplaneMode(enabled)); } } Message::ToggleWiFi(enabled) => { - self.wifi = enabled; + if !enabled { + self.nm_state.clear(); + } + self.nm_state.wifi_enabled = enabled; + if let Some(tx) = self.nm_sender.as_mut() { let _ = tx.unbounded_send(NetworkManagerRequest::SetWiFi(enabled)); } } Message::NetworkManagerEvent(event) => match event { - NetworkManagerEvent::Init { - sender, - state: - NetworkManagerState { - wireless_access_points, - active_conns, - known_access_points, - wifi_enabled, - airplane_mode, - }, - } => { + NetworkManagerEvent::Init { sender, state } => { self.nm_sender.replace(sender); - self.wireless_access_points = wireless_access_points; - self.active_conns = active_conns; - self.wifi = wifi_enabled; - self.airplane_mode = airplane_mode; + self.nm_state = state; self.update_icon_name(); - self.known_access_points = known_access_points; } NetworkManagerEvent::WiFiEnabled(enabled) => { - self.wifi = enabled; + if !enabled { + self.nm_state.clear(); + } + self.nm_state.wifi_enabled = enabled; } NetworkManagerEvent::WirelessAccessPoints(access_points) => { - self.wireless_access_points = access_points; + self.nm_state.wireless_access_points = access_points; } NetworkManagerEvent::ActiveConns(conns) => { - self.active_conns = conns; + self.nm_state.active_conns = conns; self.update_icon_name(); } NetworkManagerEvent::RequestResponse { - state: - NetworkManagerState { - wireless_access_points, - active_conns, - known_access_points, - wifi_enabled, - airplane_mode, - }, + state, success, req, } => { @@ -225,16 +208,12 @@ impl Application for CosmicNetworkApplet { | NetworkManagerRequest::SetWiFi(_) => {} NetworkManagerRequest::SelectAccessPoint(_) | NetworkManagerRequest::Password(_, _) => { + dbg!("success"); + dbg!(&state); self.new_connection.take(); self.show_visible_networks = false; } } - self.wireless_access_points = wireless_access_points; - self.active_conns = active_conns; - self.known_access_points = known_access_points; - self.airplane_mode = airplane_mode; - self.wifi = wifi_enabled; - self.update_icon_name(); } else { match req { NetworkManagerRequest::SetAirplaneMode(_) @@ -259,6 +238,8 @@ impl Application for CosmicNetworkApplet { } } } + self.nm_state = state; + self.update_icon_name(); } }, Message::SelectWirelessAccessPoint(access_point) => { @@ -346,7 +327,7 @@ impl Application for CosmicNetworkApplet { SurfaceIdWrapper::Popup(_) => { let mut vpn_ethernet_col = column![]; let mut known_wifi = column![]; - for conn in &self.active_conns { + for conn in &self.nm_state.active_conns { match conn { ActiveConnectionInfo::Vpn { name, ip_addresses } => { let mut ipv4 = column![]; @@ -432,7 +413,7 @@ impl Application for CosmicNetworkApplet { } }; } - for known in &self.known_access_points { + for known in &self.nm_state.known_access_points { let mut btn = button(Button::Secondary) .custom(vec![ icon("network-wireless-symbolic", 24) @@ -469,7 +450,7 @@ impl Application for CosmicNetworkApplet { let mut content = column![ vpn_ethernet_col, container( - toggler(fl!("airplane-mode"), self.airplane_mode, |m| { + toggler(fl!("airplane-mode"), self.nm_state.airplane_mode, |m| { Message::ToggleAirplaneMode(m) }) .width(Length::Fill) @@ -477,8 +458,10 @@ impl Application for CosmicNetworkApplet { .padding([0, 12]), horizontal_rule(1), container( - toggler(fl!("wifi"), self.wifi, |m| { Message::ToggleWiFi(m) }) - .width(Length::Fill) + toggler(fl!("wifi"), self.nm_state.wifi_enabled, |m| { + Message::ToggleWiFi(m) + }) + .width(Length::Fill) ) .padding([0, 12]), horizontal_rule(1), @@ -579,7 +562,6 @@ impl Application for CosmicNetworkApplet { ] .align_items(Alignment::Center) .width(Length::Fill) - .padding([0, 24]) .spacing(12); let connecting = row![ id, @@ -589,7 +571,9 @@ impl Application for CosmicNetworkApplet { })) .width(Length::Units(24)) .height(Length::Units(24)), - ]; + ] + .spacing(8) + .padding([0, 24]); content = content.push(connecting); } NewConnectionState::Failure(access_point) => { @@ -632,10 +616,15 @@ impl Application for CosmicNetworkApplet { content = content.push(col); } } - } else if self.wifi { + } else if self.nm_state.wifi_enabled { let mut list_col = column![]; - for ap in &self.wireless_access_points { - if self.active_conns.iter().any(|a| ap.ssid == a.name()) { + for ap in &self.nm_state.wireless_access_points { + if self + .nm_state + .active_conns + .iter() + .any(|a| ap.ssid == a.name()) + { continue; } let button = button(button_style) diff --git a/cosmic-applet-network/src/network_manager/mod.rs b/cosmic-applet-network/src/network_manager/mod.rs index 6ea50ac0..f7e30c9c 100644 --- a/cosmic-applet-network/src/network_manager/mod.rs +++ b/cosmic-applet-network/src/network_manager/mod.rs @@ -539,4 +539,10 @@ impl NetworkManagerState { _self.known_access_points = known_access_points; Ok(_self) } + + pub fn clear(&mut self) { + self.active_conns = Vec::new(); + self.known_access_points = Vec::new(); + self.wireless_access_points = Vec::new(); + } } From 4b5cc64e309cbf7c70766e986c36f0791474f02a Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 10 Jan 2023 13:29:52 -0500 Subject: [PATCH 09/11] fix: longer timeouts & cleanup --- cosmic-applet-network/src/app.rs | 2 -- cosmic-applet-network/src/network_manager/mod.rs | 11 ++++------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index 53b32726..4c7d5f58 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -208,8 +208,6 @@ impl Application for CosmicNetworkApplet { | NetworkManagerRequest::SetWiFi(_) => {} NetworkManagerRequest::SelectAccessPoint(_) | NetworkManagerRequest::Password(_, _) => { - dbg!("success"); - dbg!(&state); self.new_connection.take(); self.show_visible_networks = false; } diff --git a/cosmic-applet-network/src/network_manager/mod.rs b/cosmic-applet-network/src/network_manager/mod.rs index f7e30c9c..79eb869a 100644 --- a/cosmic-applet-network/src/network_manager/mod.rs +++ b/cosmic-applet-network/src/network_manager/mod.rs @@ -170,7 +170,7 @@ async fn start_listening( let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); let s = if let enums::ActiveConnectionState::Activating = state { - if let Ok(Some(s)) = timeout(Duration::from_secs(5), active.receive_state_changed().await.next()).await { + if let Ok(Some(s)) = timeout(Duration::from_secs(10), active.receive_state_changed().await.next()).await { s.get().await.unwrap_or_default().into() } else { state @@ -215,7 +215,7 @@ async fn start_listening( let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); let s = if let enums::ActiveConnectionState::Activating = state { - if let Ok(Some(s)) = timeout(Duration::from_secs(5), active.receive_state_changed().await.next()).await { + if let Ok(Some(s)) = timeout(Duration::from_secs(10), active.receive_state_changed().await.next()).await { s.get().await.unwrap_or_default().into() } else { state @@ -281,7 +281,7 @@ async fn start_listening( let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); let s = if let enums::ActiveConnectionState::Activating = state { - if let Ok(Some(s)) = timeout(Duration::from_secs(1), active.receive_state_changed().await.next()).await { + if let Ok(Some(s)) = timeout(Duration::from_secs(10), active.receive_state_changed().await.next()).await { s.get().await.unwrap_or_default().into() } else { state @@ -293,7 +293,6 @@ async fn start_listening( } else { false }; - // dbg!(&success); status = (Some((id, NetworkManagerEvent::RequestResponse { req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()), success, @@ -302,7 +301,6 @@ async fn start_listening( break; } - // dbg!(&status); let mut ap = None; for d in &devices { @@ -334,7 +332,7 @@ async fn start_listening( let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap(); let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default()); let s = if let enums::ActiveConnectionState::Activating = state { - if let Ok(Some(s)) = timeout(Duration::from_secs(1), active.receive_state_changed().await.next()).await { + if let Ok(Some(s)) = timeout(Duration::from_secs(10), active.receive_state_changed().await.next()).await { s.get().await.unwrap_or_default().into() } else { state @@ -356,7 +354,6 @@ async fn start_listening( } } } - // dbg!(&status); if status.0.is_none() { status = (Some((id, NetworkManagerEvent::RequestResponse { From cbbd350fc67dfed9c6179949bdd76283f6b55a8d Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 10 Jan 2023 14:03:38 -0500 Subject: [PATCH 10/11] update power applet to use latest zbus --- Cargo.lock | 112 +++++---------------------------- cosmic-applet-power/Cargo.toml | 12 +--- 2 files changed, 17 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2042f86..54abb816 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -551,7 +551,7 @@ dependencies = [ "rust-embed", "smithay-client-toolkit", "tokio", - "zbus 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zbus", ] [[package]] @@ -560,7 +560,7 @@ version = "0.1.0" dependencies = [ "libcosmic", "smithay-client-toolkit", - "zbus 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zbus", ] [[package]] @@ -582,7 +582,7 @@ dependencies = [ "slotmap", "smithay-client-toolkit", "tokio", - "zbus 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zbus", ] [[package]] @@ -606,7 +606,7 @@ dependencies = [ "nix 0.26.1", "smithay-client-toolkit", "tokio", - "zbus 3.7.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", + "zbus", ] [[package]] @@ -662,8 +662,8 @@ dependencies = [ "derive_builder", "procfs", "time 0.3.17", - "zbus 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zvariant 3.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zbus", + "zvariant", ] [[package]] @@ -2477,11 +2477,12 @@ dependencies = [ [[package]] name = "logind-zbus" -version = "3.0.3" -source = "git+https://github.com/pop-os/logind-zbus?branch=main#0789bde15b61b3f65b1e028841eeb5411f66f474" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2cfc54565c8d002ad7344ec08ce512c269b2de56dea59850708691e4b18fe3" dependencies = [ "serde", - "zbus 3.7.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", + "zbus", ] [[package]] @@ -4874,46 +4875,9 @@ dependencies = [ "tracing", "uds_windows", "winapi", - "zbus_macros 3.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zbus_names 2.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zvariant 3.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zbus" -version = "3.7.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" -dependencies = [ - "async-broadcast", - "async-executor", - "async-io", - "async-lock", - "async-recursion", - "async-task", - "async-trait", - "byteorder", - "derivative", - "dirs 4.0.0", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix 0.25.1", - "once_cell", - "ordered-stream", - "rand", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "tracing", - "uds_windows", - "winapi", - "zbus_macros 3.7.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", - "zbus_names 2.5.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", - "zvariant 3.10.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", + "zbus_macros", + "zbus_names", + "zvariant", ] [[package]] @@ -4929,18 +4893,6 @@ dependencies = [ "syn", ] -[[package]] -name = "zbus_macros" -version = "3.7.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "regex", - "syn", -] - [[package]] name = "zbus_names" version = "2.5.0" @@ -4949,17 +4901,7 @@ checksum = "f34f314916bd89bdb9934154627fab152f4f28acdda03e7c4c68181b214fe7e3" dependencies = [ "serde", "static_assertions", - "zvariant 3.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zbus_names" -version = "2.5.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" -dependencies = [ - "serde", - "static_assertions", - "zvariant 3.10.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", + "zvariant", ] [[package]] @@ -4979,20 +4921,7 @@ dependencies = [ "libc", "serde", "static_assertions", - "zvariant_derive 3.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zvariant" -version = "3.10.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" -dependencies = [ - "byteorder", - "enumflags2", - "libc", - "serde", - "static_assertions", - "zvariant_derive 3.10.0 (git+https://gitlab.freedesktop.org/dbus/zbus?branch=main)", + "zvariant_derive", ] [[package]] @@ -5006,14 +4935,3 @@ dependencies = [ "quote", "syn", ] - -[[package]] -name = "zvariant_derive" -version = "3.10.0" -source = "git+https://gitlab.freedesktop.org/dbus/zbus?branch=main#18240526a612e56e9379f64d42c07053eed9657e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] diff --git a/cosmic-applet-power/Cargo.toml b/cosmic-applet-power/Cargo.toml index 80402eac..42f746ed 100644 --- a/cosmic-applet-power/Cargo.toml +++ b/cosmic-applet-power/Cargo.toml @@ -12,13 +12,5 @@ tokio = { version = "1.20.1", features=["full"] } libcosmic = { git = "https://github.com/pop-os/libcosmic/", branch = "master", default-features = false, features = ["wayland", "applet"] } sctk = { package = "smithay-client-toolkit", git = "https://github.com/Smithay/client-toolkit", rev = "3776d4a" } nix = "0.26.1" - -# Until the 3.6.3 release, need the implementation of clone on zbus::Error -[dependencies.zbus] -git = "https://gitlab.freedesktop.org/dbus/zbus" -branch = "main" - -# Until zbus 3.6.3 is released -[dependencies.logind-zbus] -git = "https://github.com/pop-os/logind-zbus" -branch = "main" +zbus = "3.7" +logind-zbus = "3.1" From a423aaa27a2b3047e380afde29cca917eb47573e Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 10 Jan 2023 17:29:19 -0500 Subject: [PATCH 11/11] refactor: Vec::with_capacity where possible --- cosmic-applet-network/src/app.rs | 68 ++++++++----------- .../src/network_manager/current_networks.rs | 62 +++++------------ 2 files changed, 46 insertions(+), 84 deletions(-) diff --git a/cosmic-applet-network/src/app.rs b/cosmic-applet-network/src/app.rs index 4c7d5f58..e1f38a35 100644 --- a/cosmic-applet-network/src/app.rs +++ b/cosmic-applet-network/src/app.rs @@ -7,7 +7,7 @@ use cosmic::{ popup::{destroy_popup, get_popup}, SurfaceIdWrapper, }, - widget::{column, container, row, scrollable, text, text_input}, + widget::{column, container, row, scrollable, text, text_input, Column}, Alignment, Application, Color, Command, Length, Subscription, }, iced_native::{ @@ -328,20 +328,16 @@ impl Application for CosmicNetworkApplet { for conn in &self.nm_state.active_conns { match conn { ActiveConnectionInfo::Vpn { name, ip_addresses } => { - let mut ipv4 = column![]; + let mut ipv4 = Vec::with_capacity(ip_addresses.len()); for addr in ip_addresses { - match addr { - std::net::IpAddr::V4(a) => { - ipv4 = ipv4.push( - text(format!("{}: {}", fl!("ipv4"), a.to_string())) - .size(12), - ); - } - std::net::IpAddr::V6(_) => {} - } + ipv4.push( + text(format!("{}: {}", fl!("ipv4"), addr.to_string())) + .size(12) + .into(), + ); } - vpn_ethernet_col = - vpn_ethernet_col.push(column![text(name), ipv4].spacing(4)); + vpn_ethernet_col = vpn_ethernet_col + .push(column![text(name), Column::with_children(ipv4)].spacing(4)); } ActiveConnectionInfo::Wired { name, @@ -349,17 +345,13 @@ impl Application for CosmicNetworkApplet { speed, ip_addresses, } => { - let mut ipv4 = column![]; + let mut ipv4 = Vec::with_capacity(ip_addresses.len()); for addr in ip_addresses { - match addr { - std::net::IpAddr::V4(a) => { - ipv4 = ipv4.push( - text(format!("{}: {}", fl!("ipv4"), a.to_string())) - .size(12), - ); - } - std::net::IpAddr::V6(a) => {} - } + ipv4.push( + text(format!("{}: {}", fl!("ipv4"), addr.to_string())) + .size(12) + .into(), + ); } vpn_ethernet_col = vpn_ethernet_col.push( column![ @@ -368,7 +360,7 @@ impl Application for CosmicNetworkApplet { text(format!("{speed} {}", fl!("megabits-per-second"))) ] .spacing(16), - ipv4, + Column::with_children(ipv4), ] .spacing(4), ); @@ -376,17 +368,13 @@ impl Application for CosmicNetworkApplet { ActiveConnectionInfo::WiFi { name, ip_addresses, .. } => { - let mut ipv4 = column![]; + let mut ipv4 = Vec::with_capacity(ip_addresses.len()); for addr in ip_addresses { - match addr { - std::net::IpAddr::V4(a) => { - ipv4 = ipv4.push( - text(format!("{}: {}", fl!("ipv4"), a.to_string())) - .size(12), - ); - } - std::net::IpAddr::V6(_) => {} - } + ipv4.push( + text(format!("{}: {}", fl!("ipv4"), addr.to_string())) + .size(12) + .into(), + ); } known_wifi = known_wifi.push(column![button(Button::Secondary) .custom(vec![ @@ -397,7 +385,8 @@ impl Application for CosmicNetworkApplet { .width(Length::Units(24)) .height(Length::Units(24)) .into(), - column![text(name).size(14), ipv4,].into(), + column![text(name).size(14), Column::with_children(ipv4)] + .into(), text(format!("{}", fl!("connected"))) .size(14) .width(Length::Fill) @@ -615,7 +604,8 @@ impl Application for CosmicNetworkApplet { } } } else if self.nm_state.wifi_enabled { - let mut list_col = column![]; + let mut list_col = + Vec::with_capacity(self.nm_state.wireless_access_points.len()); for ap in &self.nm_state.wireless_access_points { if self .nm_state @@ -644,9 +634,11 @@ impl Application for CosmicNetworkApplet { .on_press(Message::SelectWirelessAccessPoint(ap.clone())) .width(Length::Fill) .padding([8, 24]); - list_col = list_col.push(button); + list_col.push(button.into()); } - content = content.push(scrollable(list_col).height(Length::Units(300))); + content = content.push( + scrollable(Column::with_children(list_col)).height(Length::Units(300)), + ); } } self.applet_helper.popup_container(content).into() diff --git a/cosmic-applet-network/src/network_manager/current_networks.rs b/cosmic-applet-network/src/network_manager/current_networks.rs index a32bf354..9024770f 100644 --- a/cosmic-applet-network/src/network_manager/current_networks.rs +++ b/cosmic-applet-network/src/network_manager/current_networks.rs @@ -5,59 +5,29 @@ use cosmic_dbus_networkmanager::{ device::SpecificDevice, interface::enums::{ApFlags, ApSecurityFlags}, }; -use std::net::IpAddr; +use std::net::Ipv4Addr; pub async fn active_connections( active_connections: Vec>, ) -> zbus::Result> { let mut info = Vec::::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(); + if connection.vpn().await.unwrap_or_default() { - let mut ip_addresses = Vec::new(); - for address_data in connection - .ip4_config() - .await? - .address_data() - .await - .unwrap_or_default() - { - ip_addresses.push(IpAddr::V4(address_data.address)); - } - for address_data in connection - .ip6_config() - .await? - .address_data() - .await - .unwrap_or_default() - { - ip_addresses.push(IpAddr::V6(address_data.address)); - } info.push(ActiveConnectionInfo::Vpn { name: connection.id().await?, - ip_addresses, + ip_addresses: addresses.clone(), }); continue; } for device in connection.devices().await.unwrap_or_default() { - let mut ip_addresses = Vec::new(); - for address_data in connection - .ip4_config() - .await? - .address_data() - .await - .unwrap_or_default() - { - ip_addresses.push(IpAddr::V4(address_data.address)); - } - for address_data in connection - .ip6_config() - .await? - .address_data() - .await - .unwrap_or_default() - { - ip_addresses.push(IpAddr::V6(address_data.address)); - } match device .downcast_to_device() .await @@ -69,14 +39,14 @@ pub async fn active_connections( name: connection.id().await?, hw_address: wired_device.hw_address().await?, speed: wired_device.speed().await?, - ip_addresses, + 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, + ip_addresses: addresses.clone(), hw_address: wireless_device.hw_address().await?, flags: access_point.flags().await?, rsn_flags: access_point.rsn_flags().await?, @@ -87,7 +57,7 @@ pub async fn active_connections( Some(SpecificDevice::WireGuard(_)) => { info.push(ActiveConnectionInfo::Vpn { name: connection.id().await?, - ip_addresses, + ip_addresses: addresses.clone(), }); } _ => {} @@ -113,11 +83,11 @@ pub enum ActiveConnectionInfo { name: String, hw_address: String, speed: u32, - ip_addresses: Vec, + ip_addresses: Vec, }, WiFi { name: String, - ip_addresses: Vec, + ip_addresses: Vec, hw_address: String, flags: ApFlags, rsn_flags: ApSecurityFlags, @@ -125,7 +95,7 @@ pub enum ActiveConnectionInfo { }, Vpn { name: String, - ip_addresses: Vec, + ip_addresses: Vec, }, }