Explorar o código

bin/taud: split the code into separate modules

ghassmo %!s(int64=4) %!d(string=hai) anos
pai
achega
66c715d7b7
Modificáronse 4 ficheiros con 331 adicións e 297 borrados
  1. 36 297
      bin/taud/src/main.rs
  2. 55 0
      bin/taud/src/month_tasks.rs
  3. 83 0
      bin/taud/src/task_info.rs
  4. 157 0
      bin/taud/src/util.rs

+ 36 - 297
bin/taud/src/main.rs

@@ -1,17 +1,10 @@
-use std::{
-    fs::{create_dir_all, File},
-    io::BufReader,
-    path::PathBuf,
-    sync::Arc,
-};
+use std::{fs::create_dir_all, path::PathBuf, sync::Arc};
 
 use async_executor::Executor;
 use async_trait::async_trait;
 use chrono::{TimeZone, Utc};
 use clap::{IntoApp, Parser};
 use log::debug;
-use rand::{distributions::Alphanumeric, thread_rng, Rng};
-use serde::{de::DeserializeOwned, Deserialize, Serialize};
 use serde_json::{json, Value};
 use simplelog::{ColorChoice, TermLogger, TerminalMode};
 
@@ -21,215 +14,20 @@ use darkfi::{
         rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
     },
     util::{
-        cli::{log_config, spawn_config, Config, UrlConfig},
+        cli::{log_config, spawn_config, Config},
         expand_path, join_config_path,
     },
     Error, Result,
 };
 
