From 1d38e8ae2a7db505fa9bf6d592bcf8cf6ce841bd Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Mon, 11 Oct 2021 19:08:18 +0200
Subject: [PATCH] refact: lighter main

---
 .gitignore                 |  1 +
 src/bma/lookup_identity.rs |  2 +-
 src/cli/certify.rs         |  2 +-
 src/cli/mod.rs             | 99 ++++++++++++++++++++++++++++++++------
 src/main.rs                | 23 +++++----
 5 files changed, 100 insertions(+), 27 deletions(-)

diff --git a/.gitignore b/.gitignore
index ea8c4bf..6b39d31 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 /target
+.idea/
\ No newline at end of file
diff --git a/src/bma/lookup_identity.rs b/src/bma/lookup_identity.rs
index d15c01e..398b54f 100644
--- a/src/bma/lookup_identity.rs
+++ b/src/bma/lookup_identity.rs
@@ -23,7 +23,7 @@ impl LookupIdentity {
     }
 }
 
-pub fn lookup(node: BmaNode, uid_or_pub: String) -> () {
+pub fn lookup(node: &BmaNode, uid_or_pub: &String) -> () {
     let address = node.get_address();
     let resp = reqwest::blocking::get(format!("{}/wot/lookup/{}", address, uid_or_pub)).expect("Could not fetch lookup data from distant node");
     lookup_print(&LookupResult(&resp.json().expect("Could not get JSON result from distant node")));
diff --git a/src/cli/certify.rs b/src/cli/certify.rs
index 84b8052..b6441c9 100644
--- a/src/cli/certify.rs
+++ b/src/cli/certify.rs
@@ -5,7 +5,7 @@ use crate::crypto::duniter_key::ToDuniterKey;
 use crate::dubp::documents::certification::Certification;
 use crate::dubp::signable::Signable;
 
-pub fn certify(node: BmaNode, uid_or_pub: String) -> Result<(), String> {
+pub fn certify(node: &BmaNode, uid_or_pub: &String) -> Result<(), String> {
     let address = node.get_address();
     println!("Fetching identity using \"{}\" pattern...", uid_or_pub);
     let resp = reqwest::blocking::get(format!("{}/wot/lookup/{}", address, uid_or_pub)).expect("Could not fetch lookup data from distant node");
diff --git a/src/cli/mod.rs b/src/cli/mod.rs
index 4f69eae..a6c4df6 100644
--- a/src/cli/mod.rs
+++ b/src/cli/mod.rs
@@ -3,62 +3,131 @@ use std::env::Args;
 use crate::cli::Command::*;
 use crate::bma::BmaNode;
 use std::env;
+use crate::{bma, cli, compute_key, compute_pub, compute_sec};
+use crate::crypto::duniter_key::ScryptDuniterKey;
+use core::fmt;
 
 pub mod certify;
 
 const DEFAULT_NODE: &str = "https://g1-test.duniter.org";
 
+// TODO: constantize pub, sec, etc
+
 pub enum Command {
     /// Compute the public key from salt/passwd and displays it
-    PUB(String, String),
+    PUB(String, String, String),
     /// Compute the secret key from salt/passwd and displays it
-    SEC(String, String),
+    SEC(String, String, String),
     /// Compute the keyring from salt/passwd and displays it
-    KEYRING(String, String),
+    KEYRING(String, String, String),
     /// Search an identity on a Duniter node (BMA API)
-    LOOKUP(BmaNode, String),
+    LOOKUP(String, BmaNode, String),
     /// Search an identity on a Duniter node (BMA API) and certify it
-    CERTIFY(BmaNode, String),
-    /// Unknown command
-    UNKNOWN(String)
+    CERTIFY(String, BmaNode, String),
+    /// Some unknown command
+    UNKNOWN(String),
 }
 
 impl Command {
 
-    pub fn from(mut args: Args) -> Command {
+    pub fn name(&self) -> String {
+        let str_name = match self {
+            PUB(_, _, _) => "pub",
+            SEC(_, _, _) => "sec",
+            KEYRING(_, _, _) => "keyring",
+            LOOKUP(_, _, _) => "lookup",
+            CERTIFY(_, _, _) => "certify",
+            UNKNOWN(name) => name.as_str(),
+        };
+        str_name.to_string()
+    }
+
+    pub fn execute(&self) -> Result<(), String> {
+        match self {
+            PUB(_, salt, passwd) => {
+                println!("{}", compute_pub(ScryptDuniterKey::new(salt.to_string(), passwd.to_string())));
+            }
+            SEC(_, salt, passwd) => println!("{}", compute_sec(ScryptDuniterKey::new(salt.to_string(), passwd.to_string()))),
+            KEYRING(_, salt, passwd) => println!("{}", compute_key(ScryptDuniterKey::new(salt.to_string(), passwd.to_string()))),
+            LOOKUP(_, bma_node, uid_or_pub) => bma::lookup_identity::lookup(bma_node, uid_or_pub),
+            CERTIFY(_, bma_node, uid_or_pub) => cli::certify::certify(bma_node, uid_or_pub).unwrap_or_else(|e| eprintln!("{}", e)),
+            UNKNOWN(cmd) => eprintln!("Unknown command {}", cmd),
+            _ => return Err("Not handled command yet".to_string())
+        }
+        Ok(())
+    }
+
+    pub fn from<I>(mut args: I) -> Option<Command>
+    where I:Iterator<Item = String> {
         args.next();
-        let command = args.next().expect("Command must be provided");
+        let command = match args.next() {
+            None => return None,
+            Some(cmd_name) => cmd_name
+        };
 
         let command = command.as_str();
         match command {
             "pub" => {
                 let salt = args.next().expect("Salt must be provided");
                 let passwd = args.next().expect("Password must be provided");
-                PUB(salt, passwd)
+                Some(PUB(command.to_string(), salt, passwd))
             },
             "sec" => {
                 let salt = args.next().expect("Salt must be provided");
                 let passwd = args.next().expect("Password must be provided");
-                SEC(salt, passwd)
+                Some(SEC(command.to_string(), salt, passwd))
             },
             "keyring" => {
                 let salt = args.next().expect("Salt must be provided");
                 let passwd = args.next().expect("Password must be provided");
-                KEYRING(salt, passwd)
+                Some(KEYRING(command.to_string(), salt, passwd))
             },
             "lookup" => {
                 let uid_or_pub = args.next().expect("UID or pubkey must be provided");
                 let default = String::from(DEFAULT_NODE);
                 let bma_node = BmaNode::new(env::var("DUNITER_NODE").unwrap_or(default).as_str());
-                LOOKUP(bma_node, uid_or_pub)
+                Some(LOOKUP(command.to_string(), bma_node, uid_or_pub))
             },
             "cert" => {
                 let uid_or_pub = args.next().expect("UID or pubkey must be provided");
                 let default = String::from(DEFAULT_NODE);
                 let bma_node = BmaNode::new(env::var("DUNITER_NODE").unwrap_or(default).as_str());
-                CERTIFY(bma_node, uid_or_pub)
+                Some(CERTIFY(command.to_string(), bma_node, uid_or_pub))
             },
-            _ => UNKNOWN(String::from(command)),
+            _ => Some(UNKNOWN(command.to_string())),
         }
     }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::cli::Command;
+    use crate::cli::Command::PUB;
+
+    #[test]
+    fn known_command () {
+        let args = vec!["", "pub", "abc", "def"];
+        let cmd = Command::from(args.into_iter().map(|x| x.to_string()));
+        assert!(cmd.is_some());
+        let cmd = cmd.unwrap();
+        let is_expected_cmd = if let Command::PUB(..) = cmd { true } else { false };
+        assert!(is_expected_cmd);
+    }
+
+    #[test]
+    fn unknown_command () {
+        let args = vec!["", "abracadabra"];
+        let cmd = Command::from(args.into_iter().map(|x| x.to_string()));
+        assert!(cmd.is_some());
+        let cmd = cmd.unwrap();
+        let is_expected_cmd = if let Command::UNKNOWN(..) = cmd { true } else { false };
+        assert!(is_expected_cmd);
+    }
+
+    #[test]
+    fn no_command () {
+        let args = vec![""];
+        let cmd = Command::from(args.into_iter().map(|x| x.to_string()));
+        assert!(cmd.is_none());
+    }
 }
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 0eb54a9..8d327d3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,21 +1,24 @@
 use std::env;
+use std::process::exit;
 
 use duniter_mini_client::{compute_pub, compute_sec, compute_key, cli, bma};
 use duniter_mini_client::cli::Command;
-use duniter_mini_client::cli::Command::{UNKNOWN, PUB, SEC, KEYRING, LOOKUP, CERTIFY};
+use duniter_mini_client::cli::Command::{PUB, SEC, KEYRING, LOOKUP, CERTIFY};
 use duniter_mini_client::crypto::duniter_key::ScryptDuniterKey;
 
 fn main() {
     let command = Command::from(env::args());
 
-    // TODO: Result<(), String>
-
-    match command {
-        PUB(salt, passwd) => println!("{}", compute_pub(ScryptDuniterKey::new(salt, passwd))),
-        SEC(salt, passwd) => println!("{}", compute_sec(ScryptDuniterKey::new(salt, passwd))),
-        KEYRING(salt, passwd) => println!("{}", compute_key(ScryptDuniterKey::new(salt, passwd))),
-        LOOKUP(bma_node, uid_or_pub) => bma::lookup_identity::lookup(bma_node, uid_or_pub),
-        CERTIFY(bma_node, uid_or_pub) => cli::certify::certify(bma_node, uid_or_pub).unwrap_or_else(|e| eprintln!("{}", e)),
-        UNKNOWN(cmd) => eprintln!("Unknown command {}", cmd),
+    let command = match command {
+        Some(c) => c,
+        None => {
+            eprintln!("No command found");
+            exit(1);
+        }
     };
+
+    if let Err(e) = command.execute() {
+        eprintln!("Command executed with error: {}", e);
+        exit(2);
+    }
 }
\ No newline at end of file
-- 
GitLab