diff --git a/bin/tau/tau-cli/src/main.rs b/bin/tau/tau-cli/src/main.rs index 5001396d6..375beef5a 100644 --- a/bin/tau/tau-cli/src/main.rs +++ b/bin/tau/tau-cli/src/main.rs @@ -21,6 +21,8 @@ use primitives::{task_from_cli, State, TaskEvent}; use util::{desc_in_editor, due_as_timestamp}; use view::{comments_as_string, print_task_info, print_task_list}; +const DEFAULT_PATH: &str = "~/tau_exported_tasks"; + #[derive(Parser)] #[clap(name = "tau", version)] struct Args { @@ -76,6 +78,12 @@ enum TauSubcommand { /// Tau workspace workspace: String, }, + + /// Import tasks from a specified directory. + Import { path: Option }, + + /// Export tasks to a specified directory. + Export { path: Option }, } pub struct Tau { @@ -153,6 +161,23 @@ async fn main() -> Result<()> { tau.switch_ws(workspace).await?; Ok(()) } + + TauSubcommand::Export { path } => { + if path.is_some() { + tau.export_to(path.unwrap()).await?; + } else { + tau.export_to(DEFAULT_PATH.into()).await?; + } + Ok(()) + } + TauSubcommand::Import { path } => { + if path.is_some() { + tau.import_from(path.unwrap()).await?; + } else { + tau.import_from(DEFAULT_PATH.into()).await?; + } + Ok(()) + } }, None => { let task_ids = tau.get_ids().await?; diff --git a/bin/tau/tau-cli/src/rpc.rs b/bin/tau/tau-cli/src/rpc.rs index 9b69163c2..5c402ba17 100644 --- a/bin/tau/tau-cli/src/rpc.rs +++ b/bin/tau/tau-cli/src/rpc.rs @@ -79,4 +79,24 @@ impl Tau { Ok(()) } + + /// Export tasks. + pub async fn export_to(&self, path: String) -> Result<()> { + let req = JsonRequest::new("export", json!([path])); + let rep = self.rpc_client.request(req).await?; + + debug!("Got reply: {:?}", rep); + + Ok(()) + } + + /// Import tasks. + pub async fn import_from(&self, path: String) -> Result<()> { + let req = JsonRequest::new("import", json!([path])); + let rep = self.rpc_client.request(req).await?; + + debug!("Got reply: {:?}", rep); + + Ok(()) + } } diff --git a/bin/tau/taud/src/jsonrpc.rs b/bin/tau/taud/src/jsonrpc.rs index 785458edf..7faf57cbb 100644 --- a/bin/tau/taud/src/jsonrpc.rs +++ b/bin/tau/taud/src/jsonrpc.rs @@ -1,5 +1,5 @@ use async_std::sync::{Arc, Mutex}; -use std::path::PathBuf; +use std::{fs::create_dir_all, path::PathBuf}; use async_trait::async_trait; use fxhash::FxHashMap; @@ -12,7 +12,7 @@ use darkfi::{ jsonrpc::{ErrorCode, JsonError, JsonRequest, JsonResult}, server::RequestHandler, }, - util::Timestamp, + util::{expand_path, Timestamp}, Error, }; @@ -58,6 +58,8 @@ impl RequestHandler for JsonRpcInterface { Some("set_comment") => self.set_comment(params).await, Some("get_task_by_id") => self.get_task_by_id(params).await, Some("switch_ws") => self.switch_ws(params).await, + Some("export") => self.export_to(params).await, + Some("import") => self.import_from(params).await, Some(_) | None => return JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(), }; @@ -235,6 +237,60 @@ impl JsonRpcInterface { Ok(json!(true)) } + // RPCAPI: + // Export tasks. + // --> {"jsonrpc": "2.0", "method": "export_to", "params": [path], "id": 1} + // <-- {"jsonrpc": "2.0", "result": "true", "id": 1} + async fn export_to(&self, params: &[Value]) -> TaudResult { + debug!(target: "tau", "JsonRpc::export_to() params {:?}", params); + + if params.len() != 1 { + return Err(TaudError::InvalidData("len of params should be 1".into())) + } + + if !params[0].is_string() { + return Err(TaudError::InvalidData("Invalid path".into())) + } + + let path = expand_path(params[0].as_str().unwrap())?.join("exported_tasks"); + // mkdir datastore_path if not exists + create_dir_all(path.join("month")).map_err(Error::from)?; + create_dir_all(path.join("task")).map_err(Error::from)?; + let mt = MonthTasks::load_or_create(None, &self.dataset_path)?; + let tasks = mt.objects(&self.dataset_path)?; + + for task in tasks { + task.save(&path)?; + } + + Ok(json!(true)) + } + + // RPCAPI: + // Import tasks. + // --> {"jsonrpc": "2.0", "method": "import_from", "params": [path], "id": 1} + // <-- {"jsonrpc": "2.0", "result": "true", "id": 1} + async fn import_from(&self, params: &[Value]) -> TaudResult { + debug!(target: "tau", "JsonRpc::import_from() params {:?}", params); + + if params.len() != 1 { + return Err(TaudError::InvalidData("len of params should be 1".into())) + } + + if !params[0].is_string() { + return Err(TaudError::InvalidData("Invalid path".into())) + } + + let path = expand_path(params[0].as_str().unwrap())?.join("exported_tasks"); + let mt = MonthTasks::load_or_create(None, &path)?; + let tasks = mt.objects(&path)?; + + for task in tasks { + self.notify_queue_sender.send(task).await.map_err(Error::from)?; + } + Ok(json!(true)) + } + fn load_task_by_id(&self, task_id: &Value, ws: String) -> TaudResult { let task_id: u64 = serde_json::from_value(task_id.clone())?; let tasks = MonthTasks::load_current_open_tasks(&self.dataset_path, ws)?;