|
|
@@ -22,8 +22,7 @@ use async_std::sync::Mutex;
|
|
|
use async_trait::async_trait;
|
|
|
use crypto_box::ChaChaBox;
|
|
|
use log::{debug, warn};
|
|
|
-use serde::{Deserialize, Serialize};
|
|
|
-use serde_json::{json, Value};
|
|
|
+use tinyjson::JsonValue;
|
|
|
|
|
|
use darkfi::{
|
|
|
net,
|
|
|
@@ -51,43 +50,25 @@ pub struct JsonRpcInterface {
|
|
|
p2p: net::P2pPtr,
|
|
|
}
|
|
|
|
|
|
-#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
-struct BaseTaskInfo {
|
|
|
- title: String,
|
|
|
- tags: Vec<String>,
|
|
|
- desc: String,
|
|
|
- assign: Vec<String>,
|
|
|
- project: Vec<String>,
|
|
|
- due: Option<Timestamp>,
|
|
|
- rank: Option<f32>,
|
|
|
-}
|
|
|
-
|
|
|
#[async_trait]
|
|
|
impl RequestHandler for JsonRpcInterface {
|
|
|
async fn handle_request(&self, req: JsonRequest) -> JsonResult {
|
|
|
- if !req.params.is_array() {
|
|
|
- return JsonError::new(ErrorCode::InvalidParams, None, req.id).into()
|
|
|
- }
|
|
|
-
|
|
|
- let params = req.params.as_array().unwrap();
|
|
|
-
|
|
|
let rep = match req.method.as_str() {
|
|
|
- Some("add") => self.add(params).await,
|
|
|
- Some("get_ids") => self.get_ids(params).await,
|
|
|
- Some("update") => self.update(params).await,
|
|
|
- Some("set_state") => self.set_state(params).await,
|
|
|
- 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("get_ws") => self.get_ws(params).await,
|
|
|
- Some("export") => self.export_to(params).await,
|
|
|
- Some("import") => self.import_from(params).await,
|
|
|
- Some("get_stop_tasks") => self.get_stop_tasks(params).await,
|
|
|
- Some("ping") => self.pong(params).await,
|
|
|
-
|
|
|
- Some("dnet_switch") => self.dnet_switch(params).await,
|
|
|
- Some("dnet_info") => self.dnet_info(params).await,
|
|
|
- Some(_) | None => return JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(),
|
|
|
+ "add" => self.add(req.params).await,
|
|
|
+ "get_ids" => self.get_ids(req.params).await,
|
|
|
+ "update" => self.update(req.params).await,
|
|
|
+ "set_state" => self.set_state(req.params).await,
|
|
|
+ "set_comment" => self.set_comment(req.params).await,
|
|
|
+ "get_task_by_id" => self.get_task_by_id(req.params).await,
|
|
|
+ "switch_ws" => self.switch_ws(req.params).await,
|
|
|
+ "get_ws" => self.get_ws(req.params).await,
|
|
|
+ "export" => self.export_to(req.params).await,
|
|
|
+ "import" => self.import_from(req.params).await,
|
|
|
+ "get_stop_tasks" => self.get_stop_tasks(req.params).await,
|
|
|
+
|
|
|
+ "ping" => return self.pong(req.id, req.params).await,
|
|
|
+ "dnet_switch" => self.dnet_switch(req.params).await,
|
|
|
+ _ => return JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(),
|
|
|
};
|
|
|
|
|
|
to_json_result(rep, req.id)
|
|
|
@@ -106,15 +87,6 @@ impl JsonRpcInterface {
|
|
|
Self { dataset_path, nickname, workspace, workspaces, notify_queue_sender, p2p }
|
|
|
}
|
|
|
|
|
|
- // RPCAPI:
|
|
|
- // Replies to a ping method.
|
|
|
- //
|
|
|
- // --> {"jsonrpc": "2.0", "method": "ping", "params": [], "id": 42}
|
|
|
- // <-- {"jsonrpc": "2.0", "result": "pong", "id": 42}
|
|
|
- async fn pong(&self, _params: &[Value]) -> TaudResult<Value> {
|
|
|
- Ok(json!("pong"))
|
|
|
- }
|
|
|
-
|
|
|
// RPCAPI:
|
|
|
// Activate or deactivate dnet in the P2P stack.
|
|
|
// By sending `true`, dnet will be activated, and by sending `false` dnet will
|
|
|
@@ -122,28 +94,21 @@ impl JsonRpcInterface {
|
|
|
//
|
|
|
// --> {"jsonrpc": "2.0", "method": "dnet_switch", "params": [true], "id": 42}
|
|
|
// <-- {"jsonrpc": "2.0", "result": true, "id": 42}
|
|
|
- async fn dnet_switch(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
- if params.len() != 1 && params[0].as_bool().is_none() {
|
|
|
+ async fn dnet_switch(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
+ if params.len() != 1 || !params[0].is_bool() {
|
|
|
return Err(TaudError::InvalidData("Invalid parameters".into()))
|
|
|
}
|
|
|
|
|
|
- if params[0].as_bool().unwrap() {
|
|
|
+ let switch = params[0].get::<bool>().unwrap();
|
|
|
+
|
|
|
+ if *switch {
|
|
|
self.p2p.dnet_enable().await;
|
|
|
} else {
|
|
|
self.p2p.dnet_disable().await;
|
|
|
}
|
|
|
|
|
|
- Ok(json!(true))
|
|
|
- }
|
|
|
-
|
|
|
- // RPCAPI:
|
|
|
- // Retrieves P2P network information.
|
|
|
- //
|
|
|
- // --> {"jsonrpc": "2.0", "method": "dnet_info", "params": [], "id": 42}
|
|
|
- // <-- {"jsonrpc": "2.0", result": {"nodeID": [], "nodeinfo": [], "id": 42}
|
|
|
- async fn dnet_info(&self, _params: &[Value]) -> TaudResult<Value> {
|
|
|
- let dnet_info = self.p2p.dnet_info().await;
|
|
|
- Ok(net::P2p::map_dnet_info(dnet_info))
|
|
|
+ Ok(JsonValue::Boolean(true))
|
|
|
}
|
|
|
|
|
|
// RPCAPI:
|
|
|
@@ -161,79 +126,156 @@ impl JsonRpcInterface {
|
|
|
// "id": 1
|
|
|
// }
|
|
|
// <-- {"jsonrpc": "2.0", "result": true, "id": 1}
|
|
|
- async fn add(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
+ async fn add(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::add() params {:?}", params);
|
|
|
|
|
|
- let task: BaseTaskInfo = serde_json::from_value(params[0].clone())?;
|
|
|
+ if params.len() != 7 ||
|
|
|
+ !params[0].is_string() ||
|
|
|
+ !params[1].is_array() ||
|
|
|
+ !params[2].is_string() ||
|
|
|
+ !params[3].is_array() ||
|
|
|
+ !params[4].is_array()
|
|
|
+ {
|
|
|
+ return Err(TaudError::InvalidData("Invalid parameters".to_string()))
|
|
|
+ }
|
|
|
+
|
|
|
+ let due = match ¶ms[5] {
|
|
|
+ JsonValue::Null => None,
|
|
|
+ JsonValue::String(u64_str) => match u64::from_str_radix(&u64_str, 10) {
|
|
|
+ Ok(v) => Some(Timestamp(v)),
|
|
|
+ Err(e) => return Err(TaudError::InvalidData(e.to_string())),
|
|
|
+ },
|
|
|
+ _ => return Err(TaudError::InvalidData("Invalid parameters".to_string())),
|
|
|
+ };
|
|
|
+
|
|
|
+ let rank = match params[6] {
|
|
|
+ JsonValue::Null => None,
|
|
|
+ JsonValue::Number(numba) => Some(numba as f32),
|
|
|
+ _ => return Err(TaudError::InvalidData("Invalid parameters".to_string())),
|
|
|
+ };
|
|
|
+
|
|
|
+ let tags = {
|
|
|
+ let mut tags = vec![];
|
|
|
+
|
|
|
+ for val in params[1].get::<Vec<JsonValue>>().unwrap().iter() {
|
|
|
+ if let Some(tag) = val.get::<String>() {
|
|
|
+ tags.push(tag.clone());
|
|
|
+ } else {
|
|
|
+ return Err(TaudError::InvalidData("Invalid parameters".to_string()))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ tags
|
|
|
+ };
|
|
|
+
|
|
|
+ let assigns = {
|
|
|
+ let mut assigns = vec![];
|
|
|
+
|
|
|
+ for val in params[3].get::<Vec<JsonValue>>().unwrap().iter() {
|
|
|
+ if let Some(assign) = val.get::<String>() {
|
|
|
+ assigns.push(assign.clone());
|
|
|
+ } else {
|
|
|
+ return Err(TaudError::InvalidData("Invalid parameters".to_string()))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ assigns
|
|
|
+ };
|
|
|
+
|
|
|
+ let projects = {
|
|
|
+ let mut projects = vec![];
|
|
|
+
|
|
|
+ for val in params[4].get::<Vec<JsonValue>>().unwrap().iter() {
|
|
|
+ if let Some(project) = val.get::<String>() {
|
|
|
+ projects.push(project.clone());
|
|
|
+ } else {
|
|
|
+ return Err(TaudError::InvalidData("Invalid parameters".to_string()))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ projects
|
|
|
+ };
|
|
|
+
|
|
|
let mut new_task: TaskInfo = TaskInfo::new(
|
|
|
self.workspace.lock().await.clone(),
|
|
|
- &task.title,
|
|
|
- &task.desc,
|
|
|
+ ¶ms[0].get::<String>().unwrap(),
|
|
|
+ ¶ms[2].get::<String>().unwrap(),
|
|
|
&self.nickname,
|
|
|
- task.due,
|
|
|
- task.rank,
|
|
|
+ due,
|
|
|
+ rank,
|
|
|
&self.dataset_path,
|
|
|
)?;
|
|
|
- new_task.set_project(&task.project);
|
|
|
- new_task.set_assign(&task.assign);
|
|
|
- new_task.set_tags(&task.tags);
|
|
|
+ new_task.set_project(&projects);
|
|
|
+ new_task.set_assign(&assigns);
|
|
|
+ new_task.set_tags(&tags);
|
|
|
|
|
|
self.notify_queue_sender.send(new_task.clone()).await.map_err(Error::from)?;
|
|
|
- Ok(json!(new_task.id))
|
|
|
+ Ok(JsonValue::Number(new_task.id.into()))
|
|
|
}
|
|
|
|
|
|
// RPCAPI:
|
|
|
// List tasks
|
|
|
// --> {"jsonrpc": "2.0", "method": "get_ids", "params": [], "id": 1}
|
|
|
// <-- {"jsonrpc": "2.0", "result": [task_id, ...], "id": 1}
|
|
|
- async fn get_ids(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
+ async fn get_ids(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::get_ids() params {:?}", params);
|
|
|
|
|
|
let ws = self.workspace.lock().await.clone();
|
|
|
let tasks = MonthTasks::load_current_tasks(&self.dataset_path, ws, false)?;
|
|
|
|
|
|
- let task_ids: Vec<u32> = tasks.iter().map(|task| task.get_id()).collect();
|
|
|
+ let task_ids: Vec<JsonValue> =
|
|
|
+ tasks.iter().map(|task| JsonValue::Number(task.get_id().into())).collect();
|
|
|
|
|
|
- Ok(json!(task_ids))
|
|
|
+ Ok(JsonValue::Array(task_ids))
|
|
|
}
|
|
|
|
|
|
// RPCAPI:
|
|
|
// Update task and returns `true` upon success.
|
|
|
// --> {"jsonrpc": "2.0", "method": "update", "params": [task_id, {"title": "new title"} ], "id": 1}
|
|
|
// <-- {"jsonrpc": "2.0", "result": true, "id": 1}
|
|
|
- async fn update(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
+ async fn update(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::update() params {:?}", params);
|
|
|
|
|
|
- if params.len() != 2 {
|
|
|
+ if params.len() != 2 || !params[0].is_number() || !params[1].is_object() {
|
|
|
return Err(TaudError::InvalidData("len of params should be 2".into()))
|
|
|
}
|
|
|
|
|
|
let ws = self.workspace.lock().await.clone();
|
|
|
- let task = self.check_params_for_update(¶ms[0], ¶ms[1], ws)?;
|
|
|
+
|
|
|
+ let task = self.check_params_for_update(
|
|
|
+ *params[0].get::<f64>().unwrap() as u32,
|
|
|
+ params[1].get::<HashMap<String, JsonValue>>().unwrap(),
|
|
|
+ ws,
|
|
|
+ )?;
|
|
|
|
|
|
self.notify_queue_sender.send(task).await.map_err(Error::from)?;
|
|
|
|
|
|
- Ok(json!(true))
|
|
|
+ Ok(JsonValue::Boolean(true))
|
|
|
}
|
|
|
|
|
|
// RPCAPI:
|
|
|
// Set state for a task and returns `true` upon success.
|
|
|
// --> {"jsonrpc": "2.0", "method": "set_state", "params": [task_id, state], "id": 1}
|
|
|
// <-- {"jsonrpc": "2.0", "result": true, "id": 1}
|
|
|
- async fn set_state(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
+ async fn set_state(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
// Allowed states for a task
|
|
|
let states = ["stop", "start", "open", "pause"];
|
|
|
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::set_state() params {:?}", params);
|
|
|
|
|
|
- if params.len() != 2 {
|
|
|
+ if params.len() != 2 || !params[0].is_number() || !params[1].is_string() {
|
|
|
return Err(TaudError::InvalidData("len of params should be 2".into()))
|
|
|
}
|
|
|
|
|
|
- let state: String = serde_json::from_value(params[1].clone())?;
|
|
|
+ let state = params[1].get::<String>().unwrap();
|
|
|
let ws = self.workspace.lock().await.clone();
|
|
|
|
|
|
- let mut task: TaskInfo = self.load_task_by_id(¶ms[0], ws)?;
|
|
|
+ let mut task: TaskInfo =
|
|
|
+ self.load_task_by_id(*params[0].get::<f64>().unwrap() as u32, ws)?;
|
|
|
|
|
|
if states.contains(&state.as_str()) {
|
|
|
task.set_state(&state);
|
|
|
@@ -242,73 +284,90 @@ impl JsonRpcInterface {
|
|
|
|
|
|
self.notify_queue_sender.send(task).await.map_err(Error::from)?;
|
|
|
|
|
|
- Ok(json!(true))
|
|
|
+ Ok(JsonValue::Boolean(true))
|
|
|
}
|
|
|
|
|
|
// RPCAPI:
|
|
|
// Set comment for a task and returns `true` upon success.
|
|
|
// --> {"jsonrpc": "2.0", "method": "set_comment", "params": [task_id, comment_content], "id": 1}
|
|
|
// <-- {"jsonrpc": "2.0", "result": true, "id": 1}
|
|
|
- async fn set_comment(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
+ async fn set_comment(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::set_comment() params {:?}", params);
|
|
|
|
|
|
- if params.len() != 2 {
|
|
|
+ if params.len() != 2 || !params[0].is_number() || !params[1].is_string() {
|
|
|
return Err(TaudError::InvalidData("len of params should be 2".into()))
|
|
|
}
|
|
|
|
|
|
- let comment_content: String = serde_json::from_value(params[1].clone())?;
|
|
|
+ let id = *params[0].get::<f64>().unwrap() as u32;
|
|
|
+ let comment_content = params[1].get::<String>().unwrap();
|
|
|
|
|
|
let ws = self.workspace.lock().await.clone();
|
|
|
- let mut task: TaskInfo = self.load_task_by_id(¶ms[0], ws)?;
|
|
|
+ let mut task: TaskInfo = self.load_task_by_id(id, ws)?;
|
|
|
|
|
|
task.set_comment(Comment::new(&comment_content, &self.nickname));
|
|
|
set_event(&mut task, "comment", &self.nickname, &comment_content);
|
|
|
|
|
|
self.notify_queue_sender.send(task).await.map_err(Error::from)?;
|
|
|
|
|
|
- Ok(json!(true))
|
|
|
+ Ok(JsonValue::Boolean(true))
|
|
|
}
|
|
|
|
|
|
// RPCAPI:
|
|
|
// Get a task by id.
|
|
|
// --> {"jsonrpc": "2.0", "method": "get_task_by_id", "params": [task_id], "id": 1}
|
|
|
// <-- {"jsonrpc": "2.0", "result": "task", "id": 1}
|
|
|
- async fn get_task_by_id(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
+ async fn get_task_by_id(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::get_task_by_id() params {:?}", params);
|
|
|
|
|
|
- if params.len() != 1 {
|
|
|
+ if params.len() != 1 || !params[0].is_number() {
|
|
|
return Err(TaudError::InvalidData("len of params should be 1".into()))
|
|
|
}
|
|
|
|
|
|
let ws = self.workspace.lock().await.clone();
|
|
|
- let task: TaskInfo = self.load_task_by_id(¶ms[0], ws)?;
|
|
|
+ let task: TaskInfo = self.load_task_by_id(*params[0].get::<f64>().unwrap() as u32, ws)?;
|
|
|
+ let task: JsonValue = (&task).into();
|
|
|
|
|
|
- Ok(json!(task))
|
|
|
+ Ok(task)
|
|
|
}
|
|
|
|
|
|
// RPCAPI:
|
|
|
// Get all tasks.
|
|
|
// --> {"jsonrpc": "2.0", "method": "get_stop_tasks", "params": [task_id], "id": 1}
|
|
|
// <-- {"jsonrpc": "2.0", "result": "task", "id": 1}
|
|
|
- async fn get_stop_tasks(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
+ async fn get_stop_tasks(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::get_stop_tasks() params {:?}", params);
|
|
|
|
|
|
- if params.len() != 1 {
|
|
|
+ if params.len() != 1 || !params[0].is_string() {
|
|
|
return Err(TaudError::InvalidData("len of params should be 1".into()))
|
|
|
}
|
|
|
- let month = params[0].as_u64().map(Timestamp);
|
|
|
+
|
|
|
+ let month = match params[0].get::<String>() {
|
|
|
+ Some(u64_str) => match u64::from_str_radix(u64_str, 10) {
|
|
|
+ Ok(v) => Some(Timestamp(v)),
|
|
|
+ //Err(e) => return Err(TaudError::InvalidData(e.to_string())),
|
|
|
+ Err(_) => None,
|
|
|
+ },
|
|
|
+
|
|
|
+ None => None,
|
|
|
+ };
|
|
|
+
|
|
|
let ws = self.workspace.lock().await.clone();
|
|
|
|
|
|
let tasks = MonthTasks::load_stop_tasks(&self.dataset_path, ws, month.as_ref())?;
|
|
|
+ let tasks: Vec<JsonValue> = tasks.iter().map(|x| x.into()).collect();
|
|
|
|
|
|
- Ok(json!(tasks))
|
|
|
+ Ok(JsonValue::Array(tasks))
|
|
|
}
|
|
|
|
|
|
// RPCAPI:
|
|
|
// Switch tasks workspace.
|
|
|
// --> {"jsonrpc": "2.0", "method": "switch_ws", "params": [workspace], "id": 1}
|
|
|
// <-- {"jsonrpc": "2.0", "result": "true", "id": 1}
|
|
|
- async fn switch_ws(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
+ async fn switch_ws(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::switch_ws() params {:?}", params);
|
|
|
|
|
|
if params.len() != 1 {
|
|
|
@@ -319,34 +378,36 @@ impl JsonRpcInterface {
|
|
|
return Err(TaudError::InvalidData("Invalid workspace".into()))
|
|
|
}
|
|
|
|
|
|
- let ws = params[0].as_str().unwrap().to_string();
|
|
|
+ let ws = params[0].get::<String>().unwrap();
|
|
|
let mut s = self.workspace.lock().await;
|
|
|
|
|
|
- if self.workspaces.contains_key(&ws) {
|
|
|
- *s = ws
|
|
|
+ if self.workspaces.contains_key(ws) {
|
|
|
+ *s = ws.to_string()
|
|
|
} else {
|
|
|
warn!("Workspace \"{}\" is not configured", ws);
|
|
|
- return Ok(json!(false))
|
|
|
+ return Ok(JsonValue::Boolean(false))
|
|
|
}
|
|
|
|
|
|
- Ok(json!(true))
|
|
|
+ Ok(JsonValue::Boolean(true))
|
|
|
}
|
|
|
|
|
|
// RPCAPI:
|
|
|
// Get workspace.
|
|
|
// --> {"jsonrpc": "2.0", "method": "get_ws", "params": [], "id": 1}
|
|
|
// <-- {"jsonrpc": "2.0", "result": "workspace", "id": 1}
|
|
|
- async fn get_ws(&self, params: &[Value]) -> TaudResult<Value> {
|
|
|
+ async fn get_ws(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::get_ws() params {:?}", params);
|
|
|
let ws = self.workspace.lock().await.clone();
|
|
|
- Ok(json!(ws))
|
|
|
+ Ok(JsonValue::String(ws))
|
|
|
}
|
|
|
|
|
|
// 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<Value> {
|
|
|
+ async fn export_to(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::export_to() params {:?}", params);
|
|
|
|
|
|
if params.len() != 1 {
|
|
|
@@ -358,7 +419,8 @@ impl JsonRpcInterface {
|
|
|
}
|
|
|
|
|
|
// mkdir datastore_path if not exists
|
|
|
- let path = expand_path(params[0].as_str().unwrap())?.join("exported_tasks");
|
|
|
+ let path = params[0].get::<String>().unwrap();
|
|
|
+ let path = expand_path(path)?.join("exported_tasks");
|
|
|
create_dir_all(path.join("month")).map_err(Error::from)?;
|
|
|
create_dir_all(path.join("task")).map_err(Error::from)?;
|
|
|
|
|
|
@@ -369,14 +431,15 @@ impl JsonRpcInterface {
|
|
|
task.save(&path)?;
|
|
|
}
|
|
|
|
|
|
- Ok(json!(true))
|
|
|
+ Ok(JsonValue::Boolean(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<Value> {
|
|
|
+ async fn import_from(&self, params: JsonValue) -> TaudResult<JsonValue> {
|
|
|
+ let params = params.get::<Vec<JsonValue>>().unwrap();
|
|
|
debug!(target: "tau", "JsonRpc::import_from() params {:?}", params);
|
|
|
|
|
|
if params.len() != 1 {
|
|
|
@@ -387,7 +450,8 @@ impl JsonRpcInterface {
|
|
|
return Err(TaudError::InvalidData("Invalid path".into()))
|
|
|
}
|
|
|
|
|
|
- let path = expand_path(params[0].as_str().unwrap())?.join("exported_tasks");
|
|
|
+ let path = params[0].get::<String>().unwrap();
|
|
|
+ let path = expand_path(path)?.join("exported_tasks");
|
|
|
let ws = self.workspace.lock().await.clone();
|
|
|
|
|
|
let mut task_ids: Vec<u32> =
|
|
|
@@ -411,34 +475,26 @@ impl JsonRpcInterface {
|
|
|
task_ids.push(task.id);
|
|
|
self.notify_queue_sender.send(task).await.map_err(Error::from)?;
|
|
|
}
|
|
|
- Ok(json!(true))
|
|
|
+ Ok(JsonValue::Boolean(true))
|
|
|
}
|
|
|
|
|
|
- fn load_task_by_id(&self, task_id: &Value, ws: String) -> TaudResult<TaskInfo> {
|
|
|
- let task_id: u64 = serde_json::from_value(task_id.clone())?;
|
|
|
+ fn load_task_by_id(&self, task_id: u32, ws: String) -> TaudResult<TaskInfo> {
|
|
|
let tasks = MonthTasks::load_current_tasks(&self.dataset_path, ws, false)?;
|
|
|
- let task = tasks.into_iter().find(|t| (t.get_id() as u64) == task_id);
|
|
|
+ let task = tasks.into_iter().find(|t| (t.get_id()) == task_id);
|
|
|
|
|
|
task.ok_or(TaudError::InvalidId)
|
|
|
}
|
|
|
|
|
|
fn check_params_for_update(
|
|
|
&self,
|
|
|
- task_id: &Value,
|
|
|
- fields: &Value,
|
|
|
+ task_id: u32,
|
|
|
+ fields: &HashMap<String, JsonValue>,
|
|
|
ws: String,
|
|
|
) -> TaudResult<TaskInfo> {
|
|
|
let mut task: TaskInfo = self.load_task_by_id(task_id, ws)?;
|
|
|
|
|
|
- if !fields.is_object() {
|
|
|
- return Err(TaudError::InvalidData("Invalid task's data".into()))
|
|
|
- }
|
|
|
-
|
|
|
- let fields = fields.as_object().unwrap();
|
|
|
-
|
|
|
if fields.contains_key("title") {
|
|
|
- let title = fields.get("title").unwrap().clone();
|
|
|
- let title: String = serde_json::from_value(title)?;
|
|
|
+ let title = fields["title"].get::<String>().unwrap();
|
|
|
if !title.is_empty() {
|
|
|
task.set_title(&title);
|
|
|
set_event(&mut task, "title", &self.nickname, &title);
|
|
|
@@ -446,19 +502,23 @@ impl JsonRpcInterface {
|
|
|
}
|
|
|
|
|
|
if fields.contains_key("desc") {
|
|
|
- let description = fields.get("desc");
|
|
|
- if let Some(description) = description {
|
|
|
- let description: Option<String> = serde_json::from_value(description.clone())?;
|
|
|
- if let Some(desc) = description {
|
|
|
- task.set_desc(&desc);
|
|
|
- set_event(&mut task, "desc", &self.nickname, &desc);
|
|
|
- }
|
|
|
+ let desc = fields["desc"].get::<String>().unwrap();
|
|
|
+ if !desc.is_empty() {
|
|
|
+ task.set_desc(&desc);
|
|
|
+ set_event(&mut task, "desc", &self.nickname, &desc);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if fields.contains_key("rank") {
|
|
|
- let rank_opt = fields.get("rank").unwrap();
|
|
|
- let rank: Option<Option<f32>> = serde_json::from_value(rank_opt.clone())?;
|
|
|
+ // TODO: Why is this a double Option?
|
|
|
+ let rank = {
|
|
|
+ match fields["rank"] {
|
|
|
+ JsonValue::Null => None,
|
|
|
+ JsonValue::Number(rank) => Some(Some(rank as f32)),
|
|
|
+ _ => unreachable!(),
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
if let Some(rank) = rank {
|
|
|
task.set_rank(rank);
|
|
|
match rank {
|
|
|
@@ -473,8 +533,17 @@ impl JsonRpcInterface {
|
|
|
}
|
|
|
|
|
|
if fields.contains_key("due") {
|
|
|
- let due = fields.get("due").unwrap().clone();
|
|
|
- let due: Option<Option<Timestamp>> = serde_json::from_value(due)?;
|
|
|
+ // TODO: Why is this a double Option?
|
|
|
+ let due = {
|
|
|
+ match &fields["due"] {
|
|
|
+ JsonValue::Null => None,
|
|
|
+ JsonValue::String(ts_str) => {
|
|
|
+ Some(Some(Timestamp(u64::from_str_radix(&ts_str, 10).unwrap())))
|
|
|
+ }
|
|
|
+ _ => unreachable!(),
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
if let Some(d) = due {
|
|
|
task.set_due(d);
|
|
|
match d {
|
|
|
@@ -489,8 +558,13 @@ impl JsonRpcInterface {
|
|
|
}
|
|
|
|
|
|
if fields.contains_key("assign") {
|
|
|
- let assign = fields.get("assign").unwrap().clone();
|
|
|
- let assign: Vec<String> = serde_json::from_value(assign)?;
|
|
|
+ let assign: Vec<String> = fields["assign"]
|
|
|
+ .get::<Vec<JsonValue>>()
|
|
|
+ .unwrap()
|
|
|
+ .iter()
|
|
|
+ .map(|x| x.get::<String>().unwrap().clone())
|
|
|
+ .collect();
|
|
|
+
|
|
|
if !assign.is_empty() {
|
|
|
task.set_assign(&assign);
|
|
|
set_event(&mut task, "assign", &self.nickname, &assign.join(", "));
|
|
|
@@ -498,8 +572,13 @@ impl JsonRpcInterface {
|
|
|
}
|
|
|
|
|
|
if fields.contains_key("project") {
|
|
|
- let project = fields.get("project").unwrap().clone();
|
|
|
- let project: Vec<String> = serde_json::from_value(project)?;
|
|
|
+ let project: Vec<String> = fields["project"]
|
|
|
+ .get::<Vec<JsonValue>>()
|
|
|
+ .unwrap()
|
|
|
+ .iter()
|
|
|
+ .map(|x| x.get::<String>().unwrap().clone())
|
|
|
+ .collect();
|
|
|
+
|
|
|
if !project.is_empty() {
|
|
|
task.set_project(&project);
|
|
|
set_event(&mut task, "project", &self.nickname, &project.join(", "));
|
|
|
@@ -507,8 +586,13 @@ impl JsonRpcInterface {
|
|
|
}
|
|
|
|
|
|
if fields.contains_key("tags") {
|
|
|
- let tags = fields.get("tags").unwrap().clone();
|
|
|
- let tags: Vec<String> = serde_json::from_value(tags)?;
|
|
|
+ let tags: Vec<String> = fields["tags"]
|
|
|
+ .get::<Vec<JsonValue>>()
|
|
|
+ .unwrap()
|
|
|
+ .iter()
|
|
|
+ .map(|x| x.get::<String>().unwrap().clone())
|
|
|
+ .collect();
|
|
|
+
|
|
|
if !tags.is_empty() {
|
|
|
task.set_tags(&tags);
|
|
|
set_event(&mut task, "tags", &self.nickname, &tags.join(", "));
|