diff --git a/Cargo.lock b/Cargo.lock index 622c9f2..b47e5ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1083,6 +1083,28 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inotify" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" +dependencies = [ + "bitflags", + "futures-core", + "inotify-sys", + "libc", + "tokio", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "inout" version = "0.1.4" @@ -1573,6 +1595,7 @@ dependencies = [ "event-listener", "futures", "futures-util", + "inotify", "lazy_static", "log", "num-derive", diff --git a/Cargo.toml b/Cargo.toml index 649ee7b..770cbdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,3 +41,4 @@ futures-util = "0.3.31" zip-extract = "0.2.2" dirs = "6.0.0" sysinfo = "0.34.2" +inotify = "0.11.0" diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..756c7dc --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +too-many-arguments-threshold = 9 diff --git a/src/constants.rs b/src/constants.rs index d5e7ca4..ee53813 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,6 +1,5 @@ pub const BUS_NAME: &str = "one.playtron.LocalPlugin"; pub const CLIENT_PATH: &str = "/one/playtron/LocalPlugin/PluginClient0"; -pub const PLUGIN_ID: &str = "local"; pub const NAME: &str = "Local games"; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const MINIMUM_API_VERSION: &str = "0.1.1"; diff --git a/src/local/connector.rs b/src/local/connector.rs index 0d93388..188e7f8 100644 --- a/src/local/connector.rs +++ b/src/local/connector.rs @@ -1,3 +1,4 @@ +use crate::constants::LIBRARY_PROVIDER_ID; /// This module is where you implement the functionality to interact with the store service /// legendary / gog-warp / etc code should go here. The module can be renamed to represent your /// connector more accurately eg `legendary.rs` @@ -20,16 +21,25 @@ pub struct AccountInfo { } impl LocalConnector { + // pub fn get_config_path(&self) -> PathBuf { + // dirs::data_dir().unwrap().join(PathBuf::from(format!( + // "playtron/plugins/{}", + // LIBRARY_PROVIDER_ID + // ))) + // } + pub fn get_library_paths(&self) -> Vec { let mut library_paths = Vec::new(); - let home_library_path = dirs::data_dir().unwrap().join("playtron/apps/local"); + let home_library_path = dirs::data_dir() + .unwrap() + .join(format!("playtron/apps/{}", LIBRARY_PROVIDER_ID)); if home_library_path.exists() { library_paths.push(home_library_path); } for mount_point in get_mount_points() { let library_path = PathBuf::from_str(&mount_point) .unwrap() - .join("playtron/apps/local"); + .join(format!("playtron/apps/{}", LIBRARY_PROVIDER_ID)); if library_path.exists() { library_paths.push(library_path); } diff --git a/src/local/service.rs b/src/local/service.rs index e417cfe..d7a86f8 100644 --- a/src/local/service.rs +++ b/src/local/service.rs @@ -6,10 +6,12 @@ use crate::types::app::{ use crate::types::cloud_sync::CloudPath; use crate::types::results::ResultWithError; use futures::future; +use inotify::{Inotify, WatchMask}; use rsa::pkcs1::EncodeRsaPublicKey; use rsa::pkcs8::LineEnding; use rsa::{RsaPrivateKey, RsaPublicKey}; use std::collections::BTreeMap; +use std::fs; use std::vec; use zbus::fdo; @@ -29,6 +31,39 @@ impl LocalService { Self { rsa, connector } } + pub fn initialize(&self) { + let mut inotify = Inotify::init().expect("Failed to initialize inotify"); + + let library_paths = self.connector.get_library_paths(); + library_paths.iter().for_each(|path| { + fs::read_dir(path).unwrap().for_each(|dir_result| { + let dir_entry = dir_result.unwrap(); + let game_path = dir_entry.path(); + let game_info = game_path.join("gameinfo.yaml"); + inotify + .watches() + .add( + game_info, + WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE, + ) + .expect("Failed to add inotify watch"); + }); + }); + let mut buffer = [0u8; 4096]; + tokio::spawn(async move { + loop { + let events = inotify + .read_events_blocking(&mut buffer) + .expect("Failed to read inotify events"); + + for event in events { + // TODO emit signal to trigger update of app metadata + log::info!("gameinfo modified: {:?}", event); + } + } + }); + } + pub fn get_public_key(&self) -> String { let public_key = RsaPublicKey::from(&self.rsa); public_key.to_pkcs1_pem(LineEnding::LF).unwrap() diff --git a/src/main.rs b/src/main.rs index c79a387..f99fc26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ async fn main() -> Result<(), Box> { log::info!("Starting Playtron Plugin version: {version} "); let local_service = LocalService::new(); + local_service.initialize(); build_connection(local_service).await?; register_plugin().await; diff --git a/src/plugin/plugin_interface.rs b/src/plugin/plugin_interface.rs index fa12cbc..e3d91c3 100644 --- a/src/plugin/plugin_interface.rs +++ b/src/plugin/plugin_interface.rs @@ -1,4 +1,4 @@ -use crate::constants::{MINIMUM_API_VERSION, NAME, PLUGIN_ID, VERSION}; +use crate::constants::{LIBRARY_PROVIDER_ID, MINIMUM_API_VERSION, NAME, VERSION}; use zbus::fdo; use zbus_macros::interface; @@ -16,7 +16,7 @@ impl Plugin { /// Id #[zbus(property)] async fn id(&self) -> fdo::Result<&str> { - Ok(PLUGIN_ID) + Ok(LIBRARY_PROVIDER_ID) } /// Human readable name of the plugin (e.g. “Steam”)