Skip to content

Commit

Permalink
return error instead of panicking when creating a new server (#4)
Browse files Browse the repository at this point in the history
* return error instead of panicking

Signed-off-by: Dan Bond <danbond@protonmail.com>

* bump prometheus-client to 0.18

Signed-off-by: Dan Bond <danbond@protonmail.com>

* errors -> error

Signed-off-by: Dan Bond <danbond@protonmail.com>

* use enum for error

Signed-off-by: Dan Bond <danbond@protonmail.com>

Signed-off-by: Dan Bond <danbond@protonmail.com>
  • Loading branch information
loshz authored Aug 20, 2022
1 parent 25c68a4 commit 1f2db21
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 28 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "metrics_server"
version = "0.8.1"
version = "0.9.0"
authors = ["Dan Bond <danbond@protonmail.com>"]
edition = "2021"
rust-version = "1.58"
Expand All @@ -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]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 19 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -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 {}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
27 changes: 17 additions & 10 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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<A>(addr: A, certificate: Option<Vec<u8>>, private_key: Option<Vec<u8>>) -> Self
pub fn new<A>(
addr: A,
certificate: Option<Vec<u8>>,
private_key: Option<Vec<u8>>,
) -> Result<Self, ServerError>
where
A: ToSocketAddrs,
{
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand Down
43 changes: 30 additions & 13 deletions tests/server.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use metrics_server::MetricsServer;

#[test]
#[should_panic]
fn test_new_server_invalid_address() {
let _ = MetricsServer::new("invalid:99999999", None, None);
}
Expand All @@ -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.
Expand All @@ -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]
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down

0 comments on commit 1f2db21

Please sign in to comment.