about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-02-21 22:31:31 +0100
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-02-21 22:31:31 +0100
commitdc8539e3707c1a281b3aef9c7a6e8f929845d965 (patch)
treeb48576bb037b9035df45f6bd35dae899718d2c2b
parentfix(yt/status): Show the current database version (diff)
downloadyt-dc8539e3707c1a281b3aef9c7a6e8f929845d965.zip
fix(yt/storage/notify): Switch from a polling based system to inotify
-rw-r--r--Cargo.lock108
-rw-r--r--yt/Cargo.toml1
-rw-r--r--yt/src/download/mod.rs9
-rw-r--r--yt/src/storage/video_database/mod.rs1
-rw-r--r--yt/src/storage/video_database/notify.rs67
5 files changed, 182 insertions, 4 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 06a7253..ce5e368 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -554,6 +554,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
+name = "filetime"
+version = "0.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "libredox",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
 name = "flume"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -968,6 +980,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
 
 [[package]]
+name = "inotify"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
+dependencies = [
+ "bitflags 2.8.0",
+ "inotify-sys",
+ "libc",
+]
+
+[[package]]
+name = "inotify-sys"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
 name = "is-terminal"
 version = "0.4.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1010,6 +1042,26 @@ dependencies = [
 ]
 
 [[package]]
+name = "kqueue"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
+dependencies = [
+ "kqueue-sys",
+ "libc",
+]
+
+[[package]]
+name = "kqueue-sys"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+]
+
+[[package]]
 name = "lazy_static"
 version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1058,6 +1110,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags 2.8.0",
+ "libc",
+ "redox_syscall",
+]
+
+[[package]]
 name = "libsqlite3-sys"
 version = "0.30.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1143,6 +1206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
 dependencies = [
  "libc",
+ "log",
  "wasi 0.11.0+wasi-snapshot-preview1",
  "windows-sys 0.52.0",
 ]
@@ -1158,6 +1222,30 @@ dependencies = [
 ]
 
 [[package]]
+name = "notify"
+version = "8.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
+dependencies = [
+ "bitflags 2.8.0",
+ "filetime",
+ "inotify",
+ "kqueue",
+ "libc",
+ "log",
+ "mio",
+ "notify-types",
+ "walkdir",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "notify-types"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
+
+[[package]]
 name = "nucleo-matcher"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1595,6 +1683,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
 
 [[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
 name = "scopeguard"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2341,6 +2438,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
 
 [[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2690,6 +2797,7 @@ dependencies = [
  "futures",
  "libmpv2",
  "log",
+ "notify",
  "nucleo-matcher",
  "owo-colors",
  "regex",
diff --git a/yt/Cargo.toml b/yt/Cargo.toml
index ae3d229..2a93f40 100644
--- a/yt/Cargo.toml
+++ b/yt/Cargo.toml
@@ -48,6 +48,7 @@ url.workspace = true
 yt_dlp.workspace = true
 termsize.workspace = true
 uu_fmt.workspace = true
+notify = { version = "8.0.0", default-features = false }
 
 [[bin]]
 name = "yt"
diff --git a/yt/src/download/mod.rs b/yt/src/download/mod.rs
index 7cfa0b0..317f636 100644
--- a/yt/src/download/mod.rs
+++ b/yt/src/download/mod.rs
@@ -18,6 +18,7 @@ use crate::{
         downloader::{get_next_uncached_video, set_video_cache_path},
         extractor_hash::ExtractorHash,
         getters::get_video_yt_dlp_opts,
+        notify::wait_for_cache_reduction,
     },
     unreachable::Unreachable,
 };
@@ -160,12 +161,10 @@ impl Downloader {
                     "The `printed_warning` should be false in this case, \
                     and thus should have already set the `cached_cache_allocation`."
                 );
-                // info!("Current cache size allocation: '{}'", cache_allocation);
-                // self.cached_cache_allocation = Some(cache_allocation);
             }
 
             // Wait and hope, that a large video is deleted from the cache.
-            time::sleep(Duration::from_secs(10)).await;
+            wait_for_cache_reduction(app).await?;
             Ok(CacheSizeCheck::TooLarge)
         } else {
             self.printed_warning = false;
@@ -210,6 +209,7 @@ impl Downloader {
                     );
 
                     // Replace the currently downloading video
+                    // FIXME(@bpeetz): This does not work (probably because of the python part.) <2025-02-21>
                     current_download.task_handle.abort();
 
                     let new_current_download =
@@ -227,7 +227,8 @@ impl Downloader {
                 self.current_download = Some(new_current_download);
             }
 
-            time::sleep(Duration::new(1, 0)).await;
+            // TODO(@bpeetz): Why do we sleep here? <2025-02-21>
+            time::sleep(Duration::from_secs(1)).await;
         }
 
         info!("Finished downloading!");
diff --git a/yt/src/storage/video_database/mod.rs b/yt/src/storage/video_database/mod.rs
index afcd179..22628b5 100644
--- a/yt/src/storage/video_database/mod.rs
+++ b/yt/src/storage/video_database/mod.rs
@@ -18,6 +18,7 @@ pub mod downloader;
 pub mod extractor_hash;
 pub mod getters;
 pub mod setters;
+pub mod notify;
 
 #[derive(Debug, Clone)]
 pub struct Video {
diff --git a/yt/src/storage/video_database/notify.rs b/yt/src/storage/video_database/notify.rs
new file mode 100644
index 0000000..56599ba
--- /dev/null
+++ b/yt/src/storage/video_database/notify.rs
@@ -0,0 +1,67 @@
+use std::{
+    path::{Path, PathBuf},
+    sync::mpsc,
+    thread::sleep,
+    time::Duration,
+};
+
+use crate::app::App;
+
+use anyhow::{Context, Result};
+use notify::{
+    Event, EventKind, RecursiveMode, Watcher,
+    event::{DataChange, ModifyKind},
+};
+use tokio::task;
+
+/// This functions registers a watcher for the database and only returns once a write was
+/// registered for the database.
+pub async fn wait_for_db_write(app: &App) -> Result<()> {
+    let db_path: PathBuf = app.config.paths.database_path.clone();
+    task::spawn_blocking(move || wait_for_db_write_sync(&db_path)).await?
+}
+
+fn wait_for_db_write_sync(db_path: &Path) -> Result<()> {
+    let (tx, rx) = mpsc::channel::<notify::Result<Event>>();
+
+    let mut watcher = notify::recommended_watcher(tx)?;
+
+    watcher.watch(db_path, RecursiveMode::NonRecursive)?;
+
+    for res in rx {
+        let event = res.context("Failed to wait for db write")?;
+
+        if let EventKind::Modify(ModifyKind::Data(DataChange::Any)) = event.kind {
+            // Buffer some of the `Modify` event burst.
+            sleep(Duration::from_millis(10));
+
+            return Ok(());
+        }
+    }
+
+    Ok(())
+}
+
+/// This functions registers a watcher for the cache path and returns once a file was removed
+pub async fn wait_for_cache_reduction(app: &App) -> Result<()> {
+    let download_directory: PathBuf = app.config.paths.download_dir.clone();
+    task::spawn_blocking(move || wait_for_cache_reduction_sync(&download_directory)).await?
+}
+
+fn wait_for_cache_reduction_sync(download_directory: &Path) -> Result<()> {
+    let (tx, rx) = mpsc::channel::<notify::Result<Event>>();
+
+    let mut watcher = notify::recommended_watcher(tx)?;
+
+    watcher.watch(download_directory, RecursiveMode::Recursive)?;
+
+    for res in rx {
+        let event = res.context("Failed to wait for cache size reduction")?;
+
+        if let EventKind::Remove(_) = event.kind {
+            return Ok(());
+        }
+    }
+
+    Ok(())
+}