refactor(network): use channel subscriptions
This commit is contained in:
parent
fad3b097d9
commit
4b9f46b388
5 changed files with 154 additions and 204 deletions
|
|
@ -725,8 +725,7 @@ impl Application for CosmicNetworkApplet {
|
|||
}
|
||||
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
let network_sub =
|
||||
network_manager_subscription(0).map(|e| Message::NetworkManagerEvent(e.1));
|
||||
let network_sub = network_manager_subscription(0).map(|e| Message::NetworkManagerEvent(e));
|
||||
let timeline = self
|
||||
.timeline
|
||||
.as_subscription()
|
||||
|
|
@ -737,11 +736,9 @@ impl Application for CosmicNetworkApplet {
|
|||
self.applet_helper.theme_subscription(0).map(Message::Theme),
|
||||
timeline,
|
||||
network_sub,
|
||||
active_conns_subscription(0, conn.clone())
|
||||
.map(|e| Message::NetworkManagerEvent(e.1)),
|
||||
devices_subscription(0, conn.clone()).map(|e| Message::NetworkManagerEvent(e.1)),
|
||||
wireless_enabled_subscription(0, conn.clone())
|
||||
.map(|e| Message::NetworkManagerEvent(e.1)),
|
||||
active_conns_subscription(0, conn.clone()).map(Message::NetworkManagerEvent),
|
||||
devices_subscription(0, conn.clone()).map(Message::NetworkManagerEvent),
|
||||
wireless_enabled_subscription(0, conn.clone()).map(Message::NetworkManagerEvent),
|
||||
])
|
||||
} else {
|
||||
Subscription::batch(vec![timeline, network_sub])
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::{NetworkManagerEvent, NetworkManagerState};
|
||||
use cosmic::iced::{self, subscription};
|
||||
use cosmic_dbus_networkmanager::nm::NetworkManager;
|
||||
use futures::StreamExt;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::error;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
|
@ -10,13 +10,14 @@ use zbus::Connection;
|
|||
pub fn active_conns_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||
id: I,
|
||||
conn: Connection,
|
||||
) -> iced::Subscription<(I, NetworkManagerEvent)> {
|
||||
subscription::unfold(id, State::Continue(conn), move |mut state| async move {
|
||||
loop {
|
||||
let (update, new_state) = start_listening(id, state).await;
|
||||
state = new_state;
|
||||
if let Some(update) = update {
|
||||
return (update, state);
|
||||
) -> iced::Subscription<NetworkManagerEvent> {
|
||||
let initial = State::Continue(conn.clone());
|
||||
subscription::channel(id, 50, move |mut output| {
|
||||
let mut state = initial.clone();
|
||||
|
||||
async move {
|
||||
loop {
|
||||
state = start_listening(state, &mut output).await;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -28,10 +29,10 @@ pub enum State {
|
|||
Error,
|
||||
}
|
||||
|
||||
async fn start_listening<I: Copy + Debug>(
|
||||
id: I,
|
||||
async fn start_listening(
|
||||
state: State,
|
||||
) -> (Option<(I, NetworkManagerEvent)>, State) {
|
||||
output: &mut futures::channel::mpsc::Sender<NetworkManagerEvent>,
|
||||
) -> State {
|
||||
let conn = match state {
|
||||
State::Continue(conn) => conn,
|
||||
State::Error => iced::futures::future::pending().await,
|
||||
|
|
@ -40,7 +41,7 @@ async fn start_listening<I: Copy + Debug>(
|
|||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
error!("Failed to connect to NetworkManager: {}", e);
|
||||
return (None, State::Error);
|
||||
return State::Error;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -49,8 +50,8 @@ async fn start_listening<I: Copy + Debug>(
|
|||
|
||||
let new_state = NetworkManagerState::new(&conn).await.unwrap_or_default();
|
||||
|
||||
(
|
||||
Some((id, NetworkManagerEvent::ActiveConns(new_state))),
|
||||
State::Continue(conn),
|
||||
)
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::ActiveConns(new_state))
|
||||
.await;
|
||||
State::Continue(conn)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::{NetworkManagerEvent, NetworkManagerState};
|
||||
use cosmic::iced::{self, subscription};
|
||||
use cosmic_dbus_networkmanager::nm::NetworkManager;
|
||||
use futures::StreamExt;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::error;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
|
@ -10,13 +10,14 @@ use zbus::Connection;
|
|||
pub fn devices_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||
id: I,
|
||||
conn: Connection,
|
||||
) -> iced::Subscription<(I, NetworkManagerEvent)> {
|
||||
subscription::unfold(id, State::Continue(conn), move |mut state| async move {
|
||||
loop {
|
||||
let (update, new_state) = start_listening(id, state).await;
|
||||
state = new_state;
|
||||
if let Some(update) = update {
|
||||
return (update, state);
|
||||
) -> iced::Subscription<NetworkManagerEvent> {
|
||||
let initial = State::Continue(conn.clone());
|
||||
subscription::channel(id, 50, move |mut output| {
|
||||
let mut state = initial.clone();
|
||||
|
||||
async move {
|
||||
loop {
|
||||
state = start_listening(state, &mut output).await;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -28,10 +29,10 @@ pub enum State {
|
|||
Error,
|
||||
}
|
||||
|
||||
async fn start_listening<I: Copy + Debug>(
|
||||
id: I,
|
||||
async fn start_listening(
|
||||
state: State,
|
||||
) -> (Option<(I, NetworkManagerEvent)>, State) {
|
||||
output: &mut futures::channel::mpsc::Sender<NetworkManagerEvent>,
|
||||
) -> State {
|
||||
let conn = match state {
|
||||
State::Continue(conn) => conn,
|
||||
State::Error => iced::futures::future::pending().await,
|
||||
|
|
@ -40,7 +41,7 @@ async fn start_listening<I: Copy + Debug>(
|
|||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
error!("Failed to connect to NetworkManager: {}", e);
|
||||
return (None, State::Error);
|
||||
return State::Error;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -48,9 +49,8 @@ async fn start_listening<I: Copy + Debug>(
|
|||
devices_changed.next().await;
|
||||
|
||||
let new_state = NetworkManagerState::new(&conn).await.unwrap_or_default();
|
||||
|
||||
(
|
||||
Some((id, NetworkManagerEvent::WirelessAccessPoints(new_state))),
|
||||
State::Continue(conn),
|
||||
)
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::WirelessAccessPoints(new_state))
|
||||
.await;
|
||||
State::Continue(conn)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ pub mod current_networks;
|
|||
pub mod devices;
|
||||
pub mod wireless_enabled;
|
||||
|
||||
use std::{collections::HashMap, fmt::Debug, hash::Hash, ops::Deref, time::Duration};
|
||||
use std::{collections::HashMap, fmt::Debug, ops::Deref, time::Duration};
|
||||
|
||||
use cosmic::iced::{self, subscription};
|
||||
use cosmic_dbus_networkmanager::{
|
||||
|
|
@ -19,7 +19,7 @@ use cosmic_dbus_networkmanager::{
|
|||
};
|
||||
use futures::{
|
||||
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
|
||||
StreamExt,
|
||||
SinkExt, StreamExt,
|
||||
};
|
||||
use tokio::{process::Command, time::timeout};
|
||||
use zbus::{
|
||||
|
|
@ -32,14 +32,6 @@ use self::{
|
|||
current_networks::{active_connections, ActiveConnectionInfo},
|
||||
};
|
||||
|
||||
pub fn network_manager_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||
id: I,
|
||||
) -> iced::Subscription<(I, NetworkManagerEvent)> {
|
||||
subscription::unfold(id, State::Ready, move |state| {
|
||||
start_listening_loop(id, state)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum State {
|
||||
Ready,
|
||||
|
|
@ -47,51 +39,52 @@ pub enum State {
|
|||
Finished,
|
||||
}
|
||||
|
||||
pub async fn start_listening_loop<I: Copy + Debug>(
|
||||
pub fn network_manager_subscription<I: Copy + Debug + std::hash::Hash + 'static>(
|
||||
id: I,
|
||||
mut state: State,
|
||||
) -> ((I, NetworkManagerEvent), State) {
|
||||
loop {
|
||||
let (update, new_state) = start_listening(id, state).await;
|
||||
state = new_state;
|
||||
if let Some(update) = update {
|
||||
return (update, state);
|
||||
) -> iced::Subscription<NetworkManagerEvent> {
|
||||
subscription::channel(id, 50, |mut output| async move {
|
||||
let mut state = State::Ready;
|
||||
|
||||
loop {
|
||||
state = start_listening(state, &mut output).await;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn start_listening<I: Copy + Debug>(
|
||||
id: I,
|
||||
async fn start_listening(
|
||||
state: State,
|
||||
) -> (Option<(I, NetworkManagerEvent)>, State) {
|
||||
output: &mut futures::channel::mpsc::Sender<NetworkManagerEvent>,
|
||||
) -> State {
|
||||
match state {
|
||||
State::Ready => {
|
||||
let conn = match Connection::system().await {
|
||||
Ok(c) => c,
|
||||
Err(_) => return (None, State::Finished),
|
||||
Err(_) => return State::Finished,
|
||||
};
|
||||
|
||||
let (tx, rx) = unbounded();
|
||||
let nm_state = NetworkManagerState::new(&conn).await.unwrap_or_default();
|
||||
return (
|
||||
Some((
|
||||
id,
|
||||
NetworkManagerEvent::Init {
|
||||
conn: conn.clone(),
|
||||
sender: tx,
|
||||
state: nm_state,
|
||||
},
|
||||
)),
|
||||
State::Waiting(conn, rx),
|
||||
);
|
||||
if output
|
||||
.send(NetworkManagerEvent::Init {
|
||||
conn: conn.clone(),
|
||||
sender: tx,
|
||||
state: nm_state,
|
||||
})
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
State::Waiting(conn, rx)
|
||||
} else {
|
||||
State::Finished
|
||||
}
|
||||
}
|
||||
State::Waiting(conn, mut rx) => {
|
||||
let network_manager = match NetworkManager::new(&conn).await {
|
||||
Ok(n) => n,
|
||||
Err(_) => return (None, State::Finished),
|
||||
Err(_) => return State::Finished,
|
||||
};
|
||||
|
||||
let (update, should_exit) = match rx.next().await {
|
||||
match rx.next().await {
|
||||
Some(NetworkManagerRequest::Disconnect(ssid)) => {
|
||||
let mut success = false;
|
||||
for c in network_manager
|
||||
|
|
@ -125,18 +118,13 @@ async fn start_listening<I: Copy + Debug>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
Some((
|
||||
id,
|
||||
NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Disconnect(ssid.clone()),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
},
|
||||
)),
|
||||
false,
|
||||
)
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Disconnect(ssid.clone()),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
Some(NetworkManagerRequest::SetAirplaneMode(airplane_mode)) => {
|
||||
// wifi
|
||||
|
|
@ -152,12 +140,13 @@ async fn start_listening<I: Copy + Debug>(
|
|||
.output()
|
||||
.await
|
||||
.is_ok();
|
||||
let response = NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::SetAirplaneMode(airplane_mode),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
};
|
||||
(Some((id, response)), false)
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::SetAirplaneMode(airplane_mode),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
Some(NetworkManagerRequest::SetWiFi(enabled)) => {
|
||||
let success = network_manager.set_wireless_enabled(enabled).await.is_ok();
|
||||
|
|
@ -166,15 +155,15 @@ async fn start_listening<I: Copy + Debug>(
|
|||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
};
|
||||
(Some((id, response)), false)
|
||||
_ = output.send(response).await;
|
||||
}
|
||||
Some(NetworkManagerRequest::Password(ssid, password)) => {
|
||||
let s = match NetworkManagerSettings::new(&conn).await {
|
||||
Ok(s) => s,
|
||||
Err(_) => return (None, State::Finished),
|
||||
Err(_) => return State::Finished,
|
||||
};
|
||||
|
||||
let mut status = (None, false);
|
||||
let mut status: Option<NetworkManagerEvent> = None;
|
||||
|
||||
// First try known connections
|
||||
// TODO more convenient methods of managing settings
|
||||
|
|
@ -268,22 +257,16 @@ async fn start_listening<I: Copy + Debug>(
|
|||
} else {
|
||||
false
|
||||
};
|
||||
status = (
|
||||
Some((
|
||||
id,
|
||||
NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Password(
|
||||
ssid.clone(),
|
||||
password.clone(),
|
||||
),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn)
|
||||
.await
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
)),
|
||||
false,
|
||||
);
|
||||
status = Some(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Password(
|
||||
ssid.clone(),
|
||||
password.clone(),
|
||||
),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn)
|
||||
.await
|
||||
.unwrap_or_default(),
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -291,7 +274,7 @@ async fn start_listening<I: Copy + Debug>(
|
|||
}
|
||||
|
||||
// create a connection
|
||||
if status.0.is_none() {
|
||||
if status.is_none() {
|
||||
for device in network_manager.devices().await.ok().unwrap_or_default() {
|
||||
if matches!(
|
||||
device.device_type().await.unwrap_or(DeviceType::Other),
|
||||
|
|
@ -368,53 +351,42 @@ async fn start_listening<I: Copy + Debug>(
|
|||
} else {
|
||||
false
|
||||
};
|
||||
status = (
|
||||
Some((
|
||||
id,
|
||||
NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Password(
|
||||
ssid.clone(),
|
||||
password.clone(),
|
||||
),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn)
|
||||
.await
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
)),
|
||||
false,
|
||||
);
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Password(
|
||||
ssid.clone(),
|
||||
password.clone(),
|
||||
),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn)
|
||||
.await
|
||||
.unwrap_or_default(),
|
||||
})
|
||||
.await;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if status.0.is_none() {
|
||||
status = (
|
||||
Some((
|
||||
id,
|
||||
NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Password(ssid, password),
|
||||
success: false,
|
||||
state: NetworkManagerState::new(&conn)
|
||||
.await
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
)),
|
||||
false,
|
||||
);
|
||||
if let Some(e) = status {
|
||||
_ = output.send(e).await;
|
||||
} else {
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Password(ssid, password),
|
||||
success: false,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
status
|
||||
}
|
||||
Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => {
|
||||
let s = match NetworkManagerSettings::new(&conn).await {
|
||||
Ok(s) => s,
|
||||
Err(_) => return (None, State::Finished),
|
||||
Err(_) => return State::Finished,
|
||||
};
|
||||
// find known connection with matching ssid and activate
|
||||
let mut status = (None, false);
|
||||
|
||||
for c in s.list_connections().await.unwrap_or_default() {
|
||||
let settings = match c.get_settings().await.ok() {
|
||||
|
|
@ -472,50 +444,30 @@ async fn start_listening<I: Copy + Debug>(
|
|||
} else {
|
||||
false
|
||||
};
|
||||
status = (
|
||||
Some((
|
||||
id,
|
||||
NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn)
|
||||
.await
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
)),
|
||||
false,
|
||||
);
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
})
|
||||
.await;
|
||||
|
||||
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
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()),
|
||||
success: false,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
_ => {
|
||||
return State::Finished;
|
||||
}
|
||||
None => (None, true),
|
||||
};
|
||||
(
|
||||
update,
|
||||
if should_exit {
|
||||
State::Finished
|
||||
} else {
|
||||
State::Waiting(conn, rx)
|
||||
},
|
||||
)
|
||||
|
||||
State::Waiting(conn, rx)
|
||||
}
|
||||
State::Finished => iced::futures::future::pending().await,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::{NetworkManagerEvent, NetworkManagerState};
|
||||
use cosmic::iced::{self, subscription};
|
||||
use cosmic_dbus_networkmanager::nm::NetworkManager;
|
||||
use futures::StreamExt;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::error;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
|
@ -10,13 +10,14 @@ use zbus::Connection;
|
|||
pub fn wireless_enabled_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||
id: I,
|
||||
conn: Connection,
|
||||
) -> iced::Subscription<(I, NetworkManagerEvent)> {
|
||||
subscription::unfold(id, State::Continue(conn), move |mut state| async move {
|
||||
loop {
|
||||
let (update, new_state) = start_listening(id, state).await;
|
||||
state = new_state;
|
||||
if let Some(update) = update {
|
||||
return (update, state);
|
||||
) -> iced::Subscription<NetworkManagerEvent> {
|
||||
let initial = State::Continue(conn.clone());
|
||||
subscription::channel(id, 50, move |mut output| {
|
||||
let mut state = initial.clone();
|
||||
|
||||
async move {
|
||||
loop {
|
||||
state = start_listening(state, &mut output).await;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -28,10 +29,10 @@ pub enum State {
|
|||
Error,
|
||||
}
|
||||
|
||||
async fn start_listening<I: Copy + Debug>(
|
||||
id: I,
|
||||
async fn start_listening(
|
||||
state: State,
|
||||
) -> (Option<(I, NetworkManagerEvent)>, State) {
|
||||
output: &mut futures::channel::mpsc::Sender<NetworkManagerEvent>,
|
||||
) -> State {
|
||||
let conn = match state {
|
||||
State::Continue(conn) => conn,
|
||||
State::Error => iced::futures::future::pending().await,
|
||||
|
|
@ -40,7 +41,7 @@ async fn start_listening<I: Copy + Debug>(
|
|||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
error!("Failed to connect to NetworkManager: {}", e);
|
||||
return (None, State::Error);
|
||||
return State::Error;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -48,9 +49,8 @@ async fn start_listening<I: Copy + Debug>(
|
|||
wireless_enabled_changed.next().await;
|
||||
|
||||
let new_state = NetworkManagerState::new(&conn).await.unwrap_or_default();
|
||||
|
||||
(
|
||||
Some((id, NetworkManagerEvent::WiFiEnabled(new_state))),
|
||||
State::Continue(conn),
|
||||
)
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::WiFiEnabled(new_state))
|
||||
.await;
|
||||
State::Continue(conn)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue