bit better error handling

This commit is contained in:
2021-05-19 20:13:00 +02:00
parent 204fe4d942
commit e5b77edeae
5 changed files with 75 additions and 22 deletions

View File

@ -15,3 +15,4 @@ chrono = "0.4"
flate2 = "1.0.0" flate2 = "1.0.0"
r2d2 = "0.8.9" r2d2 = "0.8.9"
r2d2_postgres = "0.18.0" r2d2_postgres = "0.18.0"
ansi_term = "0.12"

View File

@ -1,7 +1,9 @@
use crate::error::Error;
use r2d2_postgres::postgres::NoTls; use r2d2_postgres::postgres::NoTls;
use r2d2_postgres::PostgresConnectionManager; use r2d2_postgres::PostgresConnectionManager;
use std::ops::Deref; use std::ops::Deref;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::Duration;
pub enum Pool { pub enum Pool {
Postgres(r2d2::Pool<PostgresConnectionManager<NoTls>>), Postgres(r2d2::Pool<PostgresConnectionManager<NoTls>>),
@ -13,16 +15,24 @@ pub enum Client {
static mut POOL: Option<Arc<Mutex<Pool>>> = None; static mut POOL: Option<Arc<Mutex<Pool>>> = None;
pub fn init() { pub fn init() -> Result<(), Error> {
let manager = PostgresConnectionManager::new( let manager = PostgresConnectionManager::new(
"host=localhost user=postgres dbname=test".parse().unwrap(), "host=localhost user=postgres dbname=test".parse().unwrap(),
NoTls, NoTls,
); );
let pool = r2d2::Pool::new(manager).unwrap(); let pool = r2d2::Pool::builder()
.max_size(64)
.min_idle(Some(2))
.connection_timeout(Duration::from_secs(4))
.max_lifetime(Some(Duration::from_secs(3600)))
.build(manager)?;
unsafe { unsafe {
POOL = Some(Arc::new(Mutex::new(Pool::Postgres(pool)))); POOL = Some(Arc::new(Mutex::new(Pool::Postgres(pool))));
} }
Ok(())
} }
pub fn client() -> Client { pub fn client() -> Client {

View File

@ -1,34 +1,50 @@
pub enum ErrorKind { pub enum ErrorKind {
InvalidEndpoint, InvalidEndpointError,
JsonParseError, JsonParseError,
DatabaseError,
} }
pub struct Error { pub struct Error {
kind: ErrorKind, kind: ErrorKind,
desc: Option<String>,
} }
impl Error { impl Error {
pub fn new(kind: ErrorKind) -> Error { pub fn new(kind: ErrorKind) -> Error {
Error { Error { kind, desc: None }
kind,
}
}
}
impl From<serde_json::Error> for Error {
fn from(_: serde_json::Error) -> Self {
Error {
kind: ErrorKind::JsonParseError,
}
} }
} }
impl ToString for Error { impl ToString for Error {
fn to_string(&self) -> String { fn to_string(&self) -> String {
match self.kind { let mut error = match self.kind {
ErrorKind::InvalidEndpoint => "invalid endpoint", ErrorKind::InvalidEndpointError => "invalid endpoint",
ErrorKind::JsonParseError => "JSON parse error", ErrorKind::JsonParseError => "unable to parse JSON data",
}.to_string() ErrorKind::DatabaseError => "unable to connect to database",
}
.to_string();
if let Some(desc) = &self.desc {
error += ": ";
error += desc;
}
error
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Self {
Error {
kind: ErrorKind::JsonParseError,
desc: Some(error.to_string()),
}
}
}
impl From<r2d2::Error> for Error {
fn from(error: r2d2::Error) -> Self {
Error {
kind: ErrorKind::DatabaseError,
desc: Some(error.to_string()),
}
} }
} }

View File

@ -3,16 +3,18 @@ use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::thread; use std::thread;
use ansi_term::Color;
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use rusty_pool; use rusty_pool;
use std::fmt::Formatter;
use std::time::Duration; use std::time::Duration;
mod database; mod database;
mod error;
mod http; mod http;
mod udp; mod udp;
mod usimp; mod usimp;
mod websocket; mod websocket;
mod error;
enum SocketType { enum SocketType {
Http, Http,
@ -20,12 +22,24 @@ enum SocketType {
Udp, Udp,
} }
impl std::fmt::Display for SocketType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match self {
SocketType::Http => "http+ws",
SocketType::Https => "https+wss",
SocketType::Udp => "udp",
})
}
}
struct SocketConfig { struct SocketConfig {
address: SocketAddr, address: SocketAddr,
socket_type: SocketType, socket_type: SocketType,
} }
fn main() { fn main() {
println!("Locutus server");
let socket_configs: Vec<SocketConfig> = vec![ let socket_configs: Vec<SocketConfig> = vec![
SocketConfig { SocketConfig {
address: "[::]:8080".parse().unwrap(), address: "[::]:8080".parse().unwrap(),
@ -41,7 +55,13 @@ fn main() {
}, },
]; ];
database::init(); // Note: rust's stdout is line buffered!
eprint!("Initializing database connection pool...");
if let Err(error) = database::init() {
eprintln!("\n{}", Color::Red.bold().paint(error.to_string()));
std::process::exit(1);
}
eprintln!(" {}", Color::Green.paint("success"));
let thread_pool = rusty_pool::Builder::new() let thread_pool = rusty_pool::Builder::new()
.core_size(4) .core_size(4)
@ -55,6 +75,12 @@ fn main() {
for socket_config in socket_configs { for socket_config in socket_configs {
let thread_pool_mutex = thread_pool_mutex.clone(); let thread_pool_mutex = thread_pool_mutex.clone();
eprintln!(
"Creating listening thread for {} ({})",
ansi_term::Style::new().bold().paint(socket_config.address.to_string()),
socket_config.socket_type
);
threads.push(match socket_config.socket_type { threads.push(match socket_config.socket_type {
SocketType::Http => thread::spawn(move || { SocketType::Http => thread::spawn(move || {
let mut tcp_socket = TcpListener::bind(socket_config.address).unwrap(); let mut tcp_socket = TcpListener::bind(socket_config.address).unwrap();

View File

@ -7,7 +7,7 @@ use crate::error::*;
pub fn endpoint(endpoint: &str, input: serde_json::Value) -> Result<serde_json::Value, Error> { pub fn endpoint(endpoint: &str, input: serde_json::Value) -> Result<serde_json::Value, Error> {
match endpoint { match endpoint {
"echo" => Ok(serde_json::to_value(echo(serde_json::from_value(input)?))?), "echo" => Ok(serde_json::to_value(echo(serde_json::from_value(input)?))?),
_ => Err(Error::new(ErrorKind::InvalidEndpoint)), _ => Err(Error::new(ErrorKind::InvalidEndpointError)),
} }
} }