From e20574d71c96b72bd2a0395f9885b4ab6f824128 Mon Sep 17 00:00:00 2001 From: Mathieu Comandon Date: Mon, 30 Jun 2025 13:10:03 -0700 Subject: [PATCH 1/2] Remove PLUGIN_ID constant --- src/constants.rs | 1 - src/local/connector.rs | 14 ++++++++++++-- src/plugin/plugin_interface.rs | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) 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..b87217d 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/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”) From e908bf3505829c0870d1f072591b2722e448fd81 Mon Sep 17 00:00:00 2001 From: Mathieu Comandon Date: Mon, 30 Jun 2025 15:41:13 -0700 Subject: [PATCH 2/2] Watch for changes in gameinfo files --- Cargo.lock | 23 +++++++++++++++++++++++ Cargo.toml | 1 + clippy.toml | 1 + src/local/connector.rs | 12 ++++++------ src/local/service.rs | 35 +++++++++++++++++++++++++++++++++++ src/main.rs | 1 + 6 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 clippy.toml 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/local/connector.rs b/src/local/connector.rs index b87217d..188e7f8 100644 --- a/src/local/connector.rs +++ b/src/local/connector.rs @@ -21,12 +21,12 @@ 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_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(); 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;