diff --git a/src/kv.rs b/src/kv.rs index 1ad3680..0aa309a 100644 --- a/src/kv.rs +++ b/src/kv.rs @@ -1,5 +1,6 @@ use crate::{get_blob, Message, PackageId, Request}; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use std::marker::PhantomData; use thiserror::Error; /// Actions are sent to a specific key value database, "db" is the name, @@ -54,14 +55,21 @@ pub enum KvError { /// Opening or creating a kv will give you a Result. /// You can call it's impl functions to interact with it. #[derive(Debug, Serialize, Deserialize)] -pub struct Kv { +pub struct Kv { pub package_id: PackageId, pub db: String, + pub timeout: u64, + _marker: PhantomData<(K, V)>, } -impl Kv { +impl Kv +where + K: Serialize + DeserializeOwned, + V: Serialize + DeserializeOwned, +{ /// Get a value. - pub fn get(&self, key: Vec) -> anyhow::Result> { + pub fn get(&self, key: &K) -> anyhow::Result { + let key = serde_json::to_vec(key)?; let res = Request::new() .target(("our", "kv", "distro", "sys")) .body(serde_json::to_vec(&KvRequest { @@ -69,7 +77,7 @@ impl Kv { db: self.db.clone(), action: KvAction::Get { key }, })?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -81,7 +89,9 @@ impl Kv { Some(bytes) => bytes.bytes, None => return Err(anyhow::anyhow!("kv: no blob")), }; - Ok(bytes) + let value = serde_json::from_slice::(&bytes) + .map_err(|e| anyhow::anyhow!("Failed to deserialize value: {}", e))?; + Ok(value) } KvResponse::Err { error } => Err(error.into()), _ => Err(anyhow::anyhow!("kv: unexpected response {:?}", response)), @@ -92,7 +102,10 @@ impl Kv { } /// Set a value, optionally in a transaction. - pub fn set(&self, key: Vec, value: Vec, tx_id: Option) -> anyhow::Result<()> { + pub fn set(&self, key: &K, value: &V, tx_id: Option) -> anyhow::Result<()> { + let key = serde_json::to_vec(key)?; + let value = serde_json::to_vec(value)?; + let res = Request::new() .target(("our", "kv", "distro", "sys")) .body(serde_json::to_vec(&KvRequest { @@ -101,7 +114,7 @@ impl Kv { action: KvAction::Set { key, tx_id }, })?) .blob_bytes(value) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -118,7 +131,8 @@ impl Kv { } /// Delete a value, optionally in a transaction. - pub fn delete(&self, key: Vec, tx_id: Option) -> anyhow::Result<()> { + pub fn delete(&self, key: &K, tx_id: Option) -> anyhow::Result<()> { + let key = serde_json::to_vec(key)?; let res = Request::new() .target(("our", "kv", "distro", "sys")) .body(serde_json::to_vec(&KvRequest { @@ -126,7 +140,7 @@ impl Kv { db: self.db.clone(), action: KvAction::Delete { key, tx_id }, })?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -151,7 +165,7 @@ impl Kv { db: self.db.clone(), action: KvAction::BeginTx, })?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -176,7 +190,7 @@ impl Kv { db: self.db.clone(), action: KvAction::Commit { tx_id }, })?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -194,7 +208,13 @@ impl Kv { } /// Opens or creates a kv db. -pub fn open(package_id: PackageId, db: &str) -> anyhow::Result { +pub fn open(package_id: PackageId, db: &str, timeout: Option) -> anyhow::Result> +where + K: Serialize + DeserializeOwned, + V: Serialize + DeserializeOwned, +{ + let timeout = timeout.unwrap_or(5); + let res = Request::new() .target(("our", "kv", "distro", "sys")) .body(serde_json::to_vec(&KvRequest { @@ -202,7 +222,7 @@ pub fn open(package_id: PackageId, db: &str) -> anyhow::Result { db: db.to_string(), action: KvAction::Open, })?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -212,6 +232,8 @@ pub fn open(package_id: PackageId, db: &str) -> anyhow::Result { KvResponse::Ok => Ok(Kv { package_id, db: db.to_string(), + timeout, + _marker: PhantomData, }), KvResponse::Err { error } => Err(error.into()), _ => Err(anyhow::anyhow!("kv: unexpected response {:?}", response)), @@ -222,7 +244,9 @@ pub fn open(package_id: PackageId, db: &str) -> anyhow::Result { } /// Removes and deletes a kv db. -pub fn remove_db(package_id: PackageId, db: &str) -> anyhow::Result<()> { +pub fn remove_db(package_id: PackageId, db: &str, timeout: Option) -> anyhow::Result<()> { + let timeout = timeout.unwrap_or(5); + let res = Request::new() .target(("our", "kv", "distro", "sys")) .body(serde_json::to_vec(&KvRequest { @@ -230,7 +254,7 @@ pub fn remove_db(package_id: PackageId, db: &str) -> anyhow::Result<()> { db: db.to_string(), action: KvAction::RemoveDb, })?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match res { Ok(Message::Response { body, .. }) => { diff --git a/src/sqlite.rs b/src/sqlite.rs index 6bd1374..f87e120 100644 --- a/src/sqlite.rs +++ b/src/sqlite.rs @@ -79,6 +79,7 @@ pub enum SqliteError { pub struct Sqlite { pub package_id: PackageId, pub db: String, + pub timeout: u64, } impl Sqlite { @@ -96,7 +97,7 @@ impl Sqlite { action: SqliteAction::Read { query }, })?) .blob_bytes(serde_json::to_vec(¶ms)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -141,7 +142,7 @@ impl Sqlite { action: SqliteAction::Write { statement, tx_id }, })?) .blob_bytes(serde_json::to_vec(¶ms)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -169,7 +170,7 @@ impl Sqlite { db: self.db.clone(), action: SqliteAction::BeginTx, })?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -197,7 +198,7 @@ impl Sqlite { db: self.db.clone(), action: SqliteAction::Commit { tx_id }, })?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -218,7 +219,9 @@ impl Sqlite { } /// Open or create sqlite database. -pub fn open(package_id: PackageId, db: &str) -> anyhow::Result { +pub fn open(package_id: PackageId, db: &str, timeout: Option) -> anyhow::Result { + let timeout = timeout.unwrap_or(5); + let res = Request::new() .target(("our", "sqlite", "distro", "sys")) .body(serde_json::to_vec(&SqliteRequest { @@ -226,7 +229,7 @@ pub fn open(package_id: PackageId, db: &str) -> anyhow::Result { db: db.to_string(), action: SqliteAction::Open, })?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match res { Ok(Message::Response { body, .. }) => { @@ -236,6 +239,7 @@ pub fn open(package_id: PackageId, db: &str) -> anyhow::Result { SqliteResponse::Ok => Ok(Sqlite { package_id, db: db.to_string(), + timeout, }), SqliteResponse::Err { error } => Err(error.into()), _ => Err(anyhow::anyhow!( @@ -249,7 +253,9 @@ pub fn open(package_id: PackageId, db: &str) -> anyhow::Result { } /// Remove and delete sqlite database. -pub fn remove_db(package_id: PackageId, db: &str) -> anyhow::Result<()> { +pub fn remove_db(package_id: PackageId, db: &str, timeout: Option) -> anyhow::Result<()> { + let timeout = timeout.unwrap_or(5); + let res = Request::new() .target(("our", "sqlite", "distro", "sys")) .body(serde_json::to_vec(&SqliteRequest { @@ -257,7 +263,7 @@ pub fn remove_db(package_id: PackageId, db: &str) -> anyhow::Result<()> { db: db.to_string(), action: SqliteAction::RemoveDb, })?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match res { Ok(Message::Response { body, .. }) => { diff --git a/src/vfs/directory.rs b/src/vfs/directory.rs index 31fb296..6cc8154 100644 --- a/src/vfs/directory.rs +++ b/src/vfs/directory.rs @@ -6,6 +6,7 @@ use crate::{Message, Request}; /// You can call it's impl functions to interact with it. pub struct Directory { pub path: String, + pub timeout: u64, } impl Directory { @@ -19,7 +20,7 @@ impl Directory { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -37,10 +38,12 @@ impl Directory { /// Opens or creates a directory at path. /// If trying to create an existing directory, will just give you the path. -pub fn open_dir(path: &str, create: bool) -> anyhow::Result { +pub fn open_dir(path: &str, create: bool, timeout: Option) -> anyhow::Result { + let timeout = timeout.unwrap_or(5); if !create { return Ok(Directory { path: path.to_string(), + timeout, }); } let request = VfsRequest { @@ -51,7 +54,7 @@ pub fn open_dir(path: &str, create: bool) -> anyhow::Result { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -59,6 +62,7 @@ pub fn open_dir(path: &str, create: bool) -> anyhow::Result { match response { VfsResponse::Ok => Ok(Directory { path: path.to_string(), + timeout, }), VfsResponse::Err(e) => Err(e.into()), _ => Err(anyhow::anyhow!("vfs: unexpected response: {:?}", response)), @@ -69,7 +73,9 @@ pub fn open_dir(path: &str, create: bool) -> anyhow::Result { } /// Removes a dir at path, errors if path not found or path is not a directory. -pub fn remove_dir(path: &str) -> anyhow::Result<()> { +pub fn remove_dir(path: &str, timeout: Option) -> anyhow::Result<()> { + let timeout = timeout.unwrap_or(5); + let request = VfsRequest { path: path.to_string(), action: VfsAction::RemoveDir, @@ -78,7 +84,7 @@ pub fn remove_dir(path: &str) -> anyhow::Result<()> { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match message { Ok(Message::Response { body, .. }) => { diff --git a/src/vfs/file.rs b/src/vfs/file.rs index ef46345..6d38e82 100644 --- a/src/vfs/file.rs +++ b/src/vfs/file.rs @@ -6,6 +6,7 @@ use crate::{get_blob, Message, PackageId, Request}; /// You can call it's impl functions to interact with it. pub struct File { pub path: String, + pub timeout: u64, } impl File { @@ -19,7 +20,7 @@ impl File { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -50,7 +51,7 @@ impl File { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -84,7 +85,7 @@ impl File { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -117,7 +118,7 @@ impl File { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -149,7 +150,7 @@ impl File { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -176,7 +177,7 @@ impl File { .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) .blob_bytes(buffer) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -201,7 +202,7 @@ impl File { .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) .blob_bytes(buffer) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -226,7 +227,7 @@ impl File { .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) .blob_bytes(buffer) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -251,7 +252,7 @@ impl File { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -286,6 +287,7 @@ impl File { match response { VfsResponse::Ok => Ok(File { path: path.to_string(), + timeout: self.timeout, }), VfsResponse::Err(e) => Err(e.into()), _ => Err(anyhow::anyhow!("vfs: unexpected response: {:?}", response)), @@ -304,7 +306,7 @@ impl File { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -328,7 +330,7 @@ impl File { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -352,7 +354,7 @@ impl File { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(self.timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -371,7 +373,13 @@ impl File { /// Creates a drive with path "/package_id/drive", gives you read and write caps. /// Will only work on the same package_id as you're calling it from, unless you /// have root capabilities. -pub fn create_drive(package_id: PackageId, drive: &str) -> anyhow::Result { +pub fn create_drive( + package_id: PackageId, + drive: &str, + timeout: Option, +) -> anyhow::Result { + let timeout = timeout.unwrap_or(5); + let path = format!("/{}/{}", package_id, drive); let res = Request::new() .target(("our", "vfs", "distro", "sys")) @@ -379,7 +387,7 @@ pub fn create_drive(package_id: PackageId, drive: &str) -> anyhow::Result { @@ -395,7 +403,9 @@ pub fn create_drive(package_id: PackageId, drive: &str) -> anyhow::Result anyhow::Result { +pub fn open_file(path: &str, create: bool, timeout: Option) -> anyhow::Result { + let timeout = timeout.unwrap_or(5); + let request = VfsRequest { path: path.to_string(), action: VfsAction::OpenFile { create }, @@ -404,7 +414,7 @@ pub fn open_file(path: &str, create: bool) -> anyhow::Result { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -412,6 +422,7 @@ pub fn open_file(path: &str, create: bool) -> anyhow::Result { match response { VfsResponse::Ok => Ok(File { path: path.to_string(), + timeout, }), VfsResponse::Err(e) => Err(e.into()), _ => Err(anyhow::anyhow!("vfs: unexpected response: {:?}", response)), @@ -422,7 +433,8 @@ pub fn open_file(path: &str, create: bool) -> anyhow::Result { } /// Creates a file at path, if file found at path, truncates it to 0. -pub fn create_file(path: &str) -> anyhow::Result { +pub fn create_file(path: &str, timeout: Option) -> anyhow::Result { + let timeout = timeout.unwrap_or(5); let request = VfsRequest { path: path.to_string(), action: VfsAction::CreateFile, @@ -431,7 +443,7 @@ pub fn create_file(path: &str) -> anyhow::Result { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -439,6 +451,7 @@ pub fn create_file(path: &str) -> anyhow::Result { match response { VfsResponse::Ok => Ok(File { path: path.to_string(), + timeout, }), VfsResponse::Err(e) => Err(e.into()), _ => Err(anyhow::anyhow!("vfs: unexpected response: {:?}", response)), @@ -449,7 +462,9 @@ pub fn create_file(path: &str) -> anyhow::Result { } /// Removes a file at path, errors if path not found or path is not a file. -pub fn remove_file(path: &str) -> anyhow::Result<()> { +pub fn remove_file(path: &str, timeout: Option) -> anyhow::Result<()> { + let timeout = timeout.unwrap_or(5); + let request = VfsRequest { path: path.to_string(), action: VfsAction::RemoveFile, @@ -458,7 +473,7 @@ pub fn remove_file(path: &str) -> anyhow::Result<()> { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match message { Ok(Message::Response { body, .. }) => { diff --git a/src/vfs/mod.rs b/src/vfs/mod.rs index cefbdbe..5f0aa5f 100644 --- a/src/vfs/mod.rs +++ b/src/vfs/mod.rs @@ -127,7 +127,9 @@ impl VfsError { } /// Metadata of a path, returns file type and length. -pub fn metadata(path: &str) -> anyhow::Result { +pub fn metadata(path: &str, timeout: Option) -> anyhow::Result { + let timeout = timeout.unwrap_or(5); + let request = VfsRequest { path: path.to_string(), action: VfsAction::Metadata, @@ -135,7 +137,7 @@ pub fn metadata(path: &str) -> anyhow::Result { let message = Request::new() .target(("our", "vfs", "distro", "sys")) .body(serde_json::to_vec(&request)?) - .send_and_await_response(5)?; + .send_and_await_response(timeout)?; match message { Ok(Message::Response { body, .. }) => { @@ -151,11 +153,11 @@ pub fn metadata(path: &str) -> anyhow::Result { } /// Removes a path, if it's either a directory or a file. -pub fn remove_path(path: &str) -> anyhow::Result<()> { - let meta = metadata(path)?; +pub fn remove_path(path: &str, timeout: Option) -> anyhow::Result<()> { + let meta = metadata(path, timeout)?; match meta.file_type { - FileType::Directory => remove_dir(path), - FileType::File => remove_file(path), + FileType::Directory => remove_dir(path, timeout), + FileType::File => remove_file(path, timeout), _ => Err(anyhow::anyhow!( "vfs: path is not a file or directory: {}", path