-const CONFIG_FILE_CONTENTS: &[u8] = include_bytes!("../taud_config.toml");
-
-/// taud cli
-#[derive(Parser)]
-#[clap(name = "taud")]
-pub struct CliTaud {
-    /// Sets a custom config file
-    #[clap(short, long)]
-    pub config: Option<String>,
-    /// Increase verbosity
-    #[clap(short, parse(from_occurrences))]
-    pub verbose: u8,
-}
-
-fn random_ref_id() -> String {
-    thread_rng().sample_iter(&Alphanumeric).take(30).map(char::from).collect()
-}
-
-fn find_free_id(tasks_ids: &Vec<u32>) -> u32 {
-    for i in 1.. {
-        if !tasks_ids.contains(&i) {
-            return i
-        }
-    }
-    1
-}
-
-fn load<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
-    let file = File::open(path)?;
-    let reader = BufReader::new(file);
-
-    let value: T = serde_json::from_reader(reader)?;
-    Ok(value)
-}
-
-fn save<T: Serialize>(path: &PathBuf, value: &T) -> Result<()> {
-    let file = File::create(path)?;
-    serde_json::to_writer_pretty(file, value)?;
-    Ok(())
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-struct Timestamp(String);
-
-#[derive(Clone, Debug, Serialize, Deserialize)]
-struct TauConfig {
-    /// path to dataset
-    pub dataset_path: String,
-    /// Path to DER-formatted PKCS#12 archive. (used only with tls listener url)
-    pub tls_identity_path: String,
-    /// The address where taud should bind its RPC socket
-    pub rpc_listener_url: UrlConfig,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize)]
-struct Settings {
-    dataset_path: PathBuf,
-}
-
-impl Default for Settings {
-    fn default() -> Self {
-        Self { dataset_path: PathBuf::from("") }
-    }
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-struct TaskEvent {
-    action: String,
-    timestamp: Timestamp,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-struct Comment {
-    content: String,
-    author: String,
-    timestamp: Timestamp,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize)]
-struct MonthTasks {
-    created_at: Timestamp,
-    #[serde(skip_serializing, skip_deserializing)]
-    settings: Settings,
-    task_tks: Vec<String>,
-}
-
-impl MonthTasks {
-    fn add(&mut self, tk_hash: &str) {
-        self.task_tks.push(tk_hash.into());
-    }
-
-    fn objects(&self) -> Result<Vec<TaskInfo>> {
-        let mut tks: Vec<TaskInfo> = vec![];
-
-        for tk_hash in self.task_tks.iter() {
-            tks.push(TaskInfo::load(&tk_hash, &self.settings)?);
-        }
-
-        Ok(tks)
-    }
-
-    fn remove(&mut self, tk_hash: &str) {
-        if let Some(index) = self.task_tks.iter().position(|t| *t == tk_hash) {
-            self.task_tks.remove(index);
-        }
-    }
-
-    fn load(date: Timestamp, settings: Settings) -> Result<Timestamp> {
-        Ok(Timestamp(Utc::now().to_string()))
-    }
-
-    fn load_or_create(date: Timestamp, settings: Settings) -> Result<Timestamp> {
-        Ok(Timestamp(Utc::now().to_string()))
-    }
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
-struct TaskInfo {
-    ref_id: String,
-    id: u32,
-    title: String,
-    desc: String,
-    assign: Vec<String>,
-    project: Vec<String>,
-    due: Option<Timestamp>,
-    rank: u32,
-    created_at: Timestamp,
-    events: Vec<TaskEvent>,
-    comments: Vec<Comment>,
-}
-
-impl TaskInfo {
-    pub fn new(title: &str, desc: &str, due: Option<Timestamp>, rank: u32) -> Self {
-        // TODO
-        // check due date
-
-        // generate ref_id
-        let ref_id = random_ref_id();
-
-        // XXX must find the next free id
-        let mut rng = rand::thread_rng();
-        let id: u32 = rng.gen();
-
-        let created_at: Timestamp = Timestamp(Utc::now().to_string());
-
-        Self {
-            ref_id,
-            id,
-            title: title.into(),
-            desc: desc.into(),
-            assign: vec![],
-            project: vec![],
-            due,
-            rank,
-            created_at,
-            comments: vec![],
-            events: vec![],
-        }
-    }
-
-    fn assign(&mut self, n: String) {
-        self.assign.push(n);
-    }
-
-    fn project(&mut self, p: String) {
-        self.project.push(p);
-    }
-
-    fn load(tk_hash: &str, settings: &Settings) -> Result<TaskInfo> {
-        Ok(TaskInfo::new("test", "test", None, 0))
-    }
-
-    fn save(&self, settings: &Settings) -> Result<()> {
-        Ok(())
-    }
-}
-
-async fn start(config: TauConfig, executor: Arc<Executor<'_>>) -> Result<()> {
-    if config.dataset_path.is_empty() {
-        return Err(Error::ParseFailed("Failed to parse dataset_path"))
-    }
-
-    let dataset_path = expand_path(&config.dataset_path)?;
-
-    // mkdir dataset_path if not exists
-    create_dir_all(dataset_path.join("month"))?;
-    create_dir_all(dataset_path.join("task"))?;
-
-    let settings = Settings { dataset_path };
-
-    let server_config = RpcServerConfig {
-        socket_addr: config.rpc_listener_url.url.parse()?,
-        use_tls: false,
-        // this is all random filler that is meaningless bc tls is disabled
-        identity_path: Default::default(),
-        identity_pass: Default::default(),
-    };
-
-    let rpc_interface = Arc::new(JsonRpcInterface { settings });
-
-    listen_and_serve(server_config, rpc_interface, executor).await
-}
+mod month_tasks;
+mod task_info;
+mod util;
 
+use crate::{
+    task_info::TaskInfo,
+    util::{CliTaud, Settings, TauConfig, Timestamp, CONFIG_FILE_CONTENTS},
+};
 struct JsonRpcInterface {
     settings: Settings,
 }
@@ -307,6 +105,32 @@ impl JsonRpcInterface {
     }
 }
 
+async fn start(config: TauConfig, executor: Arc<Executor<'_>>) -> Result<()> {
+    if config.dataset_path.is_empty() {
+        return Err(Error::ParseFailed("Failed to parse dataset_path"))
+    }
+
+    let dataset_path = expand_path(&config.dataset_path)?;
+
+    // mkdir dataset_path if not exists
+    create_dir_all(dataset_path.join("month"))?;
+    create_dir_all(dataset_path.join("task"))?;
+
+    let settings = Settings { dataset_path };
+
+    let server_config = RpcServerConfig {
+        socket_addr: config.rpc_listener_url.url.parse()?,
+        use_tls: false,
+        // this is all random filler that is meaningless bc tls is disabled
+        identity_path: Default::default(),
+        identity_pass: Default::default(),
+    };
+
+    let rpc_interface = Arc::new(JsonRpcInterface { settings });
+
+    listen_and_serve(server_config, rpc_interface, executor).await
+}
+
 #[async_std::main]
 async fn main() -> Result<()> {
     let args = CliTaud::parse();
@@ -327,93 +151,8 @@ async fn main() -> Result<()> {
 
     TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
 
-    let config: TauConfig = Config::<TauConfig>::load(config_path)?;
+    let config: TauConfig = Config::<TauConfig>::load(config_path.to_path_buf())?;
 
     let ex = Arc::new(Executor::new());
     smol::block_on(ex.run(start(config, ex.clone())))
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    impl PartialEq for MonthTasks {
-        fn eq(&self, other: &Self) -> bool {
-            self.created_at == other.created_at && self.task_tks == other.task_tks
-        }
-    }
-
-    #[test]
-    fn find_free_id_test() -> Result<()> {
-        let mut ids: Vec<u32> = vec![1, 3, 8, 9, 10, 3];
-        let ids_empty: Vec<u32> = vec![];
-        let ids_duplicate: Vec<u32> = vec![1; 100];
-
-        let find_id = find_free_id(&ids);
-
-        assert_eq!(find_id, 2);
-
-        ids.push(find_id);
-
-        assert_eq!(find_free_id(&ids), 4);
-
-        assert_eq!(find_free_id(&ids_empty), 1);
-
-        assert_eq!(find_free_id(&ids_duplicate), 2);
-
-        Ok(())
-    }
-
-    #[test]
-    fn load_and_save_data() -> Result<()> {
-        let path = PathBuf::from("/tmp/test_tau_data");
-
-        // mkdir dataset_path if not exists
-        create_dir_all(path.join("month"))?;
-        create_dir_all(path.join("task"))?;
-
-        // test with MonthTasks
-        ///////////////////////
-        let mt_path = path.join("month");
-        let mt_path = mt_path.join("022");
-
-        let settings = Settings { dataset_path: path.clone() };
-        let task_tks = vec![];
-        let created_at = Timestamp(Utc::now().to_string());
-
-        let mut mt = MonthTasks { created_at, task_tks, settings };
-
-        save::<MonthTasks>(&mt_path, &mt)?;
-
-        let mt_load = load::<MonthTasks>(&mt_path)?;
-        assert_eq!(mt, mt_load);
-
-        mt.add("test_hash");
-
-        save::<MonthTasks>(&mt_path, &mt)?;
-
-        let mt_load = load::<MonthTasks>(&mt_path)?;
-        assert_eq!(mt, mt_load);
-
-        // test with TaskInfo
-        ///////////////////////
-        let t_path = path.join("task");
-        let t_path = t_path.join("test_hash");
-
-        let mut task = TaskInfo::new("test_title", "test_desc", None, 0);
-
-        save::<TaskInfo>(&t_path, &task)?;
-
-        let t_load = load::<TaskInfo>(&t_path)?;
-        assert_eq!(task, t_load);
-
-        task.title = "test_title_2".into();
-
-        save::<TaskInfo>(&t_path, &task)?;
-
-        let t_load = load::<TaskInfo>(&t_path)?;
-        assert_eq!(task, t_load);
-
-        Ok(())
-    }
-}

+ 55 - 0
bin/taud/src/month_tasks.rs

@@ -0,0 +1,55 @@
+use chrono::Utc;
+use serde::{Deserialize, Serialize};
+
+use darkfi::Result;
+
+use crate::{
+    task_info::TaskInfo,
+    util::{Settings, Timestamp},
+};
+
+// XXX
+#[allow(dead_code)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct MonthTasks {
+    pub created_at: Timestamp,
+    #[serde(skip_serializing, skip_deserializing)]
+    pub settings: Settings,
+    pub task_tks: Vec<String>,
+}
+
+impl MonthTasks {
+    pub fn add(&mut self, tk_hash: &str) {
+        self.task_tks.push(tk_hash.into());
+    }
+
+    pub fn objects(&self) -> Result<Vec<TaskInfo>> {
+        let mut tks: Vec<TaskInfo> = vec![];
+
+        for tk_hash in self.task_tks.iter() {
+            tks.push(TaskInfo::load(&tk_hash, &self.settings)?);
+        }
+
+        Ok(tks)
+    }
+
+    pub fn remove(&mut self, tk_hash: &str) {
+        if let Some(index) = self.task_tks.iter().position(|t| *t == tk_hash) {
+            self.task_tks.remove(index);
+        }
+    }
+
+    fn load(_date: Timestamp, _settings: Settings) -> Result<Timestamp> {
+        Ok(Timestamp(Utc::now().to_string()))
+    }
+
+    fn load_or_create(_date: Timestamp, _settings: Settings) -> Result<Timestamp> {
+        Ok(Timestamp(Utc::now().to_string()))
+    }
+}
+
+impl PartialEq for MonthTasks {
+    fn eq(&self, other: &Self) -> bool {
+        self.created_at == other.created_at && self.task_tks == other.task_tks
+    }
+}

+ 83 - 0
bin/taud/src/task_info.rs

@@ -0,0 +1,83 @@
+use chrono::Utc;
+use rand::Rng;
+use serde::{Deserialize, Serialize};
+
+use darkfi::Result;
+
+use crate::util::{random_ref_id, Settings, Timestamp};
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+struct TaskEvent {
+    action: String,
+    timestamp: Timestamp,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+struct Comment {
+    content: String,
+    author: String,
+    timestamp: Timestamp,
+}
+
+// XXX
+#[allow(dead_code)]
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+pub struct TaskInfo {
+    ref_id: String,
+    id: u32,
+    pub title: String,
+    desc: String,
+    assign: Vec<String>,
+    project: Vec<String>,
+    due: Option<Timestamp>,
+    rank: u32,
+    created_at: Timestamp,
+    events: Vec<TaskEvent>,
+    comments: Vec<Comment>,
+}
+
+impl TaskInfo {
+    pub fn new(title: &str, desc: &str, due: Option<Timestamp>, rank: u32) -> Self {
+        // TODO
+        // check due date
+
+        // generate ref_id
+        let ref_id = random_ref_id();
+
+        // XXX must find the next free id
+        let mut rng = rand::thread_rng();
+        let id: u32 = rng.gen();
+
+        let created_at: Timestamp = Timestamp(Utc::now().to_string());
+
+        Self {
+            ref_id,
+            id,
+            title: title.into(),
+            desc: desc.into(),
+            assign: vec![],
+            project: vec![],
+            due,
+            rank,
+            created_at,
+            comments: vec![],
+            events: vec![],
+        }
+    }
+
+    pub fn assign(&mut self, n: String) {
+        self.assign.push(n);
+    }
+
+    pub fn project(&mut self, p: String) {
+        self.project.push(p);
+    }
+
+    pub fn load(_tk_hash: &str, _settings: &Settings) -> Result<Self> {
+        Ok(Self::new("test", "test", None, 0))
+    }
+
+    pub fn save(&self, _settings: &Settings) -> Result<()> {
+        Ok(())
+    }
+}

+ 157 - 0
bin/taud/src/util.rs

@@ -0,0 +1,157 @@
+use std::{fs::File, io::BufReader, path::PathBuf};
+
+use clap::Parser;
+use rand::{distributions::Alphanumeric, thread_rng, Rng};
+use serde::{de::DeserializeOwned, Deserialize, Serialize};
+
+use darkfi::{util::cli::UrlConfig, Result};
+
+pub const CONFIG_FILE_CONTENTS: &[u8] = include_bytes!("../taud_config.toml");
+
+pub fn random_ref_id() -> String {
+    thread_rng().sample_iter(&Alphanumeric).take(30).map(char::from).collect()
+}
+
+pub fn find_free_id(tasks_ids: &Vec<u32>) -> u32 {
+    for i in 1.. {
+        if !tasks_ids.contains(&i) {
+            return i
+        }
+    }
+    1
+}
+
+pub fn load<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
+    let file = File::open(path)?;
+    let reader = BufReader::new(file);
+
+    let value: T = serde_json::from_reader(reader)?;
+    Ok(value)
+}
+
+pub fn save<T: Serialize>(path: &PathBuf, value: &T) -> Result<()> {
+    let file = File::create(path)?;
+    serde_json::to_writer_pretty(file, value)?;
+    Ok(())
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct Settings {
+    pub dataset_path: PathBuf,
+}
+
+impl Default for Settings {
+    fn default() -> Self {
+        Self { dataset_path: PathBuf::from("") }
+    }
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+pub struct Timestamp(pub String);
+
+/// taud cli
+#[derive(Parser)]
+#[clap(name = "taud")]
+pub struct CliTaud {
+    /// Sets a custom config file
+    #[clap(short, long)]
+    pub config: Option<String>,
+    /// Increase verbosity
+    #[clap(short, parse(from_occurrences))]
+    pub verbose: u8,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct TauConfig {
+    /// path to dataset
+    pub dataset_path: String,
+    /// Path to DER-formatted PKCS#12 archive. (used only with tls listener url)
+    pub tls_identity_path: String,
+    /// The address where taud should bind its RPC socket
+    pub rpc_listener_url: UrlConfig,
+}
+
+#[cfg(test)]
+mod tests {
+    use std::fs::create_dir_all;
+
+    use chrono::Utc;
+
+    use crate::{month_tasks::MonthTasks, task_info::TaskInfo};
+
+    use super::*;
+
+    #[test]
+    fn find_free_id_test() -> Result<()> {
+        let mut ids: Vec<u32> = vec![1, 3, 8, 9, 10, 3];
+        let ids_empty: Vec<u32> = vec![];
+        let ids_duplicate: Vec<u32> = vec![1; 100];
+
+        let find_id = find_free_id(&ids);
+
+        assert_eq!(find_id, 2);
+
+        ids.push(find_id);
+
+        assert_eq!(find_free_id(&ids), 4);
+
+        assert_eq!(find_free_id(&ids_empty), 1);
+
+        assert_eq!(find_free_id(&ids_duplicate), 2);
+
+        Ok(())
+    }
+
+    #[test]
+    fn load_and_save_data() -> Result<()> {
+        let path = PathBuf::from("/tmp/test_tau_data");
+
+        // mkdir dataset_path if not exists
+        create_dir_all(path.join("month"))?;
+        create_dir_all(path.join("task"))?;
+
+        // test with MonthTasks
+        ///////////////////////
+        let mt_path = path.join("month");
+        let mt_path = mt_path.join("022");
+
+        let settings = Settings { dataset_path: path.clone() };
+        let task_tks = vec![];
+        let created_at = Timestamp(Utc::now().to_string());
+
+        let mut mt = MonthTasks { created_at, task_tks, settings };
+
+        save::<MonthTasks>(&mt_path, &mt)?;
+
+        let mt_load = load::<MonthTasks>(&mt_path)?;
+        assert_eq!(mt, mt_load);
+
+        mt.add("test_hash");
+
+        save::<MonthTasks>(&mt_path, &mt)?;
+
+        let mt_load = load::<MonthTasks>(&mt_path)?;
+        assert_eq!(mt, mt_load);
+
+        // test with TaskInfo
+        ///////////////////////
+        let t_path = path.join("task");
+        let t_path = t_path.join("test_hash");
+
+        let mut task = TaskInfo::new("test_title", "test_desc", None, 0);
+
+        save::<TaskInfo>(&t_path, &task)?;
+
+        let t_load = load::<TaskInfo>(&t_path)?;
+        assert_eq!(task, t_load);
+
+        task.title = "test_title_2".into();
+
+        save::<TaskInfo>(&t_path, &task)?;
+
+        let t_load = load::<TaskInfo>(&t_path)?;
+        assert_eq!(task, t_load);
+
+        Ok(())
+    }
+}