switch to miette

This commit is contained in:
LordMZTE 2021-10-09 00:30:41 +02:00
parent f015c85c60
commit d97865c360
3 changed files with 44 additions and 36 deletions

View file

@ -7,28 +7,30 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0.43"
base64 = "0.13.0" base64 = "0.13.0"
crossterm = "0.21.0" crossterm = "0.21.0"
image = "0.23.14" image = "0.23.14"
itertools = "0.10.1" itertools = "0.10.1"
serde_json = "1.0.67" miette = { version = "3.2.0", features = ["fancy"] }
serde_json = "1.0.68"
smart-default = "0.6.0" smart-default = "0.6.0"
structopt = "0.3.23" structopt = "0.3.23"
term_size = "0.3.2" term_size = "0.3.2"
termcolor = "1.1.2" termcolor = "1.1.2"
unicode-width = "0.1.8" unicode-width = "0.1.9"
viuer = "0.5.2" viuer = "0.5.2"
[dependencies.async-minecraft-ping] [dependencies.async-minecraft-ping]
git = "https://github.com/LordMZTE/async-minecraft-ping.git" git = "https://github.com/LordMZTE/async-minecraft-ping.git"
tag = "v0.2.5" tag = "v0.3.0"
[dependencies.tokio] [dependencies.tokio]
version = "1.11.0" version = "1.12.0"
features = ["rt-multi-thread", "macros", "time"] features = ["rt-multi-thread", "macros", "time"]
[build-dependencies] [build-dependencies]
clap = "2.33.3" clap = "2.33.3"
lazy_static = "1.4.0" lazy_static = "1.4.0"
yaml-rust = "0.4.5" yaml-rust = "0.4.5"
[features]

View file

@ -2,13 +2,13 @@
extern crate smart_default; extern crate smart_default;
use crate::output::Table; use crate::output::Table;
use anyhow::{anyhow, bail, Context};
use crossterm::{ use crossterm::{
style::{Attribute, Color, Print, ResetColor, SetAttribute, SetForegroundColor}, style::{Attribute, Color, Print, ResetColor, SetAttribute, SetForegroundColor},
ExecutableCommand, ExecutableCommand,
}; };
use image::{DynamicImage, ImageFormat}; use image::{DynamicImage, ImageFormat};
use itertools::Itertools; use itertools::Itertools;
use miette::{bail, miette, IntoDiagnostic, WrapErr};
use std::io::{self, Cursor, Write}; use std::io::{self, Cursor, Write};
pub mod output; pub mod output;
@ -82,7 +82,7 @@ pub fn print_mc_formatted(s: &str, mut out: impl Write) -> io::Result<()> {
'n' => exec!(at, Underlined), 'n' => exec!(at, Underlined),
'o' => exec!(at, Italic), 'o' => exec!(at, Italic),
'r' => exec!(ResetColor), 'r' => exec!(ResetColor),
_ => {}, _ => {}
} }
exec!(Print(&split[1..])); exec!(Print(&split[1..]));
} }
@ -134,28 +134,32 @@ pub fn get_table<'a>(
} }
/// parses a base64 formatted image /// parses a base64 formatted image
pub fn parse_base64_image(data: String) -> anyhow::Result<DynamicImage> { pub fn parse_base64_image(data: String) -> miette::Result<DynamicImage> {
let (header, data) = data let (header, data) = data
.split_once(',') .split_once(',')
.context("Couldn't parse base64 image due to missing format header.")?; .ok_or_else(|| miette!("Couldn't parse base64 image due to missing format header."))?;
let (data_type, image_format) = header let (data_type, image_format) = header
.split_once('/') .split_once('/')
.context("Failed to parse base64 image, header has invalid format.")?; .ok_or_else(|| miette!("Failed to parse base64 image, header has invalid format."))?;
let image_format = image_format let image_format = image_format
.split(';') .split(';')
.next() .next()
.context("Failed to parse base64 image, header has invalid format.")?; .ok_or_else(|| miette!("Failed to parse base64 image, header has invalid format."))?;
if data_type != "data:image" { if data_type != "data:image" {
bail!("base64 image is not an image! Has type {}", data_type); bail!("base64 image is not an image! Has type {}", data_type);
} }
let format = ImageFormat::from_extension(image_format).context(format!( let format = ImageFormat::from_extension(image_format).ok_or_else(|| {
"Failed to parse base64 image due to unknown image type: {}", miette!(
image_format "Failed to parse base64 image due to unknown image type: {}",
))?; image_format
let data = )
base64::decode(data).map_err(|e| anyhow!("Failed to decode base64 image data: {}", e))?; })?;
let data = base64::decode(data)
.into_diagnostic()
.wrap_err("Failed to decode base64 image data")?;
image::load(Cursor::new(data), format) image::load(Cursor::new(data), format)
.map_err(|e| anyhow!("Failed to load base64 image: {}", e)) .into_diagnostic()
.wrap_err("Failed to load base64 image")
} }

