Properly handle Result types
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -26,6 +26,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.8.4"
|
||||
@@ -656,6 +662,7 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
name = "xmpp-blackbox-exporter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
"regex",
|
||||
"serde",
|
||||
|
@@ -4,6 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.98"
|
||||
axum = "0.8.4"
|
||||
regex = "1.11.1"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
|
78
src/main.rs
78
src/main.rs
@@ -1,5 +1,16 @@
|
||||
use anyhow::{
|
||||
anyhow,
|
||||
Context,
|
||||
};
|
||||
use axum::{
|
||||
extract::Query,
|
||||
http::{
|
||||
StatusCode,
|
||||
},
|
||||
response::{
|
||||
IntoResponse,
|
||||
Response,
|
||||
},
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
@@ -40,11 +51,42 @@ impl ProbeFacts {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct AppError(anyhow::Error);
|
||||
|
||||
impl std::fmt::Display for AppError {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, formatter)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AppError {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(&self.0, formatter)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Internal server error:\n{:?}", self),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> From<E> for AppError where E: Into<anyhow::Error> {
|
||||
fn from(err: E) -> Self {
|
||||
Self(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
|
||||
let mut args = std::env::args();
|
||||
let _name = args.next().unwrap();
|
||||
let _name = args.next().ok_or(anyhow!(""))?;
|
||||
|
||||
let mut listen = String::from("[::]:3000");
|
||||
|
||||
@@ -57,7 +99,7 @@ async fn main() {
|
||||
|
||||
match arg.as_str() {
|
||||
"--listen" => {
|
||||
listen = args.next().unwrap();
|
||||
listen = args.next().ok_or(anyhow!(""))?;
|
||||
}
|
||||
unknown => {
|
||||
println!("unknown option: {}", unknown);
|
||||
@@ -70,40 +112,45 @@ async fn main() {
|
||||
.route("/", get(route_index))
|
||||
.route("/probe-client-to-server", get(route_probe_client_to_server));
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(listen).await.unwrap();
|
||||
println!("Server listening on: http://{}", listener.local_addr().unwrap());
|
||||
let listener = tokio::net::TcpListener::bind(listen).await?;
|
||||
println!("Server listening on: http://{}", listener.local_addr()?);
|
||||
println!("Probe with:");
|
||||
println!(" http://{}/probe-client-to-server?domain=fem-net.de&hostname=xmpp-2.fem-net.de&port=5222", listener.local_addr().unwrap());
|
||||
println!(" http://{}/probe-client-to-server?domain=fem-net.de&hostname=xmpp-2.fem-net.de&port=5222", listener.local_addr()?);
|
||||
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
axum::serve(listener, app).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn route_index() -> String {
|
||||
return String::from("Prometheus exporter for checking XMPP server availability");
|
||||
}
|
||||
|
||||
async fn probe_client_to_server(domain: &str, hostname: &str, port: u16) -> Result<ProbeFacts, String> {
|
||||
async fn probe_client_to_server(domain: &str, hostname: &str, port: u16) -> anyhow::Result<ProbeFacts> {
|
||||
let mut probe_facts = ProbeFacts::new();
|
||||
|
||||
let mut stream = TcpStream::connect((hostname, port)).await.unwrap();
|
||||
let mut stream = TcpStream::connect((hostname, port)).await
|
||||
.context("Couldn't connect to XMPP server")?;
|
||||
|
||||
let connect_string = format!("<stream:stream to='{}' xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' xml:lang='en' version='1.0'></stream:stream>", domain);
|
||||
|
||||
stream.write_all(connect_string.as_bytes()).await.unwrap();
|
||||
stream.write_all(connect_string.as_bytes()).await
|
||||
.context("Failed to write XMPP connection test payload")?;
|
||||
|
||||
let mut stream = BufReader::new(stream);
|
||||
|
||||
let mut response = String::new();
|
||||
stream.read_line(&mut response).await.unwrap();
|
||||
stream.read_line(&mut response).await
|
||||
.context("Failed to read XMPP connection response")?;
|
||||
|
||||
println!("{}", response);
|
||||
|
||||
let re_match_xmpp_stream = Regex::new(r"http://etherx\.jabber\.org/streams").unwrap();
|
||||
let re_match_xmpp_stream = Regex::new(r"http://etherx\.jabber\.org/streams")?;
|
||||
if re_match_xmpp_stream.is_match(&response) {
|
||||
probe_facts.is_xmpp_stream = true;
|
||||
}
|
||||
|
||||
let re_match_xmpp_client = Regex::new(r"jabber:client").unwrap();
|
||||
let re_match_xmpp_client = Regex::new(r"jabber:client")?;
|
||||
if re_match_xmpp_client.is_match(&response) {
|
||||
probe_facts.is_xmpp_client = true;
|
||||
}
|
||||
@@ -113,9 +160,10 @@ async fn probe_client_to_server(domain: &str, hostname: &str, port: u16) -> Resu
|
||||
|
||||
async fn route_probe_client_to_server(
|
||||
Query(query): Query<ProbeClientToServerQuery>,
|
||||
) -> Result<String, String> {
|
||||
) -> Result<impl IntoResponse, AppError> {
|
||||
|
||||
let probe_facts = probe_client_to_server(&query.domain, &query.hostname, query.port).await.unwrap();
|
||||
let probe_facts = probe_client_to_server(&query.domain, &query.hostname, query.port).await
|
||||
.context("Failed probing XMPP connection")?;
|
||||
|
||||
let mut out = String::new();
|
||||
|
||||
|
Reference in New Issue
Block a user