diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2020-04-28 19:57:14 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2020-04-28 20:27:29 +0200 |
commit | 44f514ea642dafdbbf44258919473a2fc711d3d9 (patch) | |
tree | 07f9779d429ff743777647b769fa09a9457cf0f0 | |
parent | b2bb2d91d824b395c17e72c81aa3efd2574d6e0f (diff) |
Reset main() impl
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/main.rs | 802 |
2 files changed, 36 insertions, 767 deletions
@@ -35,4 +35,5 @@ hyper = "0.12" itertools = "0.7" tokio = { version = "0.2", features = ["full"] } add_getters_setters = "1.1" +xdg = "2" structopt = "0.3" diff --git a/src/main.rs b/src/main.rs index 5380c9d..616291a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ extern crate config; extern crate hyper; extern crate env_logger; extern crate itertools; +extern crate xdg; #[macro_use] extern crate failure; #[macro_use] extern crate is_match; @@ -20,12 +21,12 @@ extern crate itertools; #[macro_use] extern crate log; #[macro_use] extern crate tokio; #[macro_use] extern crate add_getters_setters; +#[macro_use] extern crate structopt; mod app; -mod cli_ui; +mod cli; mod configuration; mod repository; -mod typeext; mod types; mod version; @@ -33,6 +34,7 @@ use std::collections::BTreeMap; use std::str::FromStr; use std::ops::Deref; use std::sync::Arc; +use std::path::PathBuf; use chrono::NaiveDateTime; use futures::future::Future; @@ -41,9 +43,12 @@ use futures::future::TryFutureExt; use serde_json::to_string_pretty as serde_json_to_string_pretty; use serde_json::from_str as serde_json_from_str; use failure::Fallible as Result; +use failure::err_msg; +use crate::app::App; +use crate::cli::cli; use crate::configuration::Configuration; -use crate::repository::Repository; +use crate::repository::repository::Repository; use crate::types::block::Block; use crate::types::content::Content; use crate::types::content::Payload; @@ -57,780 +62,43 @@ use std::process::exit; #[tokio::main] async fn main() -> Result<()> { + let cli = cli()?; let _ = env_logger::init(); debug!("Logger initialized"); - let boot = || -> (Configuration, Repository) { - debug!("Loading configuration"); - let mut config = config::Config::default(); - config - .merge(config::File::with_name("distrox")) - .map_err(|e| { - error!("Error loading config file: {:?}", e); - exit(1); - }) - .unwrap(); // safe! - - let config = config.try_into::<configuration::Configuration>() - .map_err(|e| { - error!("Error parsing config file: {:?}", e); - exit(1); - }) - .unwrap(); // safe! - debug!("Config loaded"); - - debug!("Loading repository..."); - let repo = Repository::new(config.api_url(), config.api_port()) - .map_err(|e| { - error!("Error opening repository: {:?}", e); - exit(1); - }) - .unwrap(); // safe - debug!("Repository loaded successfully!"); + let config_file_name = PathBuf::from("distrox.toml"); + let config: Configuration = { + let configfile = xdg::BaseDirectories::with_prefix("myapp")? + .find_config_file(&config_file_name) + .ok_or_else(|| err_msg("No configuration found"))?; - (config, repo) + let configstr = ::std::fs::read_to_string(&configfile)?; + ::toml::from_str(&configstr)? }; - match cli_ui::build_ui() - .get_matches() - .subcommand() - { - - ("gui", _mtch) => { - Err(format_err!("Not yet supported")) - } - - ("is-block", Some(mtch)) => { - debug!("Calling: is-block"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - repo.get_block(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(|_| ()) - } - - ("is-content", Some(mtch)) => { - debug!("Calling: is-content"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(|_| ()) - } - - ("is-post", Some(mtch)) => { - debug!("Calling: is-post"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - let (tx, rx) = ::std::sync::mpsc::channel(); - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |content| tx.send(content.payload().is_post()).unwrap()); - exit(if rx.recv().unwrap() { 0 } else { 1 }); - } - - ("is-reply", Some(mtch)) => { - debug!("Calling: is-reply"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - let (tx, rx) = ::std::sync::mpsc::channel(); - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |content| { - let is_reply = if !content.payload().is_post() { - false - } else { - match content.payload() { - Payload::Post { reply_to, .. } => reply_to.is_some(), - _ => false, - } - }; - - tx.send(is_reply).unwrap() - }); - - exit(if rx.recv().unwrap() { 0 } else { 1 }); - } - - ("is-profile", Some(mtch)) => { - debug!("Calling: is-profile"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - let (tx, rx) = ::std::sync::mpsc::channel(); - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |content| { - tx.send(content.payload().is_profile()).unwrap() - }); - exit(if rx.recv().unwrap() { 0 } else { 1 }); - } - - ("get-parent-blocks", Some(mtch)) => { - debug!("Calling: get-parent-blocks"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - let (tx, rx) = ::std::sync::mpsc::channel(); - repo.get_block(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |block| tx.send(block.parents().clone()).unwrap()); - - for parent in rx.recv().unwrap() { - println!("{}", parent); - } - - Ok(()) - } - - ("get-devices", Some(mtch)) => { - debug!("Calling: get-devices"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - let (tx, rx) = ::std::sync::mpsc::channel(); - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |c| tx.send(c.devices().clone()).unwrap()); - - for device in rx.recv().unwrap() { - println!("{}", device); - } - - Ok(()) - } - - ("get-payload-type", Some(mtch)) => { - debug!("Calling: get-payload-type"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - let (tx, rx) = ::std::sync::mpsc::channel(); - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |c| tx.send(match c.payload() { - Payload::None => "None", - Payload::Post { .. } => "Post", - Payload::AttachedPostComments { .. } => "AttachedPostComments", - Payload::Profile { .. } => "Profile", - }).unwrap()); - - println!("{}", rx.recv().unwrap()); - Ok(()) - } - - ("get-payload", Some(mtch)) => { - debug!("Calling: get-payload"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - let (tx, rx) = ::std::sync::mpsc::channel(); - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .and_then(|c| serde_json_to_string_pretty(c.payload())) - .map_err(|e| { - error!("Error building JSON: {:?}", e); - exit(1) - }) - .map(move |j| tx.send(j).unwrap()); - println!("{}", rx.recv().unwrap()); - Ok(()) - } - - ("get-post-content", Some(mtch)) => { - debug!("Calling: get-post-content"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - let (tx, rx) = ::std::sync::mpsc::channel(); - let content_hash = repo - .get_content(hash.clone()) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |c| { - match c.payload() { - Payload::Post { content, content_format, .. } => { - match (content_format.type_(), content_format.subtype()) { - (mime::TEXT, _) => { // plain text will be printed - content.clone() - }, - - (_, _) => { - error!("Cannot show mimetype of Post {hash} which lives at {content} ({mime})", - hash = hash, - content = content, - mime = content_format); - exit(1) - } - } - }, - _ => { - error!("Not a Post"); - exit(1) - } - } - }) - .unwrap(); - - repo.get_raw_bytes(content_hash) - .await - .and_then(|blob| String::from_utf8(blob).map_err(Into::into)) - .map_err(|e| { - error!("Content is not UTF-8: {:?}", e); - exit(1) - }) - .map(move |blob| tx.send(blob).unwrap()); + let app = { + let device_name = config.get_device_name(); + let device_key = config.get_device_key(); - println!("{}", rx.recv().unwrap()); - Ok(()) - } - - ("get-post-content-format", Some(mtch)) => { - debug!("Calling: get-post-content-format"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |content| { - match content.payload() { - Payload::Post { content_format, .. } => println!("{}", content_format), - _ => { - error!("Not a Post"); - exit(1) - } - } - }) - } - - ("get-post-reply-to", Some(mtch)) => { - debug!("Calling: get-post-reply-to"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |content| { - match content.payload() { - Payload::Post { reply_to, .. } => { - reply_to.as_ref().map(|r| println!("{}", r)); - }, - _ => { - error!("Not a Post"); - exit(1) - } - } - }) - } - - ("get-post-metadata", Some(mtch)) => { - debug!("Calling: get-post-metadata"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |content| { - match content.payload() { - Payload::Post { - comments_will_be_propagated, - comments_propagated_until, - .. - } => { - comments_will_be_propagated.as_ref().map(|b| { - println!("comments-will-be-propagated: {}", b); - }); - comments_propagated_until.as_ref().map(|b| { - println!("comments-will-be-propagated-until: {}", b); - }); - }, - _ => { - error!("Not a Post"); - exit(1) - } - } - }) - } - - ("get-profile-names", Some(mtch)) => { - debug!("Calling: get-profile-names"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |content| { - match content.payload() { - Payload::Profile { names, .. } => { - names.iter().for_each(|n| println!("{}", n)); - } - _ => { - error!("Not a Profile"); - exit(1) - } - } - }) - } - - ("get-profile-picture", Some(mtch)) => { - debug!("Calling: get-profile-picture"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(move |content| { - match content.payload() { - Payload::Profile { picture, .. } => { - picture.as_ref().map(|hash| { - warn!("Showing picture on commandline not supported"); - warn!("Printing ipfs hash of picture"); - println!("{}", hash); - }); - } - _ => { - error!("Not a Profile"); - exit(1) - } - } - }) - } - - ("get-profile-more", Some(mtch)) => { - debug!("Calling: get-profile-more"); - let (_config, repo) = boot(); - let hash = IPFSHash::from(mtch.value_of("HASH").unwrap()); // safe by clap - debug!("Working with hash: {}", hash); - - repo.get_content(hash) - .await - .map_err(|e| { - let ignore_err = is_match!(e.downcast_ref(), Some(&ipfs_api::response::Error::Api(..))); - - if !ignore_err { - error!("Error running: {:?}", e); - print_error_details(e); - } - - exit(1) - }) - .map(|content| { - match content.payload() { - Payload::Profile { more, .. } => { - match serde_json_to_string_pretty(&more) { - Err(e) => { - error!("Error building JSON: {:?}", e); - exit(1) - }, - Ok(s) => { - println!("{}", s); - }, - } - } - _ => { - error!("Not a Profile"); - exit(1) - } - } - }) - } - - ("create-post-blob", Some(mtch)) => { - debug!("Calling: create-post-blob"); - let (_config, repo) = boot(); - - let content = { - let devices = mtch.values_of("device").unwrap(); // safe by clap - let timestamp = mtch.value_of("timestamp") - .map(|t| { - t.parse::<NaiveDateTime>() - .map(Timestamp::from) - .unwrap_or_else(|e| { - error!("Could not parse time: {:?}", e); - exit(1) - }) - }); + if let (Some(name), Some(key)) = (device_name, device_key) { + let name = IPNSHash::from(name.clone()); + let key = key.clone(); + let api_url = config.get_api_url().clone(); + let api_port = config.get_api_port().clone(); - let content_format = mtch.value_of("content-format").unwrap() // safe by clap - .parse::<mime::Mime>() - .map(MimeType::from) - .unwrap_or_else(|e| { - error!("Could not parse Mime: {:?}", e); - exit(1) - }); - - let content_hash = mtch.value_of("content-hash").unwrap(); // safe by clap - let replyto_hash = mtch.value_of("replyto-hash"); - - let comments_will_be_propagated = mtch.value_of("comments-will-be-propagated") - .map(|b| b.parse::<bool>().unwrap_or_else(|e| { - error!("Could not parse bool: {:?}", e); - exit(1) - })); - - let comments_propagated_until = mtch.value_of("comments-will-be-propagated-until") - .map(|b| b.parse::<NaiveDateTime>().map(Timestamp::from).unwrap_or_else(|e| { - error!("Could not parse time: {:?}", e); - exit(1) - })); - - let payload = Payload::Post { - content_format: content_format, - content: IPFSHash::from(String::from(content_hash)), - reply_to: replyto_hash.map(String::from).map(IPFSHash::from), - comments_will_be_propagated: comments_will_be_propagated, - comments_propagated_until: comments_propagated_until - }; - - let devices = devices.map(String::from).map(IPNSHash::from).collect(); - Content::new(devices, timestamp, payload) - }; - - { - repo - .put_content(content) - .await - .map_err(|e| { - error!("Error running: {:?}", e); - print_error_details(e); - exit(1) - }) - .map(|hash| println!("{}", hash)) - } - } - - ("create-attached-post-comments-blob", Some(mtch)) => { - debug!("Calling: create-attached-post-comments-blob"); - let (_config, repo) = boot(); - - let content = { - let devices = mtch.values_of("device").unwrap(); // safe by clap - let timestamp = mtch.value_of("timestamp") - .map(|t| { - t.parse::<NaiveDateTime>() - .map(Timestamp::from) - .unwrap_or_else(|e| { - error!("Could not parse time: {:?}", e); - exit(1) - }) - }); - - let comments_for = mtch - .value_of("comments-for") - .map(String::from) - .map(IPFSHash::from) - .unwrap(); // safe by clap - - let refs = mtch.values_of("refs").unwrap() // safe by clap - .map(String::from) - .map(IPFSHash::from) - .collect(); - - let payload = Payload::AttachedPostComments { - comments_for, - refs - }; - - let devices = devices.map(String::from).map(IPNSHash::from).collect(); - Content::new(devices, timestamp, payload) - }; - - { - repo.put_content(content) - .await - .map_err(|e| { - error!("Error running: {:?}", e); - print_error_details(e); - exit(1) - }) - .map(|hash| println!("{}", hash)) - } - } - - ("create-profile-blob", Some(mtch)) => { - debug!("Calling: create-profile-blob"); - let (_config, repo) = boot(); - - let content = { - let devices = mtch.values_of("device").unwrap(); // safe by clap - let timestamp = mtch.value_of("timestamp") - .map(|t| { - t.parse::<NaiveDateTime>() - .map(Timestamp::from) - .unwrap_or_else(|e| { - error!("Could not parse time: {:?}", e); - exit(1) - }) - }); - - let names = mtch.values_of("names").unwrap().map(String::from).collect(); // safe by clap - let picture = if let Some(pic) = mtch.value_of("picture") { - Some(IPFSHash::from(String::from(pic))) - } else { - None - }; - let more = if let Some(more) = mtch.value_of("more") { - let json : BTreeMap<String, types::content::Userdata> = serde_json_from_str(more) - .unwrap_or_else(|e| { - error!("Error: {:?}", e); - exit(1) - }); - - Some(json) - } else { - None - }; - - let payload = Payload::Profile { - names, picture, more: more.unwrap_or_else(|| BTreeMap::new()) - }; - - let devices = devices.map(String::from).map(IPNSHash::from).collect(); - Content::new(devices, timestamp, payload) - }; - - { - repo.put_content(content) - .await - .map_err(|e| { - error!("Error running: {:?}", e); - print_error_details(e); - exit(1) - }) - .map(|hash| println!("{}", hash)) - } - } - - ("create-block-blob", Some(mtch)) => { - debug!("Calling: create-block-blob"); - let (_config, repo) = boot(); - - let block = { - let version = usize::from_str(mtch.value_of("version").unwrap()) // safe by clap - .map(Version::from) - .unwrap_or_else(|e| { - error!("Could not parse version: {:?}", e); - exit(1) - }); - let parents = if let Some(parents) = mtch.values_of("parents") { - parents.map(String::from).map(IPFSHash::from).collect() - } else { - vec![] - }; - - let content = mtch.value_of("content").map(String::from).map(IPFSHash::from).unwrap(); // safe by clap - - Block::new(version, parents, content) - }; - - { - repo.put_block(block) - .await - .map_err(|e| { - error!("Error running: {:?}", e); - print_error_details(e); - exit(1) - }) - .map(|hash| println!("{}", hash)) - } + tokio::spawn(async move { + App::load(name, key, &api_url, api_port) + }) + } else { + // ask user for name(s) + // boot repository + // load App object + unimplemented!() } + }.await?; - (other, _mtch) => { - error!("Unknown or unimplemented command: {}", other); - exit(1) - } - } -} + drop(config); -fn print_error_details(e: ::failure::Error) { - error!(" backtrace: {}", e.backtrace()); - { - let mut last_cause = Some(e.as_fail()); - while last_cause.is_some() { - error!(" -> {}", last_cause.unwrap()); - last_cause = last_cause.unwrap().cause(); - } - } - match e.downcast().unwrap() { - ipfs_api::response::Error::Client(e) => error!(" -> {}", e), - ipfs_api::response::Error::Http(e) => error!(" -> {}", e), - ipfs_api::response::Error::Parse(e) => error!(" -> {}", e), - ipfs_api::response::Error::ParseUtf8(e) => error!(" -> {}", e), - ipfs_api::response::Error::Url(e) => error!(" -> {}", e), - ipfs_api::response::Error::Io(e) => error!(" -> {}", e), - ipfs_api::response::Error::EncodeUrl(e) => error!(" -> {}", e), - ipfs_api::response::Error::Api(e) => error!(" -> {}", e), - ipfs_api::response::Error::StreamError(s) => error!(" -> {}", s), - ipfs_api::response::Error::UnrecognizedTrailerHeader(s) => error!(" -> {}", s), - ipfs_api::response::Error::Uncategorized(s) => error!(" -> {}", s), - } + Ok(()) } |