use std::fmt; #[derive(Copy, Clone, Debug)] pub enum Kind { InvalidEndpointError, JsonParseError, DatabaseConnectionError, DatabaseError, HttpRequestParseError, IoError, WebSocketError, NotImplementedError, UsimpProtocolError, } #[derive(Copy, Clone, Debug)] pub enum Class { ClientError, ServerError, } #[derive(Debug)] pub struct Error { kind: Kind, msg: Option, desc: Option, class: Class, } impl Error { pub fn new(kind: Kind, class: Class) -> Self { Error { kind, msg: None, desc: None, class, } } pub fn class(&self) -> &Class { &self.class } pub fn set_msg(mut self, msg: String) -> Self { self.msg = Some(msg); self } pub fn msg(&self) -> &str { match &self.msg { Some(msg) => msg.as_str(), None => match self.kind { Kind::InvalidEndpointError => "Invalid endpoint", Kind::JsonParseError => "Unable to parse JSON data", Kind::DatabaseConnectionError => "Unable to connect to database", Kind::DatabaseError => "Database error", Kind::HttpRequestParseError => "Unable to parse http request", Kind::IoError => "IO error", Kind::WebSocketError => "WebSocket protocol error", Kind::NotImplementedError => "Not yet implemented", Kind::UsimpProtocolError => "USIMP protocol error", }, } } pub fn set_desc(mut self, desc: String) -> Self { self.desc = Some(desc); self } pub fn desc(&self) -> Option<&str> { match &self.desc { Some(desc) => Some(desc.as_str()), None => None, } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut error = match self.kind { Kind::InvalidEndpointError => "invalid endpoint", Kind::JsonParseError => "unable to parse json data", Kind::DatabaseConnectionError => "unable to connect to database", Kind::DatabaseError => "database error", Kind::HttpRequestParseError => "unable to parse http request", Kind::IoError => "io error", Kind::WebSocketError => "websocket protocol error", Kind::NotImplementedError => "not yet implemented", Kind::UsimpProtocolError => "usimp protocol error", } .to_string(); if let Some(desc) = &self.desc { error += ": "; error += desc; } write!(f, "{}", error) } } impl From for Error { fn from(error: std::io::Error) -> Self { Error { kind: Kind::IoError, msg: Some(error.to_string()), desc: Some(error.to_string()), class: Class::ClientError, } } } impl From for Error { fn from(error: serde_json::Error) -> Self { Error { kind: Kind::JsonParseError, msg: Some("Unable to parse JSON data".to_string()), desc: Some(error.to_string()), class: Class::ClientError, } } } impl From for Error { fn from(error: r2d2::Error) -> Self { Error { kind: Kind::DatabaseConnectionError, msg: Some("Unable to connect to database".to_string()), desc: Some(error.to_string()), class: Class::ServerError, } } } impl From for Error { fn from(error: r2d2_postgres::postgres::Error) -> Self { // format: "db error: ERROR ..." let msg = error.to_string().split(":").skip(1).collect::(); Error { kind: Kind::DatabaseError, msg: Some("Database error".to_string()), desc: Some(msg.trim().to_string()), class: Class::ServerError, } } }