From ad117bf3ece950f52e2428c09287d910f3731979 Mon Sep 17 00:00:00 2001 From: MedzikUser Date: Wed, 24 Aug 2022 15:35:51 +0200 Subject: [PATCH] feat: move cli to other crate and add The Null Pointer (0x0.st) --- Cargo.lock | 29 ++++-- Cargo.toml | 30 +++---- imgurs-cli/Cargo.toml | 36 ++++++++ {src => imgurs-cli/src}/config/mod.rs | 0 {src => imgurs-cli/src}/config/toml.rs | 4 +- .../cli => imgurs-cli/src/imgur}/clipboard.rs | 0 {src/cli => imgurs-cli/src/imgur}/credits.rs | 0 .../src/imgur}/delete_image.rs | 0 .../src/imgur}/info_image.rs | 0 {src/cli => imgurs-cli/src/imgur}/mod.rs | 14 ++- .../src/imgur}/upload_image.rs | 2 +- src/cli/parse.rs => imgurs-cli/src/main.rs | 59 +++++++------ src/{api => }/error.rs | 0 src/{api => imgur}/client.rs | 0 src/{api => imgur}/image_type.rs | 0 src/{api => imgur}/mod.rs | 4 +- src/{api => imgur}/requests/delete_image.rs | 0 src/{api => imgur}/requests/get_image.rs | 0 src/{api => imgur}/requests/mod.rs | 0 src/{api => imgur}/requests/rate_limit.rs | 0 src/{api => imgur}/requests/upload_image.rs | 0 src/{api => imgur}/send_api_request.rs | 8 +- src/lib.rs | 15 +++- src/main.rs | 21 ----- src/null_pointer/mod.rs | 88 +++++++++++++++++++ 25 files changed, 221 insertions(+), 89 deletions(-) create mode 100644 imgurs-cli/Cargo.toml rename {src => imgurs-cli/src}/config/mod.rs (100%) rename {src => imgurs-cli/src}/config/toml.rs (92%) rename {src/cli => imgurs-cli/src/imgur}/clipboard.rs (100%) rename {src/cli => imgurs-cli/src/imgur}/credits.rs (100%) rename {src/cli => imgurs-cli/src/imgur}/delete_image.rs (100%) rename {src/cli => imgurs-cli/src/imgur}/info_image.rs (100%) rename {src/cli => imgurs-cli/src/imgur}/mod.rs (92%) rename {src/cli => imgurs-cli/src/imgur}/upload_image.rs (95%) rename src/cli/parse.rs => imgurs-cli/src/main.rs (50%) rename src/{api => }/error.rs (100%) rename src/{api => imgur}/client.rs (100%) rename src/{api => imgur}/image_type.rs (100%) rename src/{api => imgur}/mod.rs (98%) rename src/{api => imgur}/requests/delete_image.rs (100%) rename src/{api => imgur}/requests/get_image.rs (100%) rename src/{api => imgur}/requests/mod.rs (100%) rename src/{api => imgur}/requests/rate_limit.rs (100%) rename src/{api => imgur}/requests/upload_image.rs (100%) rename src/{api => imgur}/send_api_request.rs (82%) delete mode 100644 src/main.rs create mode 100644 src/null_pointer/mod.rs diff --git a/Cargo.lock b/Cargo.lock index c17774f..8bfc98f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -852,10 +852,23 @@ dependencies = [ [[package]] name = "imgurs" version = "0.8.1" +dependencies = [ + "base64", + "notify-rust", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "validator", +] + +[[package]] +name = "imgurs-cli" +version = "0.8.1" dependencies = [ "anyhow", "arboard", - "base64", "better-panic", "chrono", "clap", @@ -863,16 +876,13 @@ dependencies = [ "clap_mangen", "colored", "dirs", + "imgurs", "log", "notify-rust", - "reqwest", "serde", - "serde_json", "simple_logger", - "thiserror", "tokio", "toml", - "validator", ] [[package]] @@ -1619,6 +1629,7 @@ dependencies = [ "atty", "colored", "log", + "time 0.3.11", "winapi", ] @@ -1787,10 +1798,18 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" dependencies = [ + "itoa", "libc", "num_threads", + "time-macros", ] +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index 950b11e..972478d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,25 @@ +[workspace] +members = ["imgurs-cli"] +resolver = "2" + [package] name = "imgurs" version = "0.8.1" -description = "API and CLI for Imgur" +description = "API for Imgur" license = "BSD-3-Clause" -readme = "README.md" authors = ["MedzikUser "] homepage = "https://github.com/MedzikUser/imgurs" repository = "https://github.com/MedzikUser/imgurs.git" keywords = ["imgur", "imgur-api", "image", "image-upload"] -categories = ["command-line-utilities"] rust-version = "1.58" edition = "2021" +[features] +default = ["imgur"] +full = ["imgur", "null_pointer"] +imgur = [] +null_pointer = [] + [profile.release] lto = true panic = 'abort' @@ -19,25 +27,13 @@ opt-level = 'z' codegen-units = 1 [dependencies] -dirs = "4.0.0" -toml = "0.5.9" -chrono = "0.4.22" base64 = "0.13.0" notify-rust = "4.5.8" -clap_complete = "3.2.4" -anyhow = "1.0.62" -better-panic = "0.3.0" validator = "0.16.0" -colored = "2.0.0" -clap_mangen = "0.1.10" thiserror = "1.0.32" serde_json = "1.0.85" serde = { version = "1.0.144", features = ["derive"] } -clap = { version = "3.2.17", features = ["derive"] } -log = { version = "0.4.17", features = ["release_max_level_info", "max_level_debug"] } -simple_logger = { version = "2.3.0", default-features = false, features = ["colors"] } reqwest = { version = "0.11.11", default-features = false, features = ["json", "rustls-tls"] } -tokio = { version = "1.20.1", features = ["macros", "rt-multi-thread"] } -[target.'cfg(not(all(unix, not(any(target_os="macos", target_os="android", target_os="emscripten")))))'.dependencies] -arboard = "2.1.1" +[dev-dependencies] +tokio = { version = "1.20.1", features = ["macros", "rt-multi-thread"] } diff --git a/imgurs-cli/Cargo.toml b/imgurs-cli/Cargo.toml new file mode 100644 index 0000000..4437ba9 --- /dev/null +++ b/imgurs-cli/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "imgurs-cli" +version = "0.8.1" +description = "CLI for Imgur" +license = "BSD-3-Clause" +authors = ["MedzikUser "] +homepage = "https://github.com/MedzikUser/imgurs" +repository = "https://github.com/MedzikUser/imgurs.git" +keywords = ["imgur", "imgur-api", "image", "image-upload"] +categories = ["command-line-utilities"] +rust-version = "1.58" +edition = "2021" + +[[bin]] +name = "imgurs" +path = "src/main.rs" + +[dependencies] +anyhow = "1.0.62" +clap = { version = "3.2.17", features = ["derive"] } +clap_complete = "3.2.4" +clap_mangen = "0.1.10" +chrono = "0.4.22" +colored = "2.0.0" +notify-rust = "4.5.8" +better-panic = "0.3.0" +dirs = "4.0.0" +log = "0.4.17" +simple_logger = "2.3.0" +toml = "0.5.9" +serde = { version = "1.0.144", features = ["derive"] } +tokio = { version = "1.20.1", features = ["macros", "rt-multi-thread"] } +imgurs = { path = "..", features = ["full"] } + +[target.'cfg(not(all(unix, not(any(target_os="macos", target_os="android", target_os="emscripten")))))'.dependencies] +arboard = "2.1.1" diff --git a/src/config/mod.rs b/imgurs-cli/src/config/mod.rs similarity index 100% rename from src/config/mod.rs rename to imgurs-cli/src/config/mod.rs diff --git a/src/config/toml.rs b/imgurs-cli/src/config/toml.rs similarity index 92% rename from src/config/toml.rs rename to imgurs-cli/src/config/toml.rs index f114f36..784a864 100644 --- a/src/config/toml.rs +++ b/imgurs-cli/src/config/toml.rs @@ -28,9 +28,9 @@ pub fn parse() -> Config { .expect("failed to read line"); if value.to_lowercase() != "n\n" { - warn!("Parse toml config: {err}! Creating config file..."); + warn!("Parse toml config error: {err}! Creating config file..."); - let default_config = include_str!(concat!("../../config.toml")); + let default_config = include_str!(concat!("../../../config.toml")); let sys_config_dir = config_dir().expect("find config dir"); let config_dir = format!("{}{CONFIG_DIR}", sys_config_dir.to_string_lossy()); diff --git a/src/cli/clipboard.rs b/imgurs-cli/src/imgur/clipboard.rs similarity index 100% rename from src/cli/clipboard.rs rename to imgurs-cli/src/imgur/clipboard.rs diff --git a/src/cli/credits.rs b/imgurs-cli/src/imgur/credits.rs similarity index 100% rename from src/cli/credits.rs rename to imgurs-cli/src/imgur/credits.rs diff --git a/src/cli/delete_image.rs b/imgurs-cli/src/imgur/delete_image.rs similarity index 100% rename from src/cli/delete_image.rs rename to imgurs-cli/src/imgur/delete_image.rs diff --git a/src/cli/info_image.rs b/imgurs-cli/src/imgur/info_image.rs similarity index 100% rename from src/cli/info_image.rs rename to imgurs-cli/src/imgur/info_image.rs diff --git a/src/cli/mod.rs b/imgurs-cli/src/imgur/mod.rs similarity index 92% rename from src/cli/mod.rs rename to imgurs-cli/src/imgur/mod.rs index b1876a1..920591f 100644 --- a/src/cli/mod.rs +++ b/imgurs-cli/src/imgur/mod.rs @@ -1,12 +1,10 @@ -mod parse; +mod clipboard; +mod credits; +mod delete_image; +mod info_image; +mod upload_image; -pub mod clipboard; -pub mod credits; -pub mod delete_image; -pub mod info_image; -pub mod upload_image; - -pub use parse::*; +pub use self::{clipboard::*, credits::*, delete_image::*, info_image::*, upload_image::*}; use chrono::{prelude::DateTime, Utc}; use colored::Colorize; diff --git a/src/cli/upload_image.rs b/imgurs-cli/src/imgur/upload_image.rs similarity index 95% rename from src/cli/upload_image.rs rename to imgurs-cli/src/imgur/upload_image.rs index e8ed99b..572f9f2 100644 --- a/src/cli/upload_image.rs +++ b/imgurs-cli/src/imgur/upload_image.rs @@ -2,8 +2,8 @@ use imgurs::ImgurClient; use notify_rust::Notification; use crate::{ - cli::{clipboard::set_clipboard, print_image_info}, config::toml, + imgur::{clipboard::set_clipboard, print_image_info}, }; // show notification diff --git a/src/cli/parse.rs b/imgurs-cli/src/main.rs similarity index 50% rename from src/cli/parse.rs rename to imgurs-cli/src/main.rs index 45695c7..8067384 100644 --- a/src/cli/parse.rs +++ b/imgurs-cli/src/main.rs @@ -1,26 +1,21 @@ -use clap::{Command, IntoApp, Parser, Subcommand}; +use std::io::stdout; + +use crate::imgur::*; +use clap::{Command, CommandFactory, Parser}; use clap_complete::{generate, Generator, Shell}; use imgurs::ImgurClient; -use std::io::{self, stdout}; +use simple_logger::SimpleLogger; -use crate::cli::{credits::*, delete_image::*, info_image::*, upload_image::*}; - -// get version from Cargo.toml -const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION"); +mod config; +mod imgur; #[derive(Parser, Debug)] #[clap( name = "imgurs", about = "Imgur API CLI", long_about = None, - version = VERSION.unwrap_or("unknown") + version = env!("CARGO_PKG_VERSION"), )] -struct Cli { - #[clap(subcommand)] - command: Commands, -} - -#[derive(Subcommand, Debug)] -enum Commands { +enum Cli { #[clap(about = "Print Client Rate Limit", display_order = 1)] Credits, @@ -43,34 +38,44 @@ enum Commands { Manpage, } -fn print_completions(gen: G, app: &mut Command) { - generate(gen, app, app.get_name().to_string(), &mut stdout()) -} - #[tokio::main] -pub async fn parse(client: ImgurClient) { +async fn main() { + SimpleLogger::new().init().unwrap(); + better_panic::install(); + + // parse config file + let config = config::toml::parse(); + + // create imgur client + let client = ImgurClient::new(&config.imgur.id); + let args = Cli::parse(); - match args.command { - Commands::Credits => credits(client).await, + match args { + Cli::Credits => credits(client).await, - Commands::Upload { path } => upload_image(client, path.to_string()).await, + Cli::Upload { path } => upload_image(client, path.to_string()).await, - Commands::Delete { delete_hash } => delete_image(client, delete_hash.to_string()).await, + Cli::Delete { delete_hash } => delete_image(client, delete_hash.to_string()).await, - Commands::Info { id } => image_info(client, id.to_string()).await, + Cli::Info { id } => image_info(client, id.to_string()).await, - Commands::Completions { shell } => { + Cli::Completions { shell } => { let mut app = Cli::command(); + fn print_completions(gen: G, app: &mut Command) { + generate(gen, app, app.get_name().to_string(), &mut stdout()) + } + print_completions(shell, &mut app) } - Commands::Manpage => { + Cli::Manpage => { let clap_app = Cli::command(); let man = clap_mangen::Man::new(clap_app); - man.render(&mut io::stdout()).expect("generate manpage") + man.render(&mut stdout()) + .expect("failed to generate man page"); } } } diff --git a/src/api/error.rs b/src/error.rs similarity index 100% rename from src/api/error.rs rename to src/error.rs diff --git a/src/api/client.rs b/src/imgur/client.rs similarity index 100% rename from src/api/client.rs rename to src/imgur/client.rs diff --git a/src/api/image_type.rs b/src/imgur/image_type.rs similarity index 100% rename from src/api/image_type.rs rename to src/imgur/image_type.rs diff --git a/src/api/mod.rs b/src/imgur/mod.rs similarity index 98% rename from src/api/mod.rs rename to src/imgur/mod.rs index 584248b..e1aeb9e 100644 --- a/src/api/mod.rs +++ b/src/imgur/mod.rs @@ -1,15 +1,15 @@ mod client; -mod error; mod image_type; mod requests; mod send_api_request; pub(crate) use client::api_url; pub use client::ImgurClient; -pub use error::*; pub use image_type::*; pub use send_api_request::*; +use crate::{Error, Result}; + impl ImgurClient { /// Create a new Imgur Client /// ``` diff --git a/src/api/requests/delete_image.rs b/src/imgur/requests/delete_image.rs similarity index 100% rename from src/api/requests/delete_image.rs rename to src/imgur/requests/delete_image.rs diff --git a/src/api/requests/get_image.rs b/src/imgur/requests/get_image.rs similarity index 100% rename from src/api/requests/get_image.rs rename to src/imgur/requests/get_image.rs diff --git a/src/api/requests/mod.rs b/src/imgur/requests/mod.rs similarity index 100% rename from src/api/requests/mod.rs rename to src/imgur/requests/mod.rs diff --git a/src/api/requests/rate_limit.rs b/src/imgur/requests/rate_limit.rs similarity index 100% rename from src/api/requests/rate_limit.rs rename to src/imgur/requests/rate_limit.rs diff --git a/src/api/requests/upload_image.rs b/src/imgur/requests/upload_image.rs similarity index 100% rename from src/api/requests/upload_image.rs rename to src/imgur/requests/upload_image.rs diff --git a/src/api/send_api_request.rs b/src/imgur/send_api_request.rs similarity index 82% rename from src/api/send_api_request.rs rename to src/imgur/send_api_request.rs index fe44bc2..35aa630 100644 --- a/src/api/send_api_request.rs +++ b/src/imgur/send_api_request.rs @@ -17,13 +17,13 @@ pub async fn send_api_request( // create Request buidler let mut req = client.request(method, uri.as_str()); - // get imgurs version - let version: &str = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"); - // add `Authorization` and `User-Agent` to Request req = req .header("Authorization", format!("Client-ID {}", config.client_id)) - .header("User-Agent", format!("Imgur/{:?}", version)); + .header( + "User-Agent", + format!("Imgur/{:?}", env!("CARGO_PKG_VERSION")), + ); // if exists add HashMap to Request if form != None { diff --git a/src/lib.rs b/src/lib.rs index 1d3369e..d052075 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,6 +91,17 @@ #![warn(missing_docs)] -mod api; +mod error; +pub use error::*; -pub use api::*; +#[cfg(feature = "imgur")] +mod imgur; + +#[cfg(feature = "imgur")] +pub use imgur::*; + +#[cfg(feature = "null_pointer")] +mod null_pointer; + +#[cfg(feature = "null_pointer")] +pub use null_pointer::*; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index d13f4ea..0000000 --- a/src/main.rs +++ /dev/null @@ -1,21 +0,0 @@ -use imgurs::ImgurClient; -use simple_logger::SimpleLogger; - -mod cli; -mod config; - -fn main() { - // init logger - SimpleLogger::new().init().expect("init SimpleLogger"); - // init better_panic - better_panic::install(); - - // parse config file - let config = config::toml::parse(); - - // create imgur client - let client = ImgurClient::new(&config.imgur.id); - - // parse cli - cli::parse(client) -} diff --git a/src/null_pointer/mod.rs b/src/null_pointer/mod.rs new file mode 100644 index 0000000..6cb5947 --- /dev/null +++ b/src/null_pointer/mod.rs @@ -0,0 +1,88 @@ +use std::collections::HashMap; + +use reqwest::{Client, Method}; + +use crate::{Error, Result}; + +#[derive(Debug, Clone)] +/// The Null Pointer instance for https://0x0.st +pub struct NullPointer { + client: Client, + url: String, +} + +impl NullPointer { + /// Create a new [NullPointer] instance. + /// ```rs + /// use imgurs::NullPointer; + /// + /// let client = NullPointer::new("https://0x0.st"); + /// ``` + pub fn new(url: &str) -> Self { + let client = reqwest::Client::new(); + Self { + client, + url: url.to_string(), + } + } + + /// Upload image to Imgur + /// ```no_run + /// use imgurs::NullPointer; + /// + /// #[tokio::main] + /// async fn main() { + /// let client = NullPointer::new("https://0x0.st"); + /// + /// client.upload("path/to/file.png").await.expect("failed to upload image"); + /// } + /// ``` + pub async fn upload(&self, path: &str) -> Result { + // create http form (hashmap) + let mut form = HashMap::new(); + + // check if the specified file exists if not then check if it is a url + if std::path::Path::new(path).exists() { + let bytes = std::fs::read(path)?; + + form.insert("file", bytes); + } + // validate url adress + else { + Err(Error::InvalidUrlOrFile(path.to_string()))?; + } + + // send request to imgur api + // get http client + let client = &self.client; + + // create Request buidler + let mut req = client.request(Method::POST, &self.url); + + // add `Authorization` and `User-Agent` to Request + req = req.header( + "User-Agent", + format!("Imgur/{:?}", env!("CARGO_PKG_VERSION")), + ); + + req = req.form(&form); + + // build Request + let req = req.build()?; + + // send Request + let res = client.execute(req).await?; + + // get response http code + let status = res.status(); + + // check if an error has occurred + if status.is_client_error() || status.is_server_error() { + let body = res.text().await?; + + return Err(Error::ApiError(status.as_u16(), body)); + } + + Ok(res.json().await?) + } +}