View file

@ -1,7 +1,7 @@
use anyhow::{anyhow, Context, Result};
use async_minecraft_ping::{ConnectionConfig, ServerDescription, StatusResponse}; use async_minecraft_ping::{ConnectionConfig, ServerDescription, StatusResponse};
use itertools::Itertools; use itertools::Itertools;
use miette::{miette, IntoDiagnostic, WrapErr};
use structopt::StructOpt; use structopt::StructOpt;
use time::{Duration, Instant}; use time::{Duration, Instant};
use tokio::time; use tokio::time;
@ -74,23 +74,24 @@ impl Opt {
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> miette::Result<()> {
let opt = Opt::from_args_safe()?; let opt = Opt::from_args();
let mut ip = opt.ip.splitn(2, ':'); let mut ip = opt.ip.splitn(2, ':');
let config = ConnectionConfig::build(ip.next().context("invalid ip")?.to_owned()) let config =
.with_port( ConnectionConfig::build(ip.next().ok_or_else(|| miette!("invalid ip"))?.to_owned())
ip.next() .with_port(
.map_or(Err(()), |p| p.parse::<u16>().map_err(|_| ())) ip.next()
.and_then(|p| if p > 0 { Ok(p) } else { Err(()) }) .map_or(Err(()), |p| p.parse::<u16>().map_err(|_| ()))
.unwrap_or(25565), .and_then(|p| if p > 0 { Ok(p) } else { Err(()) })
) .unwrap_or(25565),
.with_protocol_version(opt.protocol_version); )
.with_protocol_version(opt.protocol_version);
// create timeout for server connection // create timeout for server connection
let (raw_response, ping) = time::timeout(Duration::from_millis(opt.timeout), async { let (raw_response, ping) = time::timeout(Duration::from_millis(opt.timeout), async {
let start_time = Instant::now(); let start_time = Instant::now();
let mut con = config.connect().await?; let mut con = config.connect().await.into_diagnostic()?;
// we end the timer here, because at this point, we've sent ONE request to the // we end the timer here, because at this point, we've sent ONE request to the
// server, and we don't want to send 2, since then we get double the // server, and we don't want to send 2, since then we get double the
// ping. the connect function may have some processing which may take // ping. the connect function may have some processing which may take
@ -98,10 +99,11 @@ async fn main() -> Result<()> {
// speed. // speed.
let end_time = Instant::now(); let end_time = Instant::now();
let status = con.status_raw().await?; let status = con.status_raw().await.into_diagnostic()?;
Result::<_, anyhow::Error>::Ok((status, end_time - start_time)) Result::<_, miette::Error>::Ok((status, end_time - start_time))
}) })
.await .await
.into_diagnostic()
.context("Connection to server timed out.")??; .context("Connection to server timed out.")??;
if opt.raw { if opt.raw {
@ -109,7 +111,7 @@ async fn main() -> Result<()> {
return Ok(()); return Ok(());
} }
let response = serde_json::from_str::<StatusResponse>(&raw_response)?; let response = serde_json::from_str::<StatusResponse>(&raw_response).into_diagnostic()?;
// endregion // endregion
// region printing // region printing
@ -126,12 +128,12 @@ async fn main() -> Result<()> {
opt.modversions, opt.modversions,
opt.channels, opt.channels,
) )
.stdout()?; .stdout()
.into_diagnostic()?;
if let (Some(img), true) = (response.favicon, opt.image) { if let (Some(img), true) = (response.favicon, opt.image) {
let decoded = parse_base64_image(img)?; let decoded = parse_base64_image(img)?;
viuer::print(&decoded, &opt.get_viuer_conf()) viuer::print(&decoded, &opt.get_viuer_conf()).into_diagnostic()?;
.map_err(|e| anyhow!("Failed to print favicon: {}", e))?;
} }
// endregion // endregion
Ok(()) Ok(())