fix: make all subscriptions resistant to being restarted

many of the errors we've been seeing the last few days are because of subscriptions which are restarting
This commit is contained in:
Ashley Wulber 2024-01-18 21:02:35 -05:00 committed by Ashley Wulber
parent ebe688c747
commit d4e0dd8fb8
12 changed files with 184 additions and 138 deletions

30
Cargo.lock generated
View file

@ -768,6 +768,7 @@ dependencies = [
"serde",
"shlex",
"tokio",
"tracing",
"tracing-log",
"tracing-subscriber",
"url",
@ -971,6 +972,7 @@ dependencies = [
"nix 0.27.1",
"once_cell",
"rust-embed 6.8.1",
"tokio",
"tracing",
"tracing-log",
"tracing-subscriber",
@ -990,6 +992,7 @@ dependencies = [
[[package]]
name = "cosmic-config"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"atomicwrites",
"cosmic-config-derive",
@ -1007,6 +1010,7 @@ dependencies = [
[[package]]
name = "cosmic-config-derive"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"quote",
"syn 1.0.109",
@ -1094,7 +1098,7 @@ dependencies = [
[[package]]
name = "cosmic-text"
version = "0.10.0"
source = "git+https://github.com/pop-os/cosmic-text.git?branch=refactor#dd4c4cbbe2d5ed5046054b5361a6eeead50e0bb0"
source = "git+https://github.com/pop-os/cosmic-text.git#6aadfaddac7ae68c3f97c0b9b2fa75033374a650"
dependencies = [
"bitflags 2.4.2",
"fontdb",
@ -1106,6 +1110,7 @@ dependencies = [
"self_cell 1.0.3",
"swash",
"sys-locale",
"ttf-parser",
"unicode-bidi",
"unicode-linebreak",
"unicode-script",
@ -1115,6 +1120,7 @@ dependencies = [
[[package]]
name = "cosmic-theme"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"almost",
"cosmic-config",
@ -1128,6 +1134,7 @@ dependencies = [
[[package]]
name = "cosmic-time"
version = "0.4.0"
source = "git+https://github.com/pop-os/cosmic-time#4dc1fcec44aa7471a8e707fa391f9882d23250d7"
dependencies = [
"float-cmp",
"libcosmic",
@ -2242,8 +2249,8 @@ dependencies = [
[[package]]
name = "glyphon"
version = "0.3.0"
source = "git+https://github.com/jackpot51/glyphon.git?branch=refactor#c28dc99c86b6b598633e6623096b21632f266976"
version = "0.4.1"
source = "git+https://github.com/jackpot51/glyphon.git#abb70c0fda8cf1a5dfc314c1c778103d7ba951e6"
dependencies = [
"cosmic-text",
"etagere",
@ -2538,6 +2545,7 @@ dependencies = [
[[package]]
name = "iced"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"iced_accessibility",
"iced_core",
@ -2552,6 +2560,7 @@ dependencies = [
[[package]]
name = "iced_accessibility"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"accesskit",
"accesskit_unix",
@ -2560,6 +2569,7 @@ dependencies = [
[[package]]
name = "iced_core"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"bitflags 1.3.2",
"iced_accessibility",
@ -2577,6 +2587,7 @@ dependencies = [
[[package]]
name = "iced_futures"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"futures",
"iced_core",
@ -2589,6 +2600,7 @@ dependencies = [
[[package]]
name = "iced_graphics"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"bitflags 1.3.2",
"bytemuck",
@ -2611,6 +2623,7 @@ dependencies = [
[[package]]
name = "iced_renderer"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"iced_graphics",
"iced_tiny_skia",
@ -2623,6 +2636,7 @@ dependencies = [
[[package]]
name = "iced_runtime"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"iced_accessibility",
"iced_core",
@ -2634,6 +2648,7 @@ dependencies = [
[[package]]
name = "iced_sctk"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"enum-repr",
"float-cmp",
@ -2657,6 +2672,7 @@ dependencies = [
[[package]]
name = "iced_style"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"iced_core",
"once_cell",
@ -2666,6 +2682,7 @@ dependencies = [
[[package]]
name = "iced_tiny_skia"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"bytemuck",
"cosmic-text",
@ -2683,6 +2700,7 @@ dependencies = [
[[package]]
name = "iced_wgpu"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"bitflags 1.3.2",
"bytemuck",
@ -2702,6 +2720,7 @@ dependencies = [
[[package]]
name = "iced_widget"
version = "0.12.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"iced_renderer",
"iced_runtime",
@ -2957,6 +2976,7 @@ checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]]
name = "libcosmic"
version = "0.1.0"
source = "git+https://github.com/pop-os/libcosmic#994e93d6d2f90f947d56376094eb19877d708063"
dependencies = [
"apply",
"ashpd",
@ -3141,9 +3161,9 @@ dependencies = [
[[package]]
name = "lru"
version = "0.11.1"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21"
checksum = "2994eeba8ed550fd9b47a0b38f0242bc3344e496483c6180b69139cc2fa5d1d7"
dependencies = [
"hashbrown 0.14.3",
]

View file

@ -44,10 +44,10 @@ tracing-log = "0.2.0"
lto = "thin"
# lto = "fat"
[patch."https://github.com/pop-os/cosmic-time"]
cosmic-time = { path = "../cosmic-time" }
[patch."https://github.com/pop-os/libcosmic"]
libcosmic = { path = "../libcosmic" }
cosmic-config = { path = "../libcosmic/cosmic-config" }
# [patch."https://github.com/pop-os/cosmic-time"]
# cosmic-time = { path = "../cosmic-time" }
# [patch."https://github.com/pop-os/libcosmic"]
# libcosmic = { git = "https://github.com/pop-os/libcosmic//", branch = "refactor-config-watch" }
# cosmic-config = { git = "https://github.com/pop-os/libcosmic//", branch = "refactor-config-watch" }
[patch."https://github.com/Smithay/client-toolkit"]
sctk = { git = "https://github.com/smithay/client-toolkit//", package = "smithay-client-toolkit", rev = "e63ab5f" }

View file

@ -16,6 +16,7 @@ once_cell = "1.9"
xdg = "2.4"
tracing-subscriber.workspace = true
tracing-log.workspace = true
tracing.workspace = true
nix = "0.26"
shlex = "1.1.0"
anyhow = "1.0"

View file

@ -1122,7 +1122,7 @@ impl cosmic::Application for CosmicAppList {
fn subscription(&self) -> Subscription<Message> {
Subscription::batch(vec![
wayland_subscription(self.subscription_ctr).map(Message::Wayland),
wayland_subscription().map(Message::Wayland),
listen_with(|e, _| match e {
cosmic::iced_runtime::core::Event::PlatformSpecific(
event::PlatformSpecific::Wayland(event::wayland::Event::Seat(e, seat)),

View file

@ -11,29 +11,31 @@ use futures::{
channel::mpsc::{unbounded, UnboundedReceiver},
SinkExt, StreamExt,
};
use once_cell::sync::Lazy;
use std::{fmt::Debug, hash::Hash, thread::JoinHandle};
use tokio::sync::Mutex;
use crate::wayland_handler::wayland_handler;
pub fn wayland_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
id: I,
) -> iced::Subscription<WaylandUpdate> {
subscription::channel(id, 50, move |mut output| async move {
let mut state = State::Ready;
pub static WAYLAND_RX: Lazy<Mutex<Option<UnboundedReceiver<WaylandUpdate>>>> =
Lazy::new(|| Mutex::new(None));
loop {
state = start_listening(state, &mut output).await;
}
})
pub fn wayland_subscription() -> iced::Subscription<WaylandUpdate> {
subscription::channel(
std::any::TypeId::of::<WaylandUpdate>(),
50,
move |mut output| async move {
let mut state = State::Waiting;
loop {
state = start_listening(state, &mut output).await;
}
},
)
}
pub enum State {
Ready,
Waiting(
UnboundedReceiver<WaylandUpdate>,
calloop::channel::Sender<WaylandRequest>,
JoinHandle<()>,
),
Waiting,
Finished,
}
@ -42,28 +44,28 @@ async fn start_listening(
output: &mut futures::channel::mpsc::Sender<WaylandUpdate>,
) -> State {
match state {
State::Ready => {
let (calloop_tx, calloop_rx) = calloop::channel::channel();
let (toplevel_tx, toplevel_rx) = unbounded();
let handle = std::thread::spawn(move || {
wayland_handler(toplevel_tx, calloop_rx);
});
let tx = calloop_tx.clone();
_ = output.send(WaylandUpdate::Init(tx)).await;
State::Waiting(toplevel_rx, calloop_tx, handle)
}
State::Waiting(mut rx, tx, handle) => {
if handle.is_finished() {
_ = output.send(WaylandUpdate::Finished).await;
return State::Finished;
}
State::Waiting => {
let mut guard = WAYLAND_RX.lock().await;
let rx = {
if guard.is_none() {
let (calloop_tx, calloop_rx) = calloop::channel::channel();
let (toplevel_tx, toplevel_rx) = unbounded();
let _ = std::thread::spawn(move || {
wayland_handler(toplevel_tx, calloop_rx);
});
*guard = Some(toplevel_rx);
_ = output.send(WaylandUpdate::Init(calloop_tx)).await;
}
guard.as_mut().unwrap()
};
match rx.next().await {
Some(u) => {
_ = output.send(u).await;
State::Waiting(rx, tx, handle)
State::Waiting
}
None => {
_ = output.send(WaylandUpdate::Finished).await;
tracing::error!("Wayland handler thread died");
State::Finished
}
}

View file

@ -43,8 +43,7 @@ mod pulse;
const VERSION: &str = env!("CARGO_PKG_VERSION");
#[tokio::main(flavor = "current_thread")]
pub async fn main() -> cosmic::iced::Result {
pub fn main() -> cosmic::iced::Result {
tracing_subscriber::fmt::init();
let _ = tracing_log::LogTracer::init();

View file

@ -4,6 +4,7 @@ use std::{rc::Rc, thread};
extern crate libpulse_binding as pulse;
use cosmic::iced::{self, subscription};
use cosmic::iced_futures::futures::{self, SinkExt};
use cosmic_time::once_cell::sync::Lazy;
//use futures::channel::mpsc;
use libpulse_binding::{
callbacks::ListResult,
@ -16,6 +17,10 @@ use libpulse_binding::{
proplist::Proplist,
volume::ChannelVolumes,
};
use tokio::sync::{mpsc, Mutex};
pub static FROM_PULSE: Lazy<Mutex<Option<(mpsc::Receiver<Message>, mpsc::Sender<Message>)>>> =
Lazy::new(|| Mutex::new(None));
pub fn connect() -> iced::Subscription<Event> {
struct SomeWorker;
@ -24,7 +29,7 @@ pub fn connect() -> iced::Subscription<Event> {
std::any::TypeId::of::<SomeWorker>(),
50,
move |mut output| async move {
let mut state = State::Init;
let mut state = State::Connecting;
loop {
state = start_listening(state, &mut output).await;
@ -38,34 +43,50 @@ async fn start_listening(
output: &mut futures::channel::mpsc::Sender<Event>,
) -> State {
match state {
State::Init => {
let PulseHandle {
to_pulse,
from_pulse,
} = PulseHandle::new();
_ = output.send(Event::Init(Connection(to_pulse))).await;
State::Connecting(from_pulse)
}
// Waiting for Connection to succeed
State::Connecting(mut from_pulse) => match from_pulse.recv().await {
Some(Message::Connected) => {
_ = output.send(Event::Connected).await;
State::Connected(from_pulse)
}
Some(Message::Disconnected) => {
_ = output.send(Event::Disconnected).await;
State::Connecting => {
let mut guard = FROM_PULSE.lock().await;
let (from_pulse, to_pulse) = {
if guard.is_none() {
let PulseHandle {
to_pulse,
from_pulse,
} = PulseHandle::new();
_ = output.send(Event::Init(Connection(to_pulse.clone()))).await;
State::Connecting(from_pulse)
*guard = Some((from_pulse, to_pulse));
}
guard.as_mut().unwrap()
};
to_pulse
.send(Message::UpdateConnection)
.await
.expect("Failed to request connection update");
match from_pulse.recv().await {
Some(Message::Connected) => {
_ = output.send(Event::Connected).await;
State::Connected
}
Some(Message::Disconnected) => {
_ = output.send(Event::Disconnected).await;
State::Connecting
}
Some(m) => {
tracing::error!("Unexpected message: {:?}", m);
State::Connecting
}
None => {
panic!("Pulse Sender dropped, something has gone wrong!");
}
}
Some(m) => {
panic!("Unexpected message: {:?}", m);
}
None => {
panic!("Pulse Sender dropped, something has gone wrong!");
}
},
State::Connected(mut from_pulse) => {
}
State::Connected => {
let mut guard = FROM_PULSE.lock().await;
let Some((from_pulse, _)) = guard.as_mut() else {
return State::Connecting;
};
// This is where we match messages from the pulse server to pass to the gui
match from_pulse.recv().await {
Some(Message::SetSinks(sinks)) => {
@ -73,35 +94,35 @@ async fn start_listening(
.send(Event::MessageReceived(Message::SetSinks(sinks)))
.await;
State::Connected(from_pulse)
State::Connected
}
Some(Message::SetSources(sources)) => {
_ = output
.send(Event::MessageReceived(Message::SetSources(sources)))
.await;
State::Connected(from_pulse)
State::Connected
}
Some(Message::SetDefaultSink(sink)) => {
_ = output
.send(Event::MessageReceived(Message::SetDefaultSink(sink)))
.await;
State::Connected(from_pulse)
State::Connected
}
Some(Message::SetDefaultSource(source)) => {
_ = output
.send(Event::MessageReceived(Message::SetDefaultSource(source)))
.await;
State::Connected(from_pulse)
State::Connected
}
Some(Message::Disconnected) => {
_ = output.send(Event::Disconnected).await;
State::Connecting(from_pulse)
State::Connecting
}
None => {
_ = output.send(Event::Disconnected).await;
State::Connecting(from_pulse)
State::Connecting
}
_ => State::Connected(from_pulse),
_ => State::Connected,
}
}
}
@ -109,9 +130,8 @@ async fn start_listening(
// #[derive(Debug)]
enum State {
Init,
Connecting(tokio::sync::mpsc::Receiver<Message>),
Connected(tokio::sync::mpsc::Receiver<Message>),
Connecting,
Connected,
}
#[derive(Debug, Clone)]
@ -123,7 +143,7 @@ pub enum Event {
}
#[derive(Debug, Clone)]
pub struct Connection(tokio::sync::mpsc::Sender<Message>);
pub struct Connection(mpsc::Sender<Message>);
impl Connection {
pub fn send(&mut self, message: Message) {
@ -160,10 +180,7 @@ impl PulseHandle {
pub fn new() -> Self {
let (to_pulse, mut to_pulse_recv) = tokio::sync::mpsc::channel(10);
let (from_pulse_send, from_pulse) = tokio::sync::mpsc::channel(10);
// get initial connection status
to_pulse
.try_send(Message::UpdateConnection)
.expect("Failed to send initial connection update message");
// this thread should complete by pushing a completed message,
// or fail message. This should never complete/fail without pushing
// a message. This lets the iced subscription go to sleep while init
@ -197,7 +214,6 @@ impl PulseHandle {
.await
{
tracing::error!("ERROR! {}", err);
break;
}
}
Err(_) => Self::send_disconnected(&from_pulse_send).await,
@ -215,7 +231,6 @@ impl PulseHandle {
.await
{
tracing::error!("ERROR! {}", err);
break;
}
}
Err(e) => {
@ -235,7 +250,6 @@ impl PulseHandle {
from_pulse_send.send(Message::SetSinks(sinks)).await
{
tracing::error!("ERROR! {}", err);
break;
}
}
Err(_) => Self::send_disconnected(&from_pulse_send).await,
@ -252,7 +266,6 @@ impl PulseHandle {
from_pulse_send.send(Message::SetSources(sinks)).await
{
tracing::error!("ERROR! {}", err);
break;
}
}
Err(_) => Self::send_disconnected(&from_pulse_send).await,
@ -278,13 +291,13 @@ impl PulseHandle {
server.is_some()
);
if let Some(mut cur_server) = server.take() {
tracing::trace!("getting server info...");
if cur_server.get_server_info().is_err() {
tracing::warn!("got error, server must be disconnected...");
Self::send_disconnected(&from_pulse_send).await;
} else {
tracing::trace!("got server info, still connected...");
tracing::info!("got server info, still connected...");
server = Some(cur_server);
Self::send_connected(&from_pulse_send).await;
}
} else {
match PulseServer::connect().and_then(|server| server.init()) {
@ -298,6 +311,7 @@ impl PulseHandle {
"Failed to connect to server: {:?}",
err
);
Self::send_disconnected(&from_pulse_send).await;
}
}
}

View file

@ -15,6 +15,7 @@ use cosmic::iced::{
use cosmic::iced_core::alignment::Horizontal;
use cosmic::Command;
use cosmic::iced_futures::futures::executor::block_on;
use cosmic::iced_style::application;
use cosmic::iced_widget::{scrollable, Column};
@ -26,11 +27,11 @@ use cosmic_time::{anim, chain, id, once_cell::sync::Lazy, Instant, Timeline};
use std::borrow::Cow;
use std::collections::HashMap;
use std::path::PathBuf;
use subscriptions::notifications::NotificationsAppletProxy;
use tokio::sync::mpsc::Sender;
use tracing::info;
#[tokio::main(flavor = "current_thread")]
pub async fn main() -> cosmic::iced::Result {
pub fn main() -> cosmic::iced::Result {
tracing_subscriber::fmt::init();
let _ = tracing_log::LogTracer::init();
// Prepare i18n
@ -43,7 +44,6 @@ pub async fn main() -> cosmic::iced::Result {
static DO_NOT_DISTURB: Lazy<id::Toggler> = Lazy::new(id::Toggler::unique);
#[derive(Default)]
struct Notifications {
core: cosmic::app::Core,
config: NotificationsConfig,
@ -55,6 +55,7 @@ struct Notifications {
dbus_sender: Option<Sender<subscriptions::dbus::Input>>,
cards: Vec<(id::Cards, Vec<Notification>, bool, String, String, String)>,
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
proxy: NotificationsAppletProxy<'static>,
}
impl Notifications {
@ -132,7 +133,14 @@ impl cosmic::Application for Notifications {
core,
config_helper: helper,
config,
..Default::default()
icon_name: Default::default(),
popup: None,
timeline: Default::default(),
dbus_sender: Default::default(),
cards: Vec::new(),
token_tx: Default::default(),
proxy: block_on(crate::subscriptions::notifications::get_proxy())
.expect("Failed to get proxy"),
};
_self.update_icon();
(_self, Command::none())
@ -152,25 +160,20 @@ impl cosmic::Application for Notifications {
fn subscription(&self) -> Subscription<Message> {
Subscription::batch(vec![
config_subscription::<u64, NotificationsConfig>(
0,
cosmic_notifications_config::ID.into(),
NotificationsConfig::version(),
)
.map(|(_, res)| match res {
Ok(config) => Message::Config(config),
Err((errors, config)) => {
for err in errors {
self.core
.watch_config(cosmic_notifications_config::ID.into())
.map(|res| {
for err in res.errors {
tracing::error!("{:?}", err);
}
Message::Config(config)
}
}),
Message::Config(res.config)
}),
self.timeline
.as_subscription()
.map(|(_, now)| Message::Frame(now)),
subscriptions::dbus::proxy().map(Message::DbusEvent),
subscriptions::notifications::notifications().map(Message::NotificationEvent),
subscriptions::notifications::notifications(self.proxy.clone())
.map(Message::NotificationEvent),
activation_token_subscription(0).map(Message::Token),
])
}

View file

@ -22,7 +22,7 @@ pub enum State {
Finished,
}
pub fn notifications() -> Subscription<Notification> {
pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<Notification> {
struct SomeWorker;
subscription::channel(
@ -107,7 +107,7 @@ trait NotificationsApplet {
) -> zbus::Result<()>;
}
async fn get_proxy() -> anyhow::Result<NotificationsAppletProxy<'static>> {
pub async fn get_proxy() -> anyhow::Result<NotificationsAppletProxy<'static>> {
let raw_fd = std::env::var("COSMIC_NOTIFICATIONS")?;
let raw_fd = raw_fd.parse::<RawFd>()?;

View file

@ -16,6 +16,7 @@ once_cell = "1.9"
futures = "0.3.21"
xdg = "2.4.0"
anyhow = "1.0"
tokio = "1.35"
# Application i18n
i18n-embed = { version = "0.13.4", features = ["fluent-system", "desktop-requester"] }
i18n-embed-fl = "0.6.4"

View file

@ -222,7 +222,7 @@ impl cosmic::Application for IcedWorkspacesApplet {
fn subscription(&self) -> Subscription<Message> {
Subscription::batch(vec![
workspaces(0).map(Message::WorkspaceUpdate),
workspaces().map(Message::WorkspaceUpdate),
event::listen_with(|e, _| match e {
Mouse(mouse::Event::WheelScrolled { delta }) => Some(Message::WheelScrolled(delta)),
_ => None,

View file

@ -5,7 +5,11 @@ use cosmic::iced::{
futures::{channel::mpsc, SinkExt, StreamExt},
subscription,
};
use std::hash::Hash;
use once_cell::sync::Lazy;
use tokio::sync::Mutex;
pub static WAYLAND_RX: Lazy<Mutex<Option<mpsc::Receiver<WorkspaceList>>>> =
Lazy::new(|| Mutex::new(None));
#[derive(Debug, Clone)]
pub enum WorkspacesUpdate {
@ -14,16 +18,18 @@ pub enum WorkspacesUpdate {
Errored,
}
pub fn workspaces<I: 'static + Hash + Copy + Send + Sync>(
id: I,
) -> iced::Subscription<WorkspacesUpdate> {
subscription::channel(id, 50, move |mut output| async move {
let mut state = State::Ready;
pub fn workspaces() -> iced::Subscription<WorkspacesUpdate> {
subscription::channel(
std::any::TypeId::of::<WorkspacesUpdate>(),
50,
move |mut output| async move {
let mut state = State::Waiting;
loop {
state = start_listening(state, &mut output).await;
}
})
loop {
state = start_listening(state, &mut output).await;
}
},
)
}
async fn start_listening(
@ -31,22 +37,23 @@ async fn start_listening(
output: &mut futures::channel::mpsc::Sender<WorkspacesUpdate>,
) -> State {
match state {
State::Ready => {
if let Ok(watcher) = WorkspacesWatcher::new() {
_ = output
.send(WorkspacesUpdate::Started(watcher.get_sender()))
.await;
State::Waiting(watcher)
} else {
_ = output.send(WorkspacesUpdate::Errored).await;
State::Error
}
}
State::Waiting(mut t) => {
if let Some(w) = t.workspaces().await {
State::Waiting => {
let mut guard = WAYLAND_RX.lock().await;
let rx = {
if guard.is_none() {
if let Ok(WorkspacesWatcher { rx, tx }) = WorkspacesWatcher::new() {
*guard = Some(rx);
_ = output.send(WorkspacesUpdate::Started(tx)).await;
} else {
_ = output.send(WorkspacesUpdate::Errored).await;
return State::Error;
}
}
guard.as_mut().unwrap()
};
if let Some(w) = rx.next().await {
_ = output.send(WorkspacesUpdate::Workspaces(w)).await;
State::Waiting(t)
State::Waiting
} else {
_ = output.send(WorkspacesUpdate::Errored).await;
State::Error
@ -57,8 +64,7 @@ async fn start_listening(
}
pub enum State {
Ready,
Waiting(WorkspacesWatcher),
Waiting,
Error,
}