diff --git a/.gitignore b/.gitignore index 18ded29..33ef448 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target Cargo.lock -api.key \ No newline at end of file +api.key +api.key.* diff --git a/Cargo.toml b/Cargo.toml index 59a807e..419bbb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ members = [ "blocking", "examples/event_printer", "examples/system_info", + "examples/multi_client", + "examples/multi_client_async", ] diff --git a/async/src/client.rs b/async/src/client.rs index f55d28f..0f950ec 100644 --- a/async/src/client.rs +++ b/async/src/client.rs @@ -7,12 +7,13 @@ use reqwest::Client as HttpClient; use serde::Serialize; use serde::de::DeserializeOwned as Deserialize; use std::collections::HashMap; +use syncthing_types::FolderID; use syncthing_types::events::{Event, EventType}; use syncthing_types::utils::construct_uri; use syncthing_types::{API_DEFAULT_AUTHORITY, Timestamp}; use syncthing_types::{API_HEADER_KEY, routes::*}; use syncthing_types::{EMPTY_EVENT_SUBSCRIPTION, system}; -use syncthing_types::{cluster, utils}; +use syncthing_types::{cluster, config, db, utils}; pub struct Client { client: HttpClient, @@ -37,6 +38,10 @@ impl Client { } } + pub fn authority(&self) -> &Authority { + &self.authority + } + pub(crate) async fn get + 'static>( &self, path_and_query: T, @@ -156,4 +161,18 @@ impl Client { pub async fn get_cluster_pending_devices(&self) -> Fallible { self.get(CLUSTER_PENDING_DEVICES).await } + + pub async fn get_config_folders(&self) -> Fallible> { + self.get(CONFIG_FOLDERS).await + } + + pub async fn get_config_devices(&self) -> Fallible> { + self.get(CONFIG_DEVICES).await + } + + pub async fn get_db_status(&self, folder_id: &FolderID) -> Fallible { + let mut string: String = DB_STATUS.to_string(); + string.push_str(folder_id); + self.get(string).await + } } diff --git a/async/src/lib.rs b/async/src/lib.rs index b35fc33..3f2fb81 100644 --- a/async/src/lib.rs +++ b/async/src/lib.rs @@ -4,6 +4,7 @@ mod event_stream; mod tests; pub use client::Client; +pub use http::uri::Authority; pub type Fallible = Result; pub use syncthing_types::*; diff --git a/blocking/src/client.rs b/blocking/src/client.rs index 232660d..f396023 100644 --- a/blocking/src/client.rs +++ b/blocking/src/client.rs @@ -8,10 +8,10 @@ use serde::de::DeserializeOwned as Deserialize; use std::collections::HashMap; use syncthing_types::events::{Event, EventType}; use syncthing_types::utils::construct_uri; -use syncthing_types::{API_DEFAULT_AUTHORITY, Timestamp}; +use syncthing_types::{API_DEFAULT_AUTHORITY, FolderID, Timestamp}; use syncthing_types::{API_HEADER_KEY, routes::*}; use syncthing_types::{EMPTY_EVENT_SUBSCRIPTION, system}; -use syncthing_types::{cluster, utils}; +use syncthing_types::{cluster, config, db, utils}; use ureq::Agent; pub struct Client { @@ -149,4 +149,18 @@ impl Client { pub fn get_cluster_pending_devices(&self) -> Fallible { self.get(CLUSTER_PENDING_DEVICES) } + + pub fn get_config_folders(&self) -> Fallible { + self.get(CONFIG_FOLDERS) + } + + pub fn get_config_devices(&self) -> Fallible { + self.get(CONFIG_DEVICES) + } + + pub fn get_db_status(&self, folder_id: &FolderID) -> Fallible { + let mut string = DB_STATUS.to_string(); + string.push_str(folder_id); + self.get(string) + } } diff --git a/blocking/src/lib.rs b/blocking/src/lib.rs index b35fc33..c2b8428 100644 --- a/blocking/src/lib.rs +++ b/blocking/src/lib.rs @@ -6,4 +6,5 @@ mod tests; pub use client::Client; pub type Fallible = Result; +pub use http::uri::Authority; pub use syncthing_types::*; diff --git a/examples/multi_client/Cargo.toml b/examples/multi_client/Cargo.toml new file mode 100644 index 0000000..cc72831 --- /dev/null +++ b/examples/multi_client/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "multi_client" +version = "1.0.0" +authors = ["Dylan Sandall "] +edition = "2024" + +[dependencies] +syncthing = { path = "../../blocking/" } diff --git a/examples/multi_client/src/main.rs b/examples/multi_client/src/main.rs new file mode 100644 index 0000000..e487e97 --- /dev/null +++ b/examples/multi_client/src/main.rs @@ -0,0 +1,29 @@ +use syncthing::{Authority, Client, Fallible}; + +fn main() -> Fallible<()> { + let mut clients: Vec = Vec::new(); + + clients.push(Client::with_authority( + include_str!("../../../api.key"), + Authority::from_static("localhost:8384"), + ).unwrap()); + + clients.push(Client::with_authority( + include_str!("../../../api.key.deb"), + Authority::from_static("debian-server:8384"), + ).unwrap()); + + for client in clients { + println!("client address is {}!", client.authority); + + let _p = client.ping().unwrap(); + + let system = client.get_version_info().unwrap(); + println!( + "syncthing {} is running on {:?}!\n>>> ({})!", + system.version, system.os, system.long_version + ); + println!(""); + } + Ok(()) +} diff --git a/examples/multi_client_async/Cargo.toml b/examples/multi_client_async/Cargo.toml new file mode 100644 index 0000000..e3d7a2b --- /dev/null +++ b/examples/multi_client_async/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "multi_client_async" +version = "1.0.0" +authors = ["Dylan Sandall "] +edition = "2024" + +[dependencies] +syncthing-async = { path = "../../async" } +tokio = { version = "1", features = ["macros", "rt-multi-thread"] } diff --git a/examples/multi_client_async/src/main.rs b/examples/multi_client_async/src/main.rs new file mode 100644 index 0000000..d5121b3 --- /dev/null +++ b/examples/multi_client_async/src/main.rs @@ -0,0 +1,30 @@ +use syncthing_async::{Authority, Client, Fallible}; + +#[tokio::main] +async fn main() -> Fallible<()> { + let mut clients: Vec = Vec::new(); + + clients.push(Client::with_authority( + include_str!("../../../api.key"), + Authority::from_static("localhost:8384"), + )); + + clients.push(Client::with_authority( + include_str!("../../../api.key.deb"), + Authority::from_static("debian-server:8384"), + )); + + for client in clients { + println!("client address is {}!", client.authority); + + let _p = client.ping().await?; + + let system = client.get_version_info().await?; + println!( + "syncthing {} is running on {:?}!\n>>> ({})!", + system.version, system.os, system.long_version + ); + println!(""); + } + Ok(()) +} diff --git a/types/src/config/devices.rs b/types/src/config/devices.rs new file mode 100644 index 0000000..b4d12c3 --- /dev/null +++ b/types/src/config/devices.rs @@ -0,0 +1,10 @@ +use crate::DeviceID; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct Device { + #[serde(rename = "deviceID")] + pub id: DeviceID, + pub name: String, + pub addresses: Vec, +} diff --git a/types/src/config/folders.rs b/types/src/config/folders.rs new file mode 100644 index 0000000..a588ade --- /dev/null +++ b/types/src/config/folders.rs @@ -0,0 +1,17 @@ +use crate::{DeviceID, FolderID}; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct Folder { + pub id: FolderID, + pub label: String, + pub path: String, + pub paused: bool, + pub devices: Vec, +} + +#[derive(Deserialize, Debug)] +struct FolderDevice { + #[serde(rename = "deviceID")] + device_id: DeviceID, +} diff --git a/types/src/config/mod.rs b/types/src/config/mod.rs new file mode 100644 index 0000000..fef1df0 --- /dev/null +++ b/types/src/config/mod.rs @@ -0,0 +1,5 @@ +mod devices; +mod folders; + +pub use devices::*; +pub use folders::*; diff --git a/types/src/db/mod.rs b/types/src/db/mod.rs new file mode 100644 index 0000000..7d9d690 --- /dev/null +++ b/types/src/db/mod.rs @@ -0,0 +1,2 @@ +mod status; +pub use status::*; diff --git a/types/src/db/status.rs b/types/src/db/status.rs new file mode 100644 index 0000000..31a5a10 --- /dev/null +++ b/types/src/db/status.rs @@ -0,0 +1,65 @@ +use crate::DeviceID; +use serde::Deserialize; +use std::collections::HashMap; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Status { + pub errors: u32, + pub pull_errors: u32, + pub invalid: String, + + pub global_files: u64, + pub global_directories: u64, + pub global_symlinks: u64, + pub global_deleted: u64, + pub global_bytes: u64, + pub global_total_items: u64, + + pub local_files: u64, + pub local_directories: u64, + pub local_symlinks: u64, + pub local_deleted: u64, + pub local_bytes: u64, + pub local_total_items: u64, + + pub need_files: u64, + pub need_directories: u64, + pub need_symlinks: u64, + pub need_deletes: u64, + pub need_bytes: u64, + pub need_total_items: u64, + + pub receive_only_changed_files: u64, + pub receive_only_changed_directories: u64, + pub receive_only_changed_symlinks: u64, + pub receive_only_changed_deletes: u64, + pub receive_only_changed_bytes: u64, + pub receive_only_total_items: u64, + + pub in_sync_files: u64, + pub in_sync_bytes: u64, + + pub state: FolderState, + pub state_changed: String, + + pub error: String, + + pub version: u64, + pub sequence: u64, + + pub remote_sequence: HashMap, + + pub ignore_patterns: bool, + pub watch_error: String, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum FolderState { + Idle, + Syncing, + Scanning, + Error, + Unknown, +} diff --git a/types/src/events.rs b/types/src/events.rs index 3c8f66a..3a4650a 100644 --- a/types/src/events.rs +++ b/types/src/events.rs @@ -1,4 +1,4 @@ -use crate::{DeviceID, Timestamp}; +use crate::{DeviceID, FolderID, Timestamp}; use crate::{FileName, Folder, FolderName}; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; @@ -8,7 +8,6 @@ use std::collections::HashMap; #[non_exhaustive] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct ConfigSavedEvent { - #[serde(rename = "Version")] pub version: u64, } @@ -80,7 +79,7 @@ pub struct FolderCompletionEvent { #[serde(rename = "device")] pub device_id: DeviceID, #[serde(rename = "folder")] - pub folder_id: String, + pub folder_id: FolderID, pub completion: f64, pub global_bytes: u64, pub need_bytes: u64, diff --git a/types/src/lib.rs b/types/src/lib.rs index b43dcb9..9eec153 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -1,4 +1,6 @@ pub mod cluster; +pub mod config; +pub mod db; pub mod events; pub mod routes; pub mod system; @@ -20,6 +22,7 @@ pub static EMPTY_EVENT_SUBSCRIPTION: Vec = Vec::new(); type FileName = String; //TODO: use separate type? type DeviceID = String; +pub type FolderID = String; type FolderName = String; type Folder = HashMap; pub type Timestamp = DateTime; diff --git a/types/src/routes.rs b/types/src/routes.rs index 3c22335..d27f428 100644 --- a/types/src/routes.rs +++ b/types/src/routes.rs @@ -14,3 +14,9 @@ pub static SYSTEM_UPGRADE: &str = "/rest/system/upgrade"; pub static SYSTEM_VERSION: &str = "/rest/system/version"; pub static CLUSTER_PENDING_DEVICES: &str = "/rest/cluster/pending/devices"; + +pub static CONFIG_ALL: &str = "/rest/config"; +pub static CONFIG_FOLDERS: &str = "/rest/config/folders"; +pub static CONFIG_DEVICES: &str = "/rest/config/devices"; + +pub static DB_STATUS: &str = "/rest/db/status?folder=";