feat: move cli to other crate and add The Null Pointer (0x0.st)

This commit is contained in:
MedzikUser 2022-08-24 15:35:51 +02:00
parent be73023511
commit ad117bf3ec
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
25 changed files with 221 additions and 89 deletions

29
Cargo.lock generated
View File

@ -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"

View File

@ -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 <nivua1fn@duck.com>"]
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"] }

36
imgurs-cli/Cargo.toml Normal file
View File

@ -0,0 +1,36 @@
[package]
name = "imgurs-cli"
version = "0.8.1"
description = "CLI for Imgur"
license = "BSD-3-Clause"
authors = ["MedzikUser <nivua1fn@duck.com>"]
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"

View File

@ -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());

View File

@ -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;

View File

@ -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

View File

@ -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<G: Generator>(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<G: Generator>(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");
}
}
}

View File

@ -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
/// ```

View File

@ -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 {

View File

@ -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::*;

View File

@ -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)
}

88
src/null_pointer/mod.rs Normal file
View File

@ -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<String> {
// 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?)
}
}