Skip to content

Commit c8519d3

Browse files
authored
Merge pull request locainin#13 from locainin/dev
see here: locainin#13 (comment)
2 parents 8112b18 + cb0bcf2 commit c8519d3

14 files changed

Lines changed: 901 additions & 189 deletions

File tree

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,47 @@
11
//! D-Bus command execution for noticenterctl.
22
3-
use anyhow::Result;
3+
use std::future::Future;
4+
use std::time::Duration;
5+
6+
use anyhow::{anyhow, Result};
47
use unixnotis_core::{util, ControlProxy};
58

69
use crate::cli_args::{Command, DndState};
710
use crate::main_log_follow::follow_debug_logs;
811
use crate::main_output::{print_inhibitors, print_notifications};
912

13+
const CONTROL_CALL_TIMEOUT: Duration = Duration::from_secs(5);
14+
1015
pub(crate) async fn handle_command(proxy: &ControlProxy<'_>, command: Command) -> Result<()> {
1116
// CLI forwards work to the daemon
1217
match command {
1318
Command::TogglePanel => {
1419
// Simple toggle keeps the daemon in control of its own visibility rules.
15-
proxy.toggle_panel().await?;
20+
run_control_call(proxy.toggle_panel()).await?;
1621
}
1722
Command::OpenPanel { debug } => {
1823
// Debug mode opens the panel and streams daemon logs for real-time triage.
1924
if let Some(level) = debug {
20-
proxy.open_panel_debug(level.into()).await?;
25+
run_control_call(proxy.open_panel_debug(level.into())).await?;
2126
// Panel open should still succeed when journal follow is unavailable.
2227
if let Err(err) = follow_debug_logs() {
2328
eprintln!("debug log follow unavailable: {err}");
2429
}
2530
} else {
26-
proxy.open_panel().await?;
31+
run_control_call(proxy.open_panel()).await?;
2732
}
2833
}
2934
Command::ClosePanel => {
3035
// Explicit close avoids accidental toggles when the panel is hidden.
31-
proxy.close_panel().await?;
36+
run_control_call(proxy.close_panel()).await?;
3237
}
3338
Command::Clear => {
3439
// Clear removes both active notifications and history entries.
35-
proxy.clear_all().await?;
40+
run_control_call(proxy.clear_all()).await?;
3641
}
3742
Command::Dismiss { id } => {
3843
// Dismiss targets a single notification by id.
39-
proxy.dismiss(id).await?;
44+
run_control_call(proxy.dismiss(id)).await?;
4045
}
4146
Command::ListActive { full } => {
4247
// Full output needs the debug gate
@@ -45,7 +50,7 @@ pub(crate) async fn handle_command(proxy: &ControlProxy<'_>, command: Command) -
4550
// Fall back to the safe view
4651
eprintln!("--full requires UNIXNOTIS_DIAGNOSTIC=1; using redacted output");
4752
}
48-
let notifications = proxy.list_active().await?;
53+
let notifications = run_control_call(proxy.list_active()).await?;
4954
// Shared output helper
5055
print_notifications("active", &notifications, allow_full);
5156
}
@@ -55,34 +60,34 @@ pub(crate) async fn handle_command(proxy: &ControlProxy<'_>, command: Command) -
5560
if full && !util::diagnostic_mode() {
5661
eprintln!("--full requires UNIXNOTIS_DIAGNOSTIC=1; using redacted output");
5762
}
58-
let notifications = proxy.list_history().await?;
63+
let notifications = run_control_call(proxy.list_history()).await?;
5964
print_notifications("history", &notifications, allow_full);
6065
}
6166
Command::Dnd { state } => match state {
6267
DndState::On => {
6368
// Explicit enable avoids ambiguous scripts.
64-
proxy.set_dnd(true).await?;
69+
run_control_call(proxy.set_dnd(true)).await?;
6570
}
6671
DndState::Off => {
6772
// Explicit disable avoids ambiguous scripts.
68-
proxy.set_dnd(false).await?;
73+
run_control_call(proxy.set_dnd(false)).await?;
6974
}
7075
DndState::Toggle => {
7176
// Toggle must happen atomically in the daemon to avoid read-modify-write races.
72-
proxy.toggle_dnd().await?;
77+
run_control_call(proxy.toggle_dnd()).await?;
7378
}
7479
},
7580
Command::Inhibit { reason, scope } => {
7681
// Print the token only
77-
let token = proxy.inhibit(&reason, scope.as_scope()).await?;
82+
let token = run_control_call(proxy.inhibit(&reason, scope.as_scope())).await?;
7883
println!("{token}");
7984
}
8085
Command::Uninhibit { id } => {
8186
// Token removal is safe to repeat if a previous call already released it.
82-
proxy.uninhibit(id).await?;
87+
run_control_call(proxy.uninhibit(id)).await?;
8388
}
8489
Command::ListInhibitors => {
85-
let inhibitors = proxy.list_inhibitors().await?;
90+
let inhibitors = run_control_call(proxy.list_inhibitors()).await?;
8691
// Shared output helper
8792
print_inhibitors(&inhibitors);
8893
}
@@ -96,3 +101,14 @@ pub(crate) async fn handle_command(proxy: &ControlProxy<'_>, command: Command) -
96101

97102
Ok(())
98103
}
104+
105+
async fn run_control_call<T>(call: impl Future<Output = zbus::Result<T>>) -> Result<T> {
106+
match tokio::time::timeout(CONTROL_CALL_TIMEOUT, call).await {
107+
Ok(Ok(value)) => Ok(value),
108+
Ok(Err(err)) => Err(err.into()),
109+
Err(_) => Err(anyhow!(
110+
"timed out waiting for unixnotis daemon response after {}s",
111+
CONTROL_CALL_TIMEOUT.as_secs()
112+
)),
113+
}
114+
}

crates/unixnotis-daemon/src/daemon.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,17 @@ pub struct DaemonState {
5454
// Burst tracking lets one noisy sender fall back to snapshot invalidation
5555
// instead of forcing a storm of full add/update fanout
5656
notification_signal_bursts: StdMutex<std::collections::HashMap<String, NotificationBurstState>>,
57+
// Trial mode allows local rebuild loops without forcing daemon restarts for control auth
58+
trial_mode: bool,
5759
}
5860

5961
impl DaemonState {
60-
pub fn new(connection: Connection, config: Config, sound: SoundSettings) -> Arc<Self> {
62+
pub fn new(
63+
connection: Connection,
64+
config: Config,
65+
sound: SoundSettings,
66+
trial_mode: bool,
67+
) -> Arc<Self> {
6168
let store = NotificationStore::new(config);
6269
Arc::new(Self {
6370
store: Mutex::new(store),
@@ -70,6 +77,7 @@ impl DaemonState {
7077
last_emitted_state: StdMutex::new(None),
7178
last_emitted_popup_gate: StdMutex::new(None),
7279
notification_signal_bursts: StdMutex::new(std::collections::HashMap::new()),
80+
trial_mode,
7381
})
7482
}
7583

@@ -246,6 +254,10 @@ impl DaemonState {
246254
sender_name.unwrap_or("<unknown>"),
247255
)
248256
}
257+
258+
pub(crate) fn trial_mode(&self) -> bool {
259+
self.trial_mode
260+
}
249261
}
250262

251263
pub(crate) fn to_fdo_error(err: zbus::Error) -> zbus::fdo::Error {

0 commit comments

Comments
 (0)