This repository has been archived by the owner on Jul 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from 21re/next2
Preparing to merge with master
- Loading branch information
Showing
23 changed files
with
2,767 additions
and
1,815 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,33 @@ | ||
[package] | ||
name = "microtools" | ||
version = "0.1.0" | ||
version = "0.2.0" | ||
authors = ["Bodo Junglas <[email protected]>", "Ihor Mordashev <[email protected]"] | ||
edition = "2018" | ||
|
||
[dependencies] | ||
actix = "0.7" | ||
actix-web = "0.7" | ||
actix = "0.9" | ||
actix-web = "3.2" | ||
awc = "1" | ||
serde = { version = "1.0", features = ["rc"] } | ||
serde_derive = "1.0" | ||
serde_json = "1.0" | ||
futures = "0.1" | ||
futures = "0.3" | ||
|
||
toml = { version = "0.4", optional = true } | ||
log = "0.4" | ||
bytes = "0.4.10" | ||
bytes = "0.5" | ||
prometheus = { version = "0.5", features = ["process"] } | ||
chrono = { version = "0.4", features = ["serde"], optional = true } | ||
slog = { version = "2.4", optional = true } | ||
slog-envlogger = { version = "2.1", optional = true } | ||
slog-async = { version = "2.3", optional = true } | ||
slog-json = { version = "2.2", optional = true } | ||
slog-stdlog = { version = "3.0", optional = true } | ||
slog-scope = { version = "4.0", optional = true } | ||
slog = { version = "2.5", optional = true } | ||
slog-envlogger = { version = "2.2", optional = true } | ||
slog-async = { version = "2.5", optional = true } | ||
slog-json = { version = "2.3", optional = true } | ||
slog-stdlog = { version = "4.0", optional = true } | ||
slog-scope = { version = "4.3", optional = true } | ||
r2d2 = { version = "0.8", optional = true } | ||
diesel = { version = "1.3", optional = true } | ||
url = { version = "1.7", features = ["query_encoding"] } | ||
reqwest = { version = "0.9", optional = true } | ||
url = { version = "2" } | ||
reqwest = { version = "0.10", features = ["json", "stream"] } | ||
config = { version = "0.9", optional = true } | ||
|
||
[dev-dependencies] | ||
|
@@ -35,5 +37,4 @@ spectral = "0.6" | |
with-toml = ["toml"] | ||
with-slog = ["slog", "slog-envlogger", "slog-async", "slog-json", "slog-stdlog", "slog-scope", "chrono"] | ||
with-diesel = ["r2d2", "diesel"] | ||
with-reqwest = ["reqwest"] | ||
with-config = ["config"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
pub mod auth_middleware; | ||
pub mod business_result; | ||
pub mod elasticsearch; | ||
#[cfg(test)] | ||
pub mod elasticsearch_test; | ||
pub mod gatekeeper; | ||
#[cfg(feature = "with-slog")] | ||
pub mod logging_slog; | ||
pub mod metrics; | ||
pub mod parse_request; | ||
mod problem; | ||
pub mod retry; | ||
#[cfg(test)] | ||
mod retry_tests; | ||
pub mod serde_field_value; | ||
pub mod service_requester; | ||
#[cfg(test)] | ||
mod service_requester_test; | ||
pub mod status; | ||
pub mod subject; | ||
pub mod types; | ||
pub mod ws_try; | ||
|
||
pub use crate::business_result::{AsyncBusinessResult, BusinessResult, BusinessResultExt}; | ||
pub use crate::parse_request::*; | ||
pub use crate::problem::*; | ||
pub use crate::service_requester::*; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,268 @@ | ||
use actix; | ||
use actix_web; | ||
use log::error; | ||
use serde_derive::{Deserialize, Serialize}; | ||
use serde_json; | ||
use std; | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] | ||
pub struct Problem { | ||
pub code: u16, | ||
#[serde(rename = "type")] | ||
pub problem_type: String, | ||
pub reason: String, | ||
pub details: Option<String>, | ||
} | ||
|
||
impl Problem { | ||
pub fn for_status<S: Into<String>>(code: u16, reason: S) -> Problem { | ||
Problem { | ||
code, | ||
problem_type: format!("https://httpstatus.es/{}", code), | ||
reason: reason.into(), | ||
details: None, | ||
} | ||
} | ||
|
||
pub fn bad_request() -> Problem { | ||
Self::for_status(400, "Bad request") | ||
} | ||
|
||
pub fn unauthorized() -> Problem { | ||
Self::for_status(401, "Unauthorized") | ||
} | ||
|
||
pub fn forbidden() -> Problem { | ||
Self::for_status(403, "Forbidden") | ||
} | ||
|
||
pub fn conflict() -> Problem { | ||
Self::for_status(409, "Conflict") | ||
} | ||
|
||
pub fn internal_server_error() -> Problem { | ||
Self::for_status(500, "Internal server error") | ||
} | ||
|
||
pub fn not_found() -> Problem { | ||
Self::for_status(404, "Not found") | ||
} | ||
|
||
pub fn method_not_allowed() -> Problem { | ||
Self::for_status(405, "Method not allowed") | ||
} | ||
|
||
pub fn failed_dependency() -> Problem { | ||
Self::for_status(424, "Failed dependency") | ||
} | ||
|
||
pub fn with_details<T: std::fmt::Display>(mut self, details: T) -> Problem { | ||
self.details = match self.details { | ||
Some(existing) => Some(format!("{}: {}", existing, details)), | ||
None => Some(format!("{}", details)), | ||
}; | ||
self | ||
} | ||
} | ||
|
||
impl std::fmt::Display for Problem { | ||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { | ||
match self.details { | ||
Some(ref details) => write!( | ||
f, | ||
"Problem(code={}, reason={}, details={})", | ||
self.code, self.reason, details | ||
)?, | ||
None => write!(f, "Problem(code={}, reason={})", self.code, self.reason)?, | ||
}; | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl std::error::Error for Problem {} | ||
|
||
impl From<std::env::VarError> for Problem { | ||
fn from(error: std::env::VarError) -> Problem { | ||
use std::env::VarError::*; | ||
|
||
match error { | ||
NotPresent => Problem::internal_server_error().with_details("Environment variable missing"), | ||
NotUnicode(_) => Problem::internal_server_error().with_details("Environment variable not unicode"), | ||
} | ||
} | ||
} | ||
|
||
impl From<std::io::Error> for Problem { | ||
fn from(error: std::io::Error) -> Problem { | ||
error!("IO: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("IO: {}", error)) | ||
} | ||
} | ||
|
||
impl<T> From<std::sync::PoisonError<T>> for Problem { | ||
fn from(error: std::sync::PoisonError<T>) -> Problem { | ||
error!("Sync poison: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Sync poison: {}", error)) | ||
} | ||
} | ||
|
||
impl From<std::time::SystemTimeError> for Problem { | ||
fn from(error: std::time::SystemTimeError) -> Problem { | ||
error!("SystemTime error: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("SystemTime error: {}", error)) | ||
} | ||
} | ||
|
||
impl From<std::str::Utf8Error> for Problem { | ||
fn from(error: std::str::Utf8Error) -> Problem { | ||
error!("UTF-8 error: {}", error); | ||
|
||
Problem::bad_request().with_details(format!("UTF-8 error: {}", error)) | ||
} | ||
} | ||
|
||
impl From<actix_web::error::Error> for Problem { | ||
fn from(error: actix_web::Error) -> Problem { | ||
error!("Actix: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Actix: {}", error)) | ||
} | ||
} | ||
|
||
impl actix_web::error::ResponseError for Problem { | ||
fn error_response(&self) -> actix_web::HttpResponse { | ||
actix_web::HttpResponse::build( | ||
actix_web::http::StatusCode::from_u16(self.code).unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR), | ||
) | ||
.json(self) | ||
} | ||
} | ||
|
||
impl actix_web::Responder for Problem { | ||
type Item = actix_web::HttpResponse; | ||
type Error = Problem; | ||
|
||
fn respond_to<S: 'static>(self, _req: &actix_web::HttpRequest<S>) -> Result<actix_web::HttpResponse, Problem> { | ||
Ok( | ||
actix_web::HttpResponse::build( | ||
actix_web::http::StatusCode::from_u16(self.code).unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR), | ||
) | ||
.json(self), | ||
) | ||
} | ||
} | ||
|
||
impl From<actix_web::client::SendRequestError> for Problem { | ||
fn from(error: actix_web::client::SendRequestError) -> Problem { | ||
use actix_web::client::SendRequestError::*; | ||
|
||
error!("Http client: {}", error); | ||
|
||
match error { | ||
Timeout => Problem::internal_server_error().with_details("Request timeout"), | ||
Connector(err) => Problem::internal_server_error().with_details(format!("HTTP connection error: {}", err)), | ||
ParseError(err) => Problem::internal_server_error().with_details(format!("Invalid HTTP response: {}", err)), | ||
Io(err) => Problem::from(err), | ||
} | ||
} | ||
} | ||
|
||
impl From<actix_web::error::PayloadError> for Problem { | ||
fn from(error: actix_web::error::PayloadError) -> Self { | ||
error!("Http payload: {}", error); | ||
Problem::internal_server_error().with_details(format!("Http payload: {}", error)) | ||
} | ||
} | ||
|
||
impl From<actix_web::error::ReadlinesError> for Problem { | ||
fn from(error: actix_web::error::ReadlinesError) -> Self { | ||
use actix_web::error::ReadlinesError::*; | ||
|
||
match error { | ||
EncodingError => Problem::internal_server_error().with_details("Readline: Invalid encoding"), | ||
PayloadError(error) => Problem::from(error), | ||
LimitOverflow => Problem::internal_server_error().with_details("Readline: Limit exeeded"), | ||
ContentTypeError(error) => Problem::from(error), | ||
} | ||
} | ||
} | ||
|
||
impl From<actix_web::error::ContentTypeError> for Problem { | ||
fn from(error: actix_web::error::ContentTypeError) -> Self { | ||
error!("Http content type: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Http content type: {}", error)) | ||
} | ||
} | ||
|
||
impl From<actix_web::error::JsonPayloadError> for Problem { | ||
fn from(error: actix_web::error::JsonPayloadError) -> Self { | ||
error!("Http json type: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Http json payload: {}", error)) | ||
} | ||
} | ||
|
||
impl From<actix::MailboxError> for Problem { | ||
fn from(error: actix::MailboxError) -> Self { | ||
error!("Actix mailbox error: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Actix mailbox error: {}", error)) | ||
} | ||
} | ||
|
||
#[cfg(feature = "with-toml")] | ||
impl From<::toml::de::Error> for Problem { | ||
fn from(error: ::toml::de::Error) -> Self { | ||
error!("Toml: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Toml: {}", error)) | ||
} | ||
} | ||
|
||
impl From<serde_json::Error> for Problem { | ||
fn from(error: serde_json::Error) -> Self { | ||
error!("Json: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Json: {}", error)) | ||
} | ||
} | ||
|
||
#[cfg(feature = "with-diesel")] | ||
impl From<::r2d2::Error> for Problem { | ||
fn from(error: ::r2d2::Error) -> Self { | ||
error!("R2D2: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("R2D2: {}", error)) | ||
} | ||
} | ||
|
||
#[cfg(feature = "with-diesel")] | ||
impl From<::diesel::result::Error> for Problem { | ||
fn from(error: ::diesel::result::Error) -> Self { | ||
error!("Diesel result: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Diesel result: {}", error)) | ||
} | ||
} | ||
|
||
#[cfg(feature = "with-reqwest")] | ||
impl From<::reqwest::Error> for Problem { | ||
fn from(error: ::reqwest::Error) -> Self { | ||
error!("Reqwest error: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Request result: {}", error)) | ||
} | ||
} | ||
|
||
#[cfg(feature = "with-config")] | ||
impl From<::config::ConfigError> for Problem { | ||
fn from(error: ::config::ConfigError) -> Self { | ||
error!("Config error: {}", error); | ||
|
||
Problem::internal_server_error().with_details(format!("Config: {}", error)) | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
Oops, something went wrong.