jsonrpc.rs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. use std::path::PathBuf;
  2. use async_trait::async_trait;
  3. use log::debug;
  4. use serde::{Deserialize, Serialize};
  5. use serde_json::{json, Value};
  6. use darkfi::{
  7. rpc::{
  8. jsonrpc::{ErrorCode, JsonError, JsonRequest, JsonResult},
  9. server::RequestHandler,
  10. },
  11. util::Timestamp,
  12. Error,
  13. };
  14. use crate::{
  15. error::{to_json_result, TaudError, TaudResult},
  16. month_tasks::MonthTasks,
  17. task_info::{Comment, TaskInfo},
  18. };
  19. pub struct JsonRpcInterface {
  20. dataset_path: PathBuf,
  21. notify_queue_sender: async_channel::Sender<Option<TaskInfo>>,
  22. nickname: String,
  23. }
  24. #[derive(Clone, Debug, Serialize, Deserialize)]
  25. struct BaseTaskInfo {
  26. title: String,
  27. desc: String,
  28. assign: Vec<String>,
  29. project: Vec<String>,
  30. due: Option<Timestamp>,
  31. rank: Option<f32>,
  32. }
  33. // TODO: Make more like RPC in darkfid, this implies the method categories,
  34. // and function signatures, and safety checks.
  35. #[async_trait]
  36. impl RequestHandler for JsonRpcInterface {
  37. async fn handle_request(&self, req: JsonRequest) -> JsonResult {
  38. if !req.params.is_array() {
  39. return JsonError::new(ErrorCode::InvalidParams, None, req.id).into()
  40. }
  41. let params = req.params.as_array().unwrap();
  42. if self.notify_queue_sender.send(None).await.is_err() {
  43. return JsonError::new(ErrorCode::InternalError, None, req.id).into()
  44. }
  45. let rep = match req.method.as_str() {
  46. Some("add") => self.add(params).await,
  47. Some("get_ids") => self.get_ids(params).await,
  48. Some("update") => self.update(params).await,
  49. Some("set_state") => self.set_state(params).await,
  50. Some("set_comment") => self.set_comment(params).await,
  51. Some("get_task_by_id") => self.get_task_by_id(params).await,
  52. Some(_) | None => return JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(),
  53. };
  54. to_json_result(rep, req.id)
  55. }
  56. }
  57. impl JsonRpcInterface {
  58. pub fn new(
  59. notify_queue_sender: async_channel::Sender<Option<TaskInfo>>,
  60. dataset_path: PathBuf,
  61. nickname: String,
  62. ) -> Self {
  63. Self { notify_queue_sender, dataset_path, nickname }
  64. }
  65. // RPCAPI:
  66. // Add new task and returns `true` upon success.
  67. // --> {"jsonrpc": "2.0", "method": "add",
  68. // "params":
  69. // [{
  70. // "title": "..",
  71. // "desc": "..",
  72. // assign: [..],
  73. // project: [..],
  74. // "due": ..,
  75. // "rank": ..
  76. // }],
  77. // "id": 1
  78. // }
  79. // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
  80. async fn add(&self, params: &[Value]) -> TaudResult<Value> {
  81. debug!(target: "tau", "JsonRpc::add() params {:?}", params);
  82. let task: BaseTaskInfo = serde_json::from_value(params[0].clone())?;
  83. let mut new_task: TaskInfo = TaskInfo::new(
  84. &task.title,
  85. &task.desc,
  86. &self.nickname,
  87. task.due,
  88. task.rank.unwrap_or(0.0),
  89. &self.dataset_path,
  90. )?;
  91. new_task.set_project(&task.project);
  92. new_task.set_assign(&task.assign);
  93. self.notify_queue_sender.send(Some(new_task)).await.map_err(Error::from)?;
  94. Ok(json!(true))
  95. }
  96. // RPCAPI:
  97. // List tasks
  98. // --> {"jsonrpc": "2.0", "method": "get_ids", "params": [], "id": 1}
  99. // <-- {"jsonrpc": "2.0", "result": [task_id, ...], "id": 1}
  100. async fn get_ids(&self, params: &[Value]) -> TaudResult<Value> {
  101. debug!(target: "tau", "JsonRpc::get_ids() params {:?}", params);
  102. let tasks = MonthTasks::load_current_open_tasks(&self.dataset_path)?;
  103. let task_ids: Vec<u32> = tasks.iter().map(|task| task.get_id()).collect();
  104. Ok(json!(task_ids))
  105. }
  106. // RPCAPI:
  107. // Update task and returns `true` upon success.
  108. // --> {"jsonrpc": "2.0", "method": "update", "params": [task_id, {"title": "new title"} ], "id": 1}
  109. // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
  110. async fn update(&self, params: &[Value]) -> TaudResult<Value> {
  111. debug!(target: "tau", "JsonRpc::update() params {:?}", params);
  112. if params.len() != 2 {
  113. return Err(TaudError::InvalidData("len of params should be 2".into()))
  114. }
  115. let task = self.check_params_for_update(&params[0], &params[1])?;
  116. self.notify_queue_sender.send(Some(task)).await.map_err(Error::from)?;
  117. Ok(json!(true))
  118. }
  119. // RPCAPI:
  120. // Set state for a task and returns `true` upon success.
  121. // --> {"jsonrpc": "2.0", "method": "set_state", "params": [task_id, state], "id": 1}
  122. // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
  123. async fn set_state(&self, params: &[Value]) -> TaudResult<Value> {
  124. // Allowed states for a task
  125. let states = ["stop", "open", "pause"];
  126. debug!(target: "tau", "JsonRpc::set_state() params {:?}", params);
  127. if params.len() != 2 {
  128. return Err(TaudError::InvalidData("len of params should be 2".into()))
  129. }
  130. let state: String = serde_json::from_value(params[1].clone())?;
  131. let mut task: TaskInfo = self.load_task_by_id(&params[0])?;
  132. if states.contains(&state.as_str()) {
  133. task.set_state(&state);
  134. }
  135. self.notify_queue_sender.send(Some(task)).await.map_err(Error::from)?;
  136. Ok(json!(true))
  137. }
  138. // RPCAPI:
  139. // Set comment for a task and returns `true` upon success.
  140. // --> {"jsonrpc": "2.0", "method": "set_comment", "params": [task_id, comment_content], "id": 1}
  141. // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
  142. async fn set_comment(&self, params: &[Value]) -> TaudResult<Value> {
  143. debug!(target: "tau", "JsonRpc::set_comment() params {:?}", params);
  144. if params.len() != 2 {
  145. return Err(TaudError::InvalidData("len of params should be 3".into()))
  146. }
  147. let comment_content: String = serde_json::from_value(params[1].clone())?;
  148. let mut task: TaskInfo = self.load_task_by_id(&params[0])?;
  149. task.set_comment(Comment::new(&comment_content, &self.nickname));
  150. self.notify_queue_sender.send(Some(task)).await.map_err(Error::from)?;
  151. Ok(json!(true))
  152. }
  153. // RPCAPI:
  154. // Get a task by id.
  155. // --> {"jsonrpc": "2.0", "method": "get_task_by_id", "params": [task_id], "id": 1}
  156. // <-- {"jsonrpc": "2.0", "result": "task", "id": 1}
  157. async fn get_task_by_id(&self, params: &[Value]) -> TaudResult<Value> {
  158. debug!(target: "tau", "JsonRpc::get_task_by_id() params {:?}", params);
  159. if params.len() != 1 {
  160. return Err(TaudError::InvalidData("len of params should be 1".into()))
  161. }
  162. let task: TaskInfo = self.load_task_by_id(&params[0])?;
  163. Ok(json!(task))
  164. }
  165. fn load_task_by_id(&self, task_id: &Value) -> TaudResult<TaskInfo> {
  166. let task_id: u64 = serde_json::from_value(task_id.clone())?;
  167. let tasks = MonthTasks::load_current_open_tasks(&self.dataset_path)?;
  168. let task = tasks.into_iter().find(|t| (t.get_id() as u64) == task_id);
  169. task.ok_or(TaudError::InvalidId)
  170. }
  171. fn check_params_for_update(&self, task_id: &Value, fields: &Value) -> TaudResult<TaskInfo> {
  172. let mut task: TaskInfo = self.load_task_by_id(task_id)?;
  173. if !fields.is_object() {
  174. return Err(TaudError::InvalidData("Invalid task's data".into()))
  175. }
  176. let fields = fields.as_object().unwrap();
  177. if fields.contains_key("title") {
  178. let title = fields.get("title").unwrap().clone();
  179. let title: String = serde_json::from_value(title)?;
  180. if !title.is_empty() {
  181. task.set_title(&title);
  182. }
  183. }
  184. if fields.contains_key("desc") {
  185. let description = fields.get("description");
  186. if let Some(description) = description {
  187. let description: String = serde_json::from_value(description.clone())?;
  188. task.set_desc(&description);
  189. }
  190. }
  191. if fields.contains_key("rank") {
  192. let rank_opt = fields.get("rank");
  193. if let Some(rank) = rank_opt {
  194. let rank: Option<f32> = serde_json::from_value(rank.clone())?;
  195. if let Some(r) = rank {
  196. task.set_rank(r);
  197. }
  198. }
  199. }
  200. if fields.contains_key("due") {
  201. let due = fields.get("due").unwrap().clone();
  202. let due: Option<Option<Timestamp>> = serde_json::from_value(due)?;
  203. if let Some(d) = due {
  204. task.set_due(d);
  205. }
  206. }
  207. if fields.contains_key("assign") {
  208. let assign = fields.get("assign").unwrap().clone();
  209. let assign: Vec<String> = serde_json::from_value(assign)?;
  210. if !assign.is_empty() {
  211. task.set_assign(&assign);
  212. }
  213. }
  214. if fields.contains_key("project") {
  215. let project = fields.get("project").unwrap().clone();
  216. let project: Vec<String> = serde_json::from_value(project)?;
  217. if !project.is_empty() {
  218. task.set_project(&project);
  219. }
  220. }
  221. Ok(task)
  222. }
  223. }