Reduce cpu usage and fix network monitor
This commit is contained in:
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -152,6 +152,19 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-channel"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e"
|
||||||
|
dependencies = [
|
||||||
|
"concurrent-queue",
|
||||||
|
"event-listener 3.0.1",
|
||||||
|
"event-listener-strategy",
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-executor"
|
name = "async-executor"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
@ -184,7 +197,7 @@ version = "2.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776"
|
checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel 1.9.0",
|
||||||
"async-executor",
|
"async-executor",
|
||||||
"async-io 1.13.0",
|
"async-io 1.13.0",
|
||||||
"async-lock 2.8.0",
|
"async-lock 2.8.0",
|
||||||
@ -305,7 +318,7 @@ version = "1.12.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
|
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel 1.9.0",
|
||||||
"async-global-executor",
|
"async-global-executor",
|
||||||
"async-io 1.13.0",
|
"async-io 1.13.0",
|
||||||
"async-lock 2.8.0",
|
"async-lock 2.8.0",
|
||||||
@ -408,7 +421,7 @@ version = "1.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a"
|
checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel 1.9.0",
|
||||||
"async-lock 2.8.0",
|
"async-lock 2.8.0",
|
||||||
"async-task",
|
"async-task",
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
@ -1711,6 +1724,7 @@ version = "0.1.1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ashpd",
|
"ashpd",
|
||||||
|
"async-channel 2.1.0",
|
||||||
"capnp 0.18.3",
|
"capnp 0.18.3",
|
||||||
"capnp-rpc",
|
"capnp-rpc",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -1735,7 +1749,6 @@ name = "ntfy-daemon"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ashpd",
|
|
||||||
"capnp 0.18.3",
|
"capnp 0.18.3",
|
||||||
"capnp-rpc",
|
"capnp-rpc",
|
||||||
"capnpc",
|
"capnpc",
|
||||||
|
|||||||
@ -31,4 +31,5 @@ rand = "0.8.5"
|
|||||||
ureq = "2.7.1"
|
ureq = "2.7.1"
|
||||||
futures = "0.3.0"
|
futures = "0.3.0"
|
||||||
ashpd = "0.6.0"
|
ashpd = "0.6.0"
|
||||||
|
async-channel = "2.1.0"
|
||||||
relm4-macros = { version = "0.6.2", features = [], default-features = false }
|
relm4-macros = { version = "0.6.2", features = [], default-features = false }
|
||||||
|
|||||||
@ -24,7 +24,6 @@ rusqlite = "0.29.0"
|
|||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
reqwest = { version = "0.11.18", features = ["stream", "rustls-tls"]}
|
reqwest = { version = "0.11.18", features = ["stream", "rustls-tls"]}
|
||||||
url = "2.4.0"
|
url = "2.4.0"
|
||||||
ashpd = "0.6.0"
|
|
||||||
generational-arena = "0.2.9"
|
generational-arena = "0.2.9"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
thiserror = "1.0.49"
|
thiserror = "1.0.49"
|
||||||
|
|||||||
@ -14,7 +14,7 @@ pub struct SharedEnv {
|
|||||||
db: message_repo::Db,
|
db: message_repo::Db,
|
||||||
proxy: Arc<dyn models::NotificationProxy>,
|
proxy: Arc<dyn models::NotificationProxy>,
|
||||||
http: reqwest::Client,
|
http: reqwest::Client,
|
||||||
network: Arc<ashpd::desktop::network_monitor::NetworkMonitor<'static>>,
|
network: Arc<dyn models::NetworkMonitorProxy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::pin::Pin;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
use futures::stream::Stream;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -316,3 +318,7 @@ pub struct Notification {
|
|||||||
pub trait NotificationProxy: Sync + Send {
|
pub trait NotificationProxy: Sync + Send {
|
||||||
fn send(&self, n: Notification) -> anyhow::Result<()>;
|
fn send(&self, n: Notification) -> anyhow::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait NetworkMonitorProxy: Sync + Send {
|
||||||
|
fn listen(&self) -> Pin<Box<dyn Stream<Item = ()>>>;
|
||||||
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ use std::sync::Arc;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{collections::HashMap, hash::Hash};
|
use std::{collections::HashMap, hash::Hash};
|
||||||
|
|
||||||
use ashpd::desktop::network_monitor::NetworkMonitor;
|
|
||||||
use capnp::capability::Promise;
|
use capnp::capability::Promise;
|
||||||
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, RpcSystem};
|
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, RpcSystem};
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
@ -343,7 +342,7 @@ impl SystemNotifier {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
dbpath: &str,
|
dbpath: &str,
|
||||||
notification_proxy: Arc<dyn models::NotificationProxy>,
|
notification_proxy: Arc<dyn models::NotificationProxy>,
|
||||||
network: Arc<NetworkMonitor<'static>>,
|
network: Arc<dyn models::NetworkMonitorProxy>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
watching: Rc::new(RefCell::new(HashMap::new())),
|
watching: Rc::new(RefCell::new(HashMap::new())),
|
||||||
@ -457,12 +456,12 @@ pub fn start(
|
|||||||
socket_path: std::path::PathBuf,
|
socket_path: std::path::PathBuf,
|
||||||
dbpath: &str,
|
dbpath: &str,
|
||||||
notification_proxy: Arc<dyn models::NotificationProxy>,
|
notification_proxy: Arc<dyn models::NotificationProxy>,
|
||||||
|
network_proxy: Arc<dyn models::NetworkMonitorProxy>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let rt = tokio::runtime::Builder::new_current_thread()
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
let network_monitor = rt.block_on(async move { NetworkMonitor::new().await.unwrap() });
|
|
||||||
let listener = rt.block_on(async move {
|
let listener = rt.block_on(async move {
|
||||||
let _ = std::fs::remove_file(&socket_path);
|
let _ = std::fs::remove_file(&socket_path);
|
||||||
UnixListener::bind(&socket_path).unwrap()
|
UnixListener::bind(&socket_path).unwrap()
|
||||||
@ -471,8 +470,7 @@ pub fn start(
|
|||||||
let dbpath = dbpath.to_owned();
|
let dbpath = dbpath.to_owned();
|
||||||
let f = move || {
|
let f = move || {
|
||||||
let local = tokio::task::LocalSet::new();
|
let local = tokio::task::LocalSet::new();
|
||||||
let mut system_notifier =
|
let mut system_notifier = SystemNotifier::new(&dbpath, notification_proxy, network_proxy);
|
||||||
SystemNotifier::new(&dbpath, notification_proxy, Arc::new(network_monitor));
|
|
||||||
local.spawn_local(async move {
|
local.spawn_local(async move {
|
||||||
system_notifier.watch_subscribed().await.unwrap();
|
system_notifier.watch_subscribed().await.unwrap();
|
||||||
let system_client: system_notifier::Client = capnp_rpc::new_client(system_notifier);
|
let system_client: system_notifier::Client = capnp_rpc::new_client(system_notifier);
|
||||||
|
|||||||
@ -2,7 +2,6 @@ use std::ops::ControlFlow;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use ashpd::desktop::network_monitor::NetworkMonitor;
|
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use reqwest::header::HeaderValue;
|
use reqwest::header::HeaderValue;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -141,21 +140,14 @@ impl TopicListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn reload_on_network_change(
|
async fn reload_on_network_change(
|
||||||
monitor: Arc<NetworkMonitor<'static>>,
|
monitor: Arc<dyn models::NetworkMonitorProxy>,
|
||||||
tx: mpsc::Sender<ControlFlow<()>>,
|
tx: mpsc::Sender<ControlFlow<()>>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut prev_available = false;
|
let mut m = monitor.listen();
|
||||||
|
while let Some(_) = m.next().await {
|
||||||
loop {
|
tx.send(ControlFlow::Continue(())).await?;
|
||||||
let _ = monitor.receive_changed().await?;
|
|
||||||
let available = monitor.is_available().await?;
|
|
||||||
if available && !prev_available {
|
|
||||||
if let Err(e) = tx.send(ControlFlow::Continue(())).await {
|
|
||||||
return Err(e.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prev_available = available;
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_current_status(&mut self) -> impl Future<Output = anyhow::Result<()>> {
|
fn send_current_status(&mut self) -> impl Future<Output = anyhow::Result<()>> {
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use capnp_rpc::{rpc_twoparty_capnp, twoparty, RpcSystem};
|
use capnp_rpc::{rpc_twoparty_capnp, twoparty, RpcSystem};
|
||||||
|
use futures::stream::Stream;
|
||||||
use futures::AsyncReadExt;
|
use futures::AsyncReadExt;
|
||||||
use gettextrs::gettext;
|
use gettextrs::gettext;
|
||||||
use gio::SocketClient;
|
use gio::SocketClient;
|
||||||
@ -242,6 +246,11 @@ impl NotifyApplication {
|
|||||||
let dbpath = glib::user_data_dir().join("com.ranfdev.Notify.sqlite");
|
let dbpath = glib::user_data_dir().join("com.ranfdev.Notify.sqlite");
|
||||||
info!(database_path = %dbpath.display());
|
info!(database_path = %dbpath.display());
|
||||||
|
|
||||||
|
// Here I'm sending notifications to the desktop environment and listening for network changes.
|
||||||
|
// This should have been inside ntfy-daemon, but using portals from another thread causes the error
|
||||||
|
// `Invalid client serial` and it's broken.
|
||||||
|
// Until https://github.com/flatpak/xdg-dbus-proxy/issues/46 is solved, I have to handle these things
|
||||||
|
// in the main thread. Uff.
|
||||||
let (tx, rx) = glib::MainContext::channel(Default::default());
|
let (tx, rx) = glib::MainContext::channel(Default::default());
|
||||||
let app = self.clone();
|
let app = self.clone();
|
||||||
rx.attach(None, move |n: models::Notification| {
|
rx.attach(None, move |n: models::Notification| {
|
||||||
@ -268,17 +277,39 @@ impl NotifyApplication {
|
|||||||
glib::ControlFlow::Continue
|
glib::ControlFlow::Continue
|
||||||
});
|
});
|
||||||
|
|
||||||
struct Proxy(glib::Sender<models::Notification>);
|
struct Proxies {
|
||||||
impl models::NotificationProxy for Proxy {
|
notification: glib::Sender<models::Notification>,
|
||||||
|
}
|
||||||
|
impl models::NotificationProxy for Proxies {
|
||||||
fn send(&self, n: models::Notification) -> anyhow::Result<()> {
|
fn send(&self, n: models::Notification) -> anyhow::Result<()> {
|
||||||
self.0.send(n)?;
|
self.notification.send(n)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl models::NetworkMonitorProxy for Proxies {
|
||||||
|
fn listen(&self) -> Pin<Box<dyn Stream<Item = ()>>> {
|
||||||
|
let (tx, rx) = async_channel::bounded(1);
|
||||||
|
let mut prev_available = Rc::new(Cell::new(false));
|
||||||
|
|
||||||
|
gio::NetworkMonitor::default().connect_network_changed(move |_, available| {
|
||||||
|
dbg!("sent", available);
|
||||||
|
if available && !prev_available.get() {
|
||||||
|
if let Err(e) = tx.send_blocking(()) {
|
||||||
|
warn!(error = %e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_available.replace(available);
|
||||||
|
});
|
||||||
|
|
||||||
|
Box::pin(rx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let proxies = std::sync::Arc::new(Proxies { notification: tx });
|
||||||
ntfy_daemon::system_client::start(
|
ntfy_daemon::system_client::start(
|
||||||
socket_path.to_owned(),
|
socket_path.to_owned(),
|
||||||
dbpath.to_str().unwrap(),
|
dbpath.to_str().unwrap(),
|
||||||
std::sync::Arc::new(Proxy(tx)),
|
proxies.clone(),
|
||||||
|
proxies,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.imp().hold_guard.set(self.hold()).unwrap();
|
self.imp().hold_guard.set(self.hold()).unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user