diff --git a/Cargo.toml b/Cargo.toml index 9082bce..cee028e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "metrics_server" -version = "0.8.1" +version = "0.9.0" authors = ["Dan Bond "] edition = "2021" rust-version = "1.58" @@ -18,11 +18,11 @@ include = ["src/**/*", "tests", "examples", "Cargo.toml", "LICENSE", "README.md" doctest = false [dependencies] -tiny_http = "0.11" log = "0.4" +tiny_http = "0.11" [dev-dependencies] -prometheus-client = "0.16" +prometheus-client = "0.18" reqwest = { version = "0.11", features = ["blocking"] } [features] diff --git a/README.md b/README.md index e99c68a..18aa88f 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,13 @@ This crate provides a thread safe, minimalstic HTTP/S server used to buffer metr Include the lib in your `Cargo.toml` dependencies: ```toml [dependencies] -metrics_server = "0.8" +metrics_server = "0.9" ``` To enable TLS support, pass the optional feature flag: ```toml [dependencies] -metrics_server = { version = "0.8", features = ["tls"] } +metrics_server = { version = "0.9", features = ["tls"] } ``` ### HTTP diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..80321c0 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,19 @@ +use std::error::Error; +use std::fmt; + +/// The error type for MetricsServer operations. +#[derive(Debug)] +pub enum ServerError { + /// Represents an error while creating a new server. + Create(String), +} + +impl fmt::Display for ServerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ServerError::Create(s) => write!(f, "error creating metrics server: {}", s), + } + } +} + +impl Error for ServerError {} diff --git a/src/lib.rs b/src/lib.rs index 6de807e..35e175b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,8 @@ //! let bytes = server.update(Vec::from([1, 2, 3, 4])); //! assert_eq!(4, bytes); //! ``` +mod error; mod server; +pub use error::ServerError; pub use server::MetricsServer; diff --git a/src/server.rs b/src/server.rs index 9deb4ac..5b99b64 100644 --- a/src/server.rs +++ b/src/server.rs @@ -3,6 +3,8 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use std::thread; +use crate::error::ServerError; + use log::{debug, error}; use tiny_http::{Method, Response, Server}; @@ -20,11 +22,11 @@ struct MetricsServerShared { impl MetricsServer { /// Creates an empty `MetricsServer` with a configured HTTP/S server. - /// - /// # Panics - /// - /// Panics if given an invalid address or incorrect TLS credentials. - pub fn new(addr: A, certificate: Option>, private_key: Option>) -> Self + pub fn new( + addr: A, + certificate: Option>, + private_key: Option>, + ) -> Result where A: ToSocketAddrs, { @@ -42,17 +44,20 @@ impl MetricsServer { _ => tiny_http::ServerConfig { addr, ssl: None }, }; + // Attempt to create a new server. + let server = Server::new(config).map_err(|e| ServerError::Create(e.to_string()))?; + // Create an Arc of the shared data. let shared = Arc::new(MetricsServerShared { data: Mutex::new(Vec::new()), - server: Server::new(config).unwrap(), + server, stop: AtomicBool::new(false), }); - MetricsServer { + Ok(MetricsServer { shared, thread: None, - } + }) } /// Shortcut for creating an empty `MetricsServer` and starting a HTTP server on a new thread at the given address. @@ -66,7 +71,7 @@ impl MetricsServer { where A: ToSocketAddrs, { - MetricsServer::new(addr, None, None).serve() + MetricsServer::new(addr, None, None).unwrap().serve() } /// Shortcut for creating an empty `MetricsServer` and starting a HTTPS server on a new thread at the given address. @@ -83,7 +88,9 @@ impl MetricsServer { where A: ToSocketAddrs, { - MetricsServer::new(addr, Some(certificate), Some(private_key)).serve() + MetricsServer::new(addr, Some(certificate), Some(private_key)) + .unwrap() + .serve() } /// Safely updates the data in a `MetricsServer` and returns the number of bytes written. diff --git a/tests/server.rs b/tests/server.rs index 6bc907d..0fa9c05 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -1,7 +1,6 @@ use metrics_server::MetricsServer; #[test] -#[should_panic] fn test_new_server_invalid_address() { let _ = MetricsServer::new("invalid:99999999", None, None); } @@ -12,30 +11,47 @@ fn test_new_http_server() { } #[test] -#[should_panic] #[cfg(feature = "tls")] -fn test_new_server_invalid_cert() { +fn test_new_server_invalid_certificate() { // Load TLS config. - let cert = Vec::new(); + let cert = "-----BEGIN CERTIFICATE----- +invaid certificate +-----END CERTIFICATE-----" + .as_bytes() + .to_vec(); let key = include_bytes!("./certs/private_key.pem").to_vec(); - let _ = MetricsServer::new("localhost:8441", Some(cert), Some(key)); + let server = MetricsServer::new("localhost:8441", Some(cert), Some(key)); + assert!(server.is_err()); + + if let Err(error) = server { + assert!(error.to_string().contains("error creating metrics server")) + } } #[test] -#[should_panic] #[cfg(feature = "tls")] -fn test_new_server_invalid_key() { +fn test_new_server_invalid_private_key() { // Load TLS config. let cert = include_bytes!("./certs/certificate.pem").to_vec(); - let key = Vec::new(); + let key = "-----BEGIN PRIVATE KEY----- +-----END PRIVATE KEY-----" + .as_bytes() + .to_vec(); - let _ = MetricsServer::new("localhost:8442", Some(cert), Some(key)); + let server = MetricsServer::new("localhost:8442", Some(cert), Some(key)); + assert!(server.is_err()); + + if let Err(error) = server { + assert!(error.to_string().contains("error creating metrics server")) + } } #[test] fn test_new_server_already_running() { - let srv = MetricsServer::new("localhost:8002", None, None).serve(); + let srv = MetricsServer::new("localhost:8002", None, None) + .unwrap() + .serve(); // Attempt to start an already running server should be ok // as we will return the pre-existing thread. @@ -48,7 +64,8 @@ fn test_new_https_server() { let cert = include_bytes!("./certs/certificate.pem").to_vec(); let key = include_bytes!("./certs/private_key.pem").to_vec(); - let _ = MetricsServer::new("localhost:8443", Some(cert), Some(key)); + let server = MetricsServer::new("localhost:8443", Some(cert), Some(key)); + assert!(server.is_ok()); } #[test] @@ -102,7 +119,7 @@ fn test_https_server_invalid_address() { #[test] #[should_panic] #[cfg(feature = "tls")] -fn test_https_server_invalid_cert() { +fn test_https_server_invalid_certificate() { // Load TLS config. let cert = Vec::new(); let key = include_bytes!("./certs/private_key.pem").to_vec(); @@ -113,7 +130,7 @@ fn test_https_server_invalid_cert() { #[test] #[should_panic] #[cfg(feature = "tls")] -fn test_https_server_invalid_key() { +fn test_https_server_invalid_private_key() { // Load TLS config. let cert = include_bytes!("./certs/certificate.pem").to_vec(); let key = Vec::new();