max / goingson
3 files changed,
+71 insertions,
-81 deletions
| @@ -1387,7 +1387,7 @@ | |||
| 1387 | 1387 | "libc", | |
| 1388 | 1388 | "option-ext", | |
| 1389 | 1389 | "redox_users", | |
| 1390 | - | "windows-sys 0.60.2", | |
| 1390 | + | "windows-sys 0.61.2", | |
| 1391 | 1391 | ] | |
| 1392 | 1392 | ||
| 1393 | 1393 | [[package]] | |
| @@ -1628,7 +1628,7 @@ | |||
| 1628 | 1628 | checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" | |
| 1629 | 1629 | dependencies = [ | |
| 1630 | 1630 | "libc", | |
| 1631 | - | "windows-sys 0.60.2", | |
| 1631 | + | "windows-sys 0.61.2", | |
| 1632 | 1632 | ] | |
| 1633 | 1633 | ||
| 1634 | 1634 | [[package]] | |
| @@ -3650,7 +3650,7 @@ | |||
| 3650 | 3650 | "png 0.18.1", | |
| 3651 | 3651 | "serde", | |
| 3652 | 3652 | "thiserror 2.0.20", | |
| 3653 | - | "windows-sys 0.60.2", | |
| 3653 | + | "windows-sys 0.61.2", | |
| 3654 | 3654 | ] | |
| 3655 | 3655 | ||
| 3656 | 3656 | [[package]] | |
| @@ -3783,7 +3783,7 @@ | |||
| 3783 | 3783 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3784 | 3784 | checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" | |
| 3785 | 3785 | dependencies = [ | |
| 3786 | - | "windows-sys 0.60.2", | |
| 3786 | + | "windows-sys 0.61.2", | |
| 3787 | 3787 | ] | |
| 3788 | 3788 | ||
| 3789 | 3789 | [[package]] | |
| @@ -4717,7 +4717,7 @@ | |||
| 4717 | 4717 | ||
| 4718 | 4718 | [[package]] | |
| 4719 | 4719 | name = "quasi-http" | |
| 4720 | - | version = "0.88.0" | |
| 4720 | + | version = "0.89.0" | |
| 4721 | 4721 | dependencies = [ | |
| 4722 | 4722 | "form_urlencoded", | |
| 4723 | 4723 | "http", | |
| @@ -4726,22 +4726,24 @@ | |||
| 4726 | 4726 | ||
| 4727 | 4727 | [[package]] | |
| 4728 | 4728 | name = "quasi-notifs" | |
| 4729 | - | version = "0.88.0" | |
| 4729 | + | version = "0.89.0" | |
| 4730 | 4730 | dependencies = [ | |
| 4731 | 4731 | "quasi-router", | |
| 4732 | 4732 | "synckit-config", | |
| 4733 | + | "tauri", | |
| 4734 | + | "tauri-plugin-notification", | |
| 4733 | 4735 | ] | |
| 4734 | 4736 | ||
| 4735 | 4737 | [[package]] | |
| 4736 | 4738 | name = "quasi-router" | |
| 4737 | - | version = "0.88.0" | |
| 4739 | + | version = "0.89.0" | |
| 4738 | 4740 | dependencies = [ | |
| 4739 | 4741 | "makeover-layout", | |
| 4740 | 4742 | ] | |
| 4741 | 4743 | ||
| 4742 | 4744 | [[package]] | |
| 4743 | 4745 | name = "quasi-tauri" | |
| 4744 | - | version = "0.88.0" | |
| 4746 | + | version = "0.89.0" | |
| 4745 | 4747 | dependencies = [ | |
| 4746 | 4748 | "http", | |
| 4747 | 4749 | "quasi-http", | |
| @@ -4767,7 +4769,7 @@ | |||
| 4767 | 4769 | ||
| 4768 | 4770 | [[package]] | |
| 4769 | 4771 | name = "quasi-webview" | |
| 4770 | - | version = "0.88.0" | |
| 4772 | + | version = "0.89.0" | |
| 4771 | 4773 | dependencies = [ | |
| 4772 | 4774 | "docengine", | |
| 4773 | 4775 | "makeover-layout", | |
| @@ -5206,7 +5208,7 @@ | |||
| 5206 | 5208 | "errno", | |
| 5207 | 5209 | "libc", | |
| 5208 | 5210 | "linux-raw-sys", | |
| 5209 | - | "windows-sys 0.60.2", | |
| 5211 | + | "windows-sys 0.61.2", | |
| 5210 | 5212 | ] | |
| 5211 | 5213 | ||
| 5212 | 5214 | [[package]] | |
| @@ -5263,7 +5265,7 @@ | |||
| 5263 | 5265 | "security-framework", | |
| 5264 | 5266 | "security-framework-sys", | |
| 5265 | 5267 | "webpki-root-certs", | |
| 5266 | - | "windows-sys 0.60.2", | |
| 5268 | + | "windows-sys 0.61.2", | |
| 5267 | 5269 | ] | |
| 5268 | 5270 | ||
| 5269 | 5271 | [[package]] | |
| @@ -5803,7 +5805,7 @@ | |||
| 5803 | 5805 | checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" | |
| 5804 | 5806 | dependencies = [ | |
| 5805 | 5807 | "libc", | |
| 5806 | - | "windows-sys 0.60.2", | |
| 5808 | + | "windows-sys 0.61.2", | |
| 5807 | 5809 | ] | |
| 5808 | 5810 | ||
| 5809 | 5811 | [[package]] | |
| @@ -6563,7 +6565,7 @@ | |||
| 6563 | 6565 | "getrandom 0.4.3", | |
| 6564 | 6566 | "once_cell", | |
| 6565 | 6567 | "rustix", | |
| 6566 | - | "windows-sys 0.60.2", | |
| 6568 | + | "windows-sys 0.61.2", | |
| 6567 | 6569 | ] | |
| 6568 | 6570 | ||
| 6569 | 6571 | [[package]] | |
| @@ -6585,7 +6587,7 @@ | |||
| 6585 | 6587 | "parking_lot", | |
| 6586 | 6588 | "rustix", | |
| 6587 | 6589 | "signal-hook", | |
| 6588 | - | "windows-sys 0.60.2", | |
| 6590 | + | "windows-sys 0.61.2", | |
| 6589 | 6591 | ] | |
| 6590 | 6592 | ||
| 6591 | 6593 | [[package]] | |
| @@ -7067,7 +7069,7 @@ | |||
| 7067 | 7069 | "png 0.18.1", | |
| 7068 | 7070 | "serde", | |
| 7069 | 7071 | "thiserror 2.0.20", | |
| 7070 | - | "windows-sys 0.60.2", | |
| 7072 | + | "windows-sys 0.61.2", | |
| 7071 | 7073 | ] | |
| 7072 | 7074 | ||
| 7073 | 7075 | [[package]] | |
| @@ -7102,7 +7104,7 @@ | |||
| 7102 | 7104 | dependencies = [ | |
| 7103 | 7105 | "memoffset", | |
| 7104 | 7106 | "tempfile", | |
| 7105 | - | "windows-sys 0.60.2", | |
| 7107 | + | "windows-sys 0.61.2", | |
| 7106 | 7108 | ] | |
| 7107 | 7109 | ||
| 7108 | 7110 | [[package]] | |
| @@ -7632,7 +7634,7 @@ | |||
| 7632 | 7634 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 7633 | 7635 | checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" | |
| 7634 | 7636 | dependencies = [ | |
| 7635 | - | "windows-sys 0.60.2", | |
| 7637 | + | "windows-sys 0.61.2", | |
| 7636 | 7638 | ] | |
| 7637 | 7639 | ||
| 7638 | 7640 | [[package]] | |
| @@ -8491,15 +8493,15 @@ | |||
| 8491 | 8493 | ||
| 8492 | 8494 | [[patch.unused]] | |
| 8493 | 8495 | name = "quasi-axum" | |
| 8494 | - | version = "0.88.0" | |
| 8496 | + | version = "0.89.0" | |
| 8495 | 8497 | ||
| 8496 | 8498 | [[patch.unused]] | |
| 8497 | 8499 | name = "quasi-basics" | |
| 8498 | - | version = "0.88.0" | |
| 8500 | + | version = "0.89.0" | |
| 8499 | 8501 | ||
| 8500 | 8502 | [[patch.unused]] | |
| 8501 | 8503 | name = "quasi-immediate" | |
| 8502 | - | version = "0.88.0" | |
| 8504 | + | version = "0.89.0" | |
| 8503 | 8505 | ||
| 8504 | 8506 | [[patch.unused]] | |
| 8505 | 8507 | name = "quasi-store" |
| @@ -36,7 +36,7 @@ | |||
| 36 | 36 | makeover-geometry = "0.7" | |
| 37 | 37 | # Only to write its selection and clock scripts into the frontend. Those two are | |
| 38 | 38 | # the whole of `frontend/js/` since the swap. | |
| 39 | - | quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.88" } | |
| 39 | + | quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.89" } | |
| 40 | 40 | ||
| 41 | 41 | [dependencies] | |
| 42 | 42 | goingson-core = { workspace = true } | |
| @@ -54,27 +54,22 @@ | |||
| 54 | 54 | # dependency's source even with the feature off -- so a public clone could not | |
| 55 | 55 | # build at all against a URL it could not reach. quasi went public that day and | |
| 56 | 56 | # the URL moved here with it. | |
| 57 | - | quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.88" } | |
| 58 | - | quasi-http = { git = "https://makenot.work/git/max/quasi.git", version = "0.88" } | |
| 59 | - | quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.88" } | |
| 60 | - | quasi-tauri = { git = "https://makenot.work/git/max/quasi.git", version = "0.88" } | |
| 57 | + | quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.89" } | |
| 58 | + | quasi-http = { git = "https://makenot.work/git/max/quasi.git", version = "0.89" } | |
| 59 | + | quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.89" } | |
| 60 | + | quasi-tauri = { git = "https://makenot.work/git/max/quasi.git", version = "0.89" } | |
| 61 | 61 | ||
| 62 | 62 | # The notification declaration, and it is NOT behind the `quasi` feature: the | |
| 63 | 63 | # watcher is desktop app behaviour rather than a described screen, and the | |
| 64 | 64 | # generated config keys are part of `config_key::CONFIG` on every platform. The | |
| 65 | 65 | # crate is dep-free at its core for exactly this case; `synckit` adds the spec | |
| 66 | 66 | # it produces, and `describe` (below, under `quasi`) adds the settings pane. | |
| 67 | - | # | |
| 68 | - | # NOT `quasi-tauri`'s `notifs` feature, which is where the delivery adapter | |
| 69 | - | # lives. That crate depends on `quasi-router` unconditionally, so taking its | |
| 70 | - | # `Notifier` -- eight lines over `tauri-plugin-notification`, which this app | |
| 71 | - | # already links -- would pull the whole description stack into a default build | |
| 72 | - | # and undo what the `quasi` feature is for. Filed against quasi as a finding: | |
| 73 | - | # the adapter is welded to the router crate, so an app that wants delivery | |
| 74 | - | # before it has ported its screens cannot take it. `notifications::Notifier` is | |
| 75 | - | # the eight lines meanwhile, and it goes when the flip makes quasi-router | |
| 76 | - | # unconditional here. | |
| 77 | - | quasi-notifs = { git = "https://makenot.work/git/max/quasi.git", version = "0.88", features = ["synckit", "describe"] } | |
| 67 | + | # `tauri` is the delivery adapter, which used to live in `quasi-tauri` and could | |
| 68 | + | # not be taken from there: that crate depends on `quasi-router` unconditionally, | |
| 69 | + | # so an app wanting eight lines over `tauri-plugin-notification` had to link the | |
| 70 | + | # whole description stack for them. quasicoherent `c231ff13` moved it here, | |
| 71 | + | # where the `Deliver` trait it implements already lives. | |
| 72 | + | quasi-notifs = { git = "https://makenot.work/git/max/quasi.git", version = "0.89", features = ["synckit", "describe", "tauri"] } | |
| 78 | 73 | ||
| 79 | 74 | # Tauri | |
| 80 | 75 | tauri = { workspace = true, features = ["image-png", "devtools"] } |
| @@ -23,13 +23,13 @@ | |||
| 23 | 23 | //! the data and the notification is a fact about the reader, so the unsnooze | |
| 24 | 24 | //! happens either way. | |
| 25 | 25 | //! | |
| 26 | - | //! # The one thing here that is only here because of a crate boundary | |
| 26 | + | //! # Delivery is the framework's, as of `c231ff13` | |
| 27 | 27 | //! | |
| 28 | - | //! [`Notifier`], eight lines. `quasi-tauri` ships exactly this behind its | |
| 29 | - | //! `notifs` feature and taking it would pull `quasi-router` into every build, | |
| 30 | - | //! because that crate depends on the router unconditionally. See the note in | |
| 31 | - | //! `Cargo.toml`; this goes when the flip makes the description stack | |
| 32 | - | //! unconditional. | |
| 28 | + | //! The eight lines that put an occurrence in front of a person used to be | |
| 29 | + | //! here, because the only copy of them lived in `quasi-tauri` and that crate | |
| 30 | + | //! takes `quasi-router` unconditionally. They are [`quasi_notifs::Notifier`] | |
| 31 | + | //! now, behind that crate's `tauri` feature, so taking them costs a plugin | |
| 32 | + | //! this app already links and nothing else. | |
| 33 | 33 | ||
| 34 | 34 | use crate::commands::all_config; | |
| 35 | 35 | use crate::notifs::{ | |
| @@ -38,11 +38,13 @@ | |||
| 38 | 38 | use crate::state::{AppState, DESKTOP_USER_ID}; | |
| 39 | 39 | use chrono::Utc; | |
| 40 | 40 | use quasi_notifs::config::Settings; | |
| 41 | - | use quasi_notifs::{Deliver, Occurrence, Outbox}; | |
| 41 | + | use quasi_notifs::{Notifier, Occurrence, Outbox}; | |
| 42 | 42 | use std::collections::HashMap; | |
| 43 | 43 | use std::sync::Arc; | |
| 44 | 44 | use std::time::Duration; | |
| 45 | 45 | use tauri::Manager; | |
| 46 | + | // Still this file's own, for `send_notification` below: an undeclared kind | |
| 47 | + | // bypasses the outbox and so has no `Occurrence` to hand a `Notifier`. | |
| 46 | 48 | use tauri_plugin_notification::NotificationExt; | |
| 47 | 49 | use tokio_util::sync::CancellationToken; | |
| 48 | 50 | use tracing::{debug, error, info, instrument, warn}; | |
| @@ -50,39 +52,14 @@ | |||
| 50 | 52 | /// Check interval for snooze expiry (60 seconds) | |
| 51 | 53 | const CHECK_INTERVAL_SECS: u64 = 60; | |
| 52 | 54 | ||
| 53 | - | /// Puts an occurrence in front of a person, through Tauri's notification plugin. | |
| 55 | + | /// The delivering adapter, over this app's runtime. | |
| 54 | 56 | /// | |
| 55 | - | /// The host's entire share of delivery. It cannot fail in a way the caller | |
| 56 | - | /// could act on -- the occurrence is already noted as sent, and an outbox that | |
| 57 | - | /// retried would be a queue nobody asked for -- so a refusal is counted and | |
| 58 | - | /// logged rather than returned. | |
| 59 | - | struct Notifier { | |
| 60 | - | app: tauri::AppHandle, | |
| 61 | - | refused: usize, | |
| 62 | - | } | |
| 63 | - | ||
| 64 | - | impl Notifier { | |
| 65 | - | const fn new(app: tauri::AppHandle) -> Self { | |
| 66 | - | Self { app, refused: 0 } | |
| 67 | - | } | |
| 68 | - | } | |
| 69 | - | ||
| 70 | - | impl Deliver for Notifier { | |
| 71 | - | fn deliver(&mut self, note: &Occurrence) { | |
| 72 | - | debug!(title = %note.title, body = %note.body, kind = note.kind, "Sending notification"); | |
| 73 | - | if let Err(e) = self | |
| 74 | - | .app | |
| 75 | - | .notification() | |
| 76 | - | .builder() | |
| 77 | - | .title(¬e.title) | |
| 78 | - | .body(¬e.body) | |
| 79 | - | .show() | |
| 80 | - | { | |
| 81 | - | self.refused += 1; | |
| 82 | - | warn!(error = %e, title = %note.title, refused = self.refused, "Failed to send notification"); | |
| 83 | - | } | |
| 84 | - | } | |
| 85 | - | } | |
| 57 | + | /// `tauri::AppHandle` defaults to [`tauri::Wry`] and | |
| 58 | + | /// [`Notifier`](quasi_notifs::Notifier) does not: it is generic for the reason | |
| 59 | + | /// everything tauri hands out is, and quasi-notifs takes tauri with default | |
| 60 | + | /// features off so there is no default to inherit. Named once here rather than | |
| 61 | + | /// spelled at each `Outbox<..>` below. | |
| 62 | + | type Delivering = Notifier<tauri::Wry>; | |
| 86 | 63 | ||
| 87 | 64 | /// What the reader has chosen, as the registry reads it. | |
| 88 | 65 | /// | |
| @@ -104,8 +81,14 @@ | |||
| 104 | 81 | "Starting notification watcher (interval: {}s)", | |
| 105 | 82 | CHECK_INTERVAL_SECS | |
| 106 | 83 | ); | |
| 107 | - | let mut outbox = Outbox::new(NOTIFS, Notifier::new(app.clone())); | |
| 84 | + | let mut outbox = Outbox::new(NOTIFS, Delivering::new(app.clone())); | |
| 108 | 85 | let mut interval = tokio::time::interval(Duration::from_secs(CHECK_INTERVAL_SECS)); | |
| 86 | + | // What the platform would not show. `Deliver` cannot fail in a way this | |
| 87 | + | // loop could act on -- the occurrence is already noted as sent, and | |
| 88 | + | // retrying would be a queue nobody asked for -- but a watcher refused | |
| 89 | + | // every time has a permission problem rather than a quiet user, and the | |
| 90 | + | // two look identical without saying so. Counted by the adapter, read here. | |
| 91 | + | let mut refused = 0; | |
| 109 | 92 | ||
| 110 | 93 | loop { | |
| 111 | 94 | tokio::select! { | |
| @@ -148,12 +131,21 @@ | |||
| 148 | 131 | if let Err(e) = check_tasks_due(&mut outbox, &state, &chosen) { | |
| 149 | 132 | error!(error = %e, "Error checking tasks coming due"); | |
| 150 | 133 | } | |
| 134 | + | ||
| 135 | + | let so_far = outbox.adapter().refused(); | |
| 136 | + | if so_far > refused { | |
| 137 | + | warn!( | |
| 138 | + | refused = so_far, | |
| 139 | + | "The platform refused a notification this tick" | |
| 140 | + | ); | |
| 141 | + | refused = so_far; | |
| 142 | + | } | |
| 151 | 143 | } | |
| 152 | 144 | } | |
| 153 | 145 | ||
| 154 | 146 | #[instrument(skip_all)] | |
| 155 | 147 | async fn check_task_snoozes( | |
| 156 | - | outbox: &mut Outbox<Notifier>, | |
| 148 | + | outbox: &mut Outbox<Delivering>, | |
| 157 | 149 | state: &Arc<AppState>, | |
| 158 | 150 | chosen: &Chosen, | |
| 159 | 151 | ) -> Result<(), String> { | |
| @@ -206,7 +198,7 @@ | |||
| 206 | 198 | } | |
| 207 | 199 | ||
| 208 | 200 | fn check_email_snoozes( | |
| 209 | - | outbox: &mut Outbox<Notifier>, | |
| 201 | + | outbox: &mut Outbox<Delivering>, | |
| 210 | 202 | state: &Arc<AppState>, | |
| 211 | 203 | chosen: &Chosen, | |
| 212 | 204 | ) -> Result<(), String> { | |
| @@ -250,7 +242,7 @@ | |||
| 250 | 242 | } | |
| 251 | 243 | ||
| 252 | 244 | fn check_overdue_responses( | |
| 253 | - | outbox: &mut Outbox<Notifier>, | |
| 245 | + | outbox: &mut Outbox<Delivering>, | |
| 254 | 246 | state: &Arc<AppState>, | |
| 255 | 247 | chosen: &Chosen, | |
| 256 | 248 | ) -> Result<(), String> { | |
| @@ -315,7 +307,7 @@ | |||
| 315 | 307 | ||
| 316 | 308 | #[instrument(skip_all)] | |
| 317 | 309 | async fn check_event_reminders( | |
| 318 | - | outbox: &mut Outbox<Notifier>, | |
| 310 | + | outbox: &mut Outbox<Delivering>, | |
| 319 | 311 | state: &Arc<AppState>, | |
| 320 | 312 | chosen: &Chosen, | |
| 321 | 313 | ) -> Result<(), String> { | |
| @@ -398,7 +390,7 @@ | |||
| 398 | 390 | /// of the bare task id would have lost. | |
| 399 | 391 | #[instrument(skip_all)] | |
| 400 | 392 | fn check_tasks_due( | |
| 401 | - | outbox: &mut Outbox<Notifier>, | |
| 393 | + | outbox: &mut Outbox<Delivering>, | |
| 402 | 394 | state: &Arc<AppState>, | |
| 403 | 395 | chosen: &Chosen, | |
| 404 | 396 | ) -> Result<(), String> { | |
| @@ -536,6 +528,7 @@ | |||
| 536 | 528 | #[cfg(test)] | |
| 537 | 529 | mod tests { | |
| 538 | 530 | use super::*; | |
| 531 | + | use quasi_notifs::Deliver; | |
| 539 | 532 | use quasi_notifs::config::Unset; | |
| 540 | 533 | use std::cell::RefCell; | |
| 541 | 534 | use std::rc::Rc; |