mirror of
https://github.com/LordMZTE/mcstat.git
synced 2024-05-05 14:21:09 +02:00
switch to miette
This commit is contained in:
parent
f015c85c60
commit
d97865c360
12
Cargo.toml
12
Cargo.toml
|
@ -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]
|
||||||
|
|
30
src/lib.rs
30
src/lib.rs
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
38
src/main.rs
38
src/main.rs
|
@ -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(())
|
||||||
|
|
Loading…
Reference in a new issue