Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::{borrow::Cow, fmt::Debug, str::FromStr, time::Duration};
|
||||
|
||||
use compact_str::{CompactString, ToCompactString, format_compact};
|
||||
use mail_auth::common::verify::VerifySignature;
|
||||
|
||||
use crate::*;
|
||||
|
||||
impl AsRef<EventType> for Error {
|
||||
fn as_ref(&self) -> &EventType {
|
||||
&self.0.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Value {
|
||||
fn from(value: &'static str) -> Self {
|
||||
Self::String(CompactString::const_new(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Value {
|
||||
fn from(value: String) -> Self {
|
||||
Self::String(CompactString::from_string_buffer(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompactString> for Value {
|
||||
fn from(value: CompactString) -> Self {
|
||||
Self::String(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<str>> for Value {
|
||||
fn from(value: Box<str>) -> Self {
|
||||
Self::String(CompactString::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Value {
|
||||
fn from(value: u64) -> Self {
|
||||
Self::UInt(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Value {
|
||||
fn from(value: i64) -> Self {
|
||||
Self::Int(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Value {
|
||||
fn from(value: f64) -> Self {
|
||||
Self::Float(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for Value {
|
||||
fn from(value: f32) -> Self {
|
||||
Self::Float(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for Value {
|
||||
fn from(value: u16) -> Self {
|
||||
Self::UInt(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Value {
|
||||
fn from(value: i32) -> Self {
|
||||
Self::Int(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Value {
|
||||
fn from(value: u32) -> Self {
|
||||
Self::UInt(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Value {
|
||||
fn from(value: usize) -> Self {
|
||||
Self::UInt(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Value {
|
||||
fn from(value: bool) -> Self {
|
||||
Self::Bool(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IpAddr> for Value {
|
||||
fn from(value: IpAddr) -> Self {
|
||||
match value {
|
||||
IpAddr::V4(ip) => Value::Ipv4(ip),
|
||||
IpAddr::V6(ip) => Value::Ipv6(ip),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<Value>> From<Option<T>> for Value {
|
||||
fn from(value: Option<T>) -> Self {
|
||||
match value {
|
||||
Some(value) => value.into(),
|
||||
None => Self::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Duration> for Value {
|
||||
fn from(value: Duration) -> Self {
|
||||
Self::Duration(value.as_millis() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for Value {
|
||||
fn from(value: Error) -> Self {
|
||||
Self::Event(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EventType> for Error {
|
||||
fn from(value: EventType) -> Self {
|
||||
Error::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoreEvent> for Error {
|
||||
fn from(value: StoreEvent) -> Self {
|
||||
Error::new(EventType::Store(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AuthEvent> for Error {
|
||||
fn from(value: AuthEvent) -> Self {
|
||||
Error::new(EventType::Auth(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for Value {
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
Self::Bytes(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for Value {
|
||||
fn from(value: &[u8]) -> Self {
|
||||
Self::Bytes(value.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cow<'static, str>> for Value {
|
||||
fn from(value: Cow<'static, str>) -> Self {
|
||||
match value {
|
||||
Cow::Borrowed(value) => Self::String(CompactString::const_new(value)),
|
||||
Cow::Owned(value) => Self::String(value.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<&crate::Result<T>> for Value
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
fn from(value: &crate::Result<T>) -> Self {
|
||||
match value {
|
||||
Ok(value) => format_compact!("{:?}", value).into(),
|
||||
Err(err) => Value::Event(err.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Vec<T>> for Value
|
||||
where
|
||||
T: Into<Value>,
|
||||
{
|
||||
fn from(value: Vec<T>) -> Self {
|
||||
Self::Array(value.into_iter().map(Into::into).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<&[T]> for Value
|
||||
where
|
||||
T: Into<Value> + Clone,
|
||||
{
|
||||
fn from(value: &[T]) -> Self {
|
||||
Self::Array(value.iter().map(|v| v.clone().into()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl EventType {
|
||||
pub fn from_io_error(self, err: std::io::Error) -> Error {
|
||||
self.reason(err).details("I/O error")
|
||||
}
|
||||
|
||||
pub fn from_json_error(self, err: serde_json::Error) -> Error {
|
||||
self.reason(err).details("JSON deserialization failed")
|
||||
}
|
||||
|
||||
pub fn from_base64_error(self, err: base64::DecodeError) -> Error {
|
||||
self.reason(err).details("Base64 decoding failed")
|
||||
}
|
||||
|
||||
pub fn from_http_error(self, err: reqwest::Error) -> Error {
|
||||
self.into_err()
|
||||
.ctx_opt(
|
||||
Key::Url,
|
||||
err.url().map(|url| url.as_ref().to_compact_string()),
|
||||
)
|
||||
.ctx_opt(Key::Code, err.status().map(|status| status.as_u16()))
|
||||
.reason(err)
|
||||
}
|
||||
|
||||
pub fn from_http_str_error(self, err: reqwest::header::ToStrError) -> Error {
|
||||
self.reason(err)
|
||||
.details("Failed to convert header to string")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<mail_auth::Error> for Error {
|
||||
fn from(err: mail_auth::Error) -> Self {
|
||||
match err {
|
||||
mail_auth::Error::ParseError => {
|
||||
EventType::MailAuth(MailAuthEvent::ParseError).into_err()
|
||||
}
|
||||
mail_auth::Error::MissingParameters => {
|
||||
EventType::MailAuth(MailAuthEvent::MissingParameters).into_err()
|
||||
}
|
||||
mail_auth::Error::NoHeadersFound => {
|
||||
EventType::MailAuth(MailAuthEvent::NoHeadersFound).into_err()
|
||||
}
|
||||
mail_auth::Error::Io(details) => EventType::MailAuth(MailAuthEvent::Io)
|
||||
.into_err()
|
||||
.details(CompactString::from(details)),
|
||||
mail_auth::Error::Base64 => EventType::MailAuth(MailAuthEvent::Base64).into_err(),
|
||||
mail_auth::Error::NotAligned => {
|
||||
EventType::MailAuth(MailAuthEvent::PolicyNotAligned).into_err()
|
||||
}
|
||||
mail_auth::Error::Crypto(err) => match err {
|
||||
mail_auth::common::crypto::CryptoError::Library(details) => {
|
||||
EventType::MailAuth(MailAuthEvent::Crypto)
|
||||
.into_err()
|
||||
.details(CompactString::from(details))
|
||||
}
|
||||
mail_auth::common::crypto::CryptoError::FailedVerification => {
|
||||
EventType::Dkim(DkimEvent::FailedVerification).into_err()
|
||||
}
|
||||
mail_auth::common::crypto::CryptoError::IncompatibleAlgorithms => {
|
||||
EventType::Dkim(DkimEvent::IncompatibleAlgorithms).into_err()
|
||||
}
|
||||
},
|
||||
mail_auth::Error::Dns(err) => match err {
|
||||
mail_auth::DnsError::Resolver(details) => {
|
||||
EventType::MailAuth(MailAuthEvent::DnsError)
|
||||
.into_err()
|
||||
.details(CompactString::from(details))
|
||||
}
|
||||
mail_auth::DnsError::RecordNotFound(code) => {
|
||||
EventType::MailAuth(MailAuthEvent::DnsRecordNotFound)
|
||||
.into_err()
|
||||
.code(code.to_str())
|
||||
}
|
||||
mail_auth::DnsError::InvalidRecordType => {
|
||||
EventType::MailAuth(MailAuthEvent::DnsInvalidRecordType).into_err()
|
||||
}
|
||||
},
|
||||
mail_auth::Error::Dkim(err) => match err {
|
||||
mail_auth::dkim::DkimError::UnsupportedVersion => {
|
||||
EventType::Dkim(DkimEvent::UnsupportedVersion).into_err()
|
||||
}
|
||||
mail_auth::dkim::DkimError::UnsupportedAlgorithm => {
|
||||
EventType::Dkim(DkimEvent::UnsupportedAlgorithm).into_err()
|
||||
}
|
||||
mail_auth::dkim::DkimError::UnsupportedCanonicalization => {
|
||||
EventType::Dkim(DkimEvent::UnsupportedCanonicalization).into_err()
|
||||
}
|
||||
mail_auth::dkim::DkimError::UnsupportedKeyType => {
|
||||
EventType::Dkim(DkimEvent::UnsupportedKeyType).into_err()
|
||||
}
|
||||
mail_auth::dkim::DkimError::FailedBodyHashMatch => {
|
||||
EventType::Dkim(DkimEvent::FailedBodyHashMatch).into_err()
|
||||
}
|
||||
mail_auth::dkim::DkimError::FailedAuidMatch => {
|
||||
EventType::Dkim(DkimEvent::FailedAuidMatch).into_err()
|
||||
}
|
||||
mail_auth::dkim::DkimError::RevokedPublicKey => {
|
||||
EventType::Dkim(DkimEvent::RevokedPublicKey).into_err()
|
||||
}
|
||||
mail_auth::dkim::DkimError::SignatureExpired => {
|
||||
EventType::Dkim(DkimEvent::SignatureExpired).into_err()
|
||||
}
|
||||
mail_auth::dkim::DkimError::SignatureLength => {
|
||||
EventType::Dkim(DkimEvent::SignatureLength).into_err()
|
||||
}
|
||||
},
|
||||
mail_auth::Error::Arc(err) => match err {
|
||||
mail_auth::arc::ArcError::ChainTooLong => {
|
||||
EventType::Arc(ArcEvent::ChainTooLong).into_err()
|
||||
}
|
||||
mail_auth::arc::ArcError::InvalidInstance(instance) => {
|
||||
EventType::Arc(ArcEvent::InvalidInstance).ctx(Key::Id, instance)
|
||||
}
|
||||
mail_auth::arc::ArcError::InvalidCV => {
|
||||
EventType::Arc(ArcEvent::InvalidCv).into_err()
|
||||
}
|
||||
mail_auth::arc::ArcError::HasHeaderTag => {
|
||||
EventType::Arc(ArcEvent::HasHeaderTag).into_err()
|
||||
}
|
||||
mail_auth::arc::ArcError::BrokenChain => {
|
||||
EventType::Arc(ArcEvent::BrokenChain).into_err()
|
||||
}
|
||||
mail_auth::arc::ArcError::FailedBodyHashMatch => {
|
||||
EventType::Dkim(DkimEvent::FailedBodyHashMatch).into_err()
|
||||
}
|
||||
mail_auth::arc::ArcError::SignatureExpired => {
|
||||
EventType::Dkim(DkimEvent::SignatureExpired).into_err()
|
||||
}
|
||||
mail_auth::arc::ArcError::SignatureLength => {
|
||||
EventType::Dkim(DkimEvent::SignatureLength).into_err()
|
||||
}
|
||||
},
|
||||
mail_auth::Error::Dkim2(err) => match err {
|
||||
mail_auth::dkim2::Dkim2Error::InstanceMissing(m) => {
|
||||
EventType::Dkim(DkimEvent::InstanceMissing).ctx(Key::Id, m)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::InstanceSyntax(m) => {
|
||||
EventType::Dkim(DkimEvent::InstanceSyntax).ctx(Key::Id, m)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::InstanceTagMissing { m, tag } => {
|
||||
EventType::Dkim(DkimEvent::InstanceTagMissing)
|
||||
.ctx(Key::Id, m)
|
||||
.details(tag)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::InstanceNotSigned(m) => {
|
||||
EventType::Dkim(DkimEvent::InstanceNotSigned).ctx(Key::Id, m)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::InstanceAboveSignature(m) => {
|
||||
EventType::Dkim(DkimEvent::InstanceAboveSignature).ctx(Key::Id, m)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::SignatureMissing(i) => {
|
||||
EventType::Dkim(DkimEvent::SignatureMissing).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::SignatureSyntax(i) => {
|
||||
EventType::Dkim(DkimEvent::SignatureSyntax).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::SignatureTagMissing { i, tag } => {
|
||||
EventType::Dkim(DkimEvent::SignatureTagMissing)
|
||||
.ctx(Key::Id, i)
|
||||
.details(tag)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::SignatureTagUnexpected { i, tag } => {
|
||||
EventType::Dkim(DkimEvent::SignatureTagUnexpected)
|
||||
.ctx(Key::Id, i)
|
||||
.details(tag)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::SequenceGap => {
|
||||
EventType::Dkim(DkimEvent::SequenceGap).into_err()
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::SequenceOverflow => {
|
||||
EventType::Dkim(DkimEvent::SequenceOverflow).into_err()
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::ChainTooLong => {
|
||||
EventType::Dkim(DkimEvent::ChainTooLong).into_err()
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::SignatureExpired(i) => {
|
||||
EventType::Dkim(DkimEvent::SignatureExpired).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::MailFromMismatch(i) => {
|
||||
EventType::Dkim(DkimEvent::MailFromMismatch).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::RcptToMismatch(i) => {
|
||||
EventType::Dkim(DkimEvent::RcptToMismatch).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::MailFromDomainMismatch(i) => {
|
||||
EventType::Dkim(DkimEvent::MailFromDomainMismatch).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::NextDomainMismatch(i) => {
|
||||
EventType::Dkim(DkimEvent::NextDomainMismatch).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::CustodyBreak(i) => {
|
||||
EventType::Dkim(DkimEvent::CustodyBreak).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::PublicKeyFetch(i) => {
|
||||
EventType::Dkim(DkimEvent::PublicKeyFetch).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::PublicKeyMissing(i) => {
|
||||
EventType::Dkim(DkimEvent::PublicKeyMissing).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::PublicKeyMultiple(i) => {
|
||||
EventType::Dkim(DkimEvent::PublicKeyMultiple).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::PublicKeySyntax(i) => {
|
||||
EventType::Dkim(DkimEvent::PublicKeySyntax).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::PublicKeyAlgorithmMismatch(i) => {
|
||||
EventType::Dkim(DkimEvent::PublicKeyAlgorithmMismatch).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::PublicKeyRevoked(i) => {
|
||||
EventType::Dkim(DkimEvent::RevokedPublicKey).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::IncorrectSignature(i) => {
|
||||
EventType::Dkim(DkimEvent::FailedVerification).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::NoValidAlgorithm(i) => {
|
||||
EventType::Dkim(DkimEvent::NoValidAlgorithm).ctx(Key::Id, i)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::HeaderHashMismatch(m) => {
|
||||
EventType::Dkim(DkimEvent::HeaderHashMismatch).ctx(Key::Id, m)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::BodyHashMismatch(m) => {
|
||||
EventType::Dkim(DkimEvent::FailedBodyHashMatch).ctx(Key::Id, m)
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::Modified => {
|
||||
EventType::Dkim(DkimEvent::Modified).into_err()
|
||||
}
|
||||
mail_auth::dkim2::Dkim2Error::Exploded => {
|
||||
EventType::Dkim(DkimEvent::Exploded).into_err()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mail_auth::DkimResult> for Error {
|
||||
fn from(value: &mail_auth::DkimResult) -> Self {
|
||||
match value.clone() {
|
||||
mail_auth::DkimResult::Pass => Error::new(EventType::Dkim(DkimEvent::Pass)),
|
||||
mail_auth::DkimResult::Neutral(err) => {
|
||||
Error::new(EventType::Dkim(DkimEvent::Neutral)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::DkimResult::Fail(err) => {
|
||||
Error::new(EventType::Dkim(DkimEvent::Fail)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::DkimResult::PermError(err) => {
|
||||
Error::new(EventType::Dkim(DkimEvent::PermError)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::DkimResult::TempError(err) => {
|
||||
Error::new(EventType::Dkim(DkimEvent::TempError)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::DkimResult::None => Error::new(EventType::Dkim(DkimEvent::None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mail_auth::Dkim2Result> for Error {
|
||||
fn from(value: &mail_auth::Dkim2Result) -> Self {
|
||||
match value.clone() {
|
||||
mail_auth::Dkim2Result::Pass => Error::new(EventType::Dkim(DkimEvent::Pass)),
|
||||
mail_auth::Dkim2Result::Fail(err) => {
|
||||
Error::new(EventType::Dkim(DkimEvent::Fail)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::Dkim2Result::PermError(err) => {
|
||||
Error::new(EventType::Dkim(DkimEvent::PermError)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::Dkim2Result::TempError(err) => {
|
||||
Error::new(EventType::Dkim(DkimEvent::TempError)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::Dkim2Result::None => Error::new(EventType::Dkim(DkimEvent::None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mail_auth::dkim2::Dkim2Output<'_>> for Error {
|
||||
fn from(value: &mail_auth::dkim2::Dkim2Output<'_>) -> Self {
|
||||
Error::from(value.result()).ctx_opt(
|
||||
Key::Domain,
|
||||
value
|
||||
.chain()
|
||||
.first()
|
||||
.map(|link| link.signature.d.to_compact_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mail_auth::DmarcResult> for Error {
|
||||
fn from(value: &mail_auth::DmarcResult) -> Self {
|
||||
match value.clone() {
|
||||
mail_auth::DmarcResult::Pass => Error::new(EventType::Dmarc(DmarcEvent::Pass)),
|
||||
mail_auth::DmarcResult::Fail(err) => {
|
||||
Error::new(EventType::Dmarc(DmarcEvent::Fail)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::DmarcResult::PermError(err) => {
|
||||
Error::new(EventType::Dmarc(DmarcEvent::PermError)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::DmarcResult::TempError(err) => {
|
||||
Error::new(EventType::Dmarc(DmarcEvent::TempError)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::DmarcResult::None => Error::new(EventType::Dmarc(DmarcEvent::None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mail_auth::DkimOutput<'_>> for Error {
|
||||
fn from(value: &mail_auth::DkimOutput<'_>) -> Self {
|
||||
Error::from(value.result()).ctx_opt(
|
||||
Key::Domain,
|
||||
value.signature().map(|s| s.domain().to_compact_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mail_auth::IprevOutput> for Error {
|
||||
fn from(value: &mail_auth::IprevOutput) -> Self {
|
||||
match value.result().clone() {
|
||||
mail_auth::IprevResult::Pass => Error::new(EventType::Iprev(IprevEvent::Pass)),
|
||||
mail_auth::IprevResult::Fail(err) => {
|
||||
Error::new(EventType::Iprev(IprevEvent::Fail)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::IprevResult::PermError(err) => {
|
||||
Error::new(EventType::Iprev(IprevEvent::PermError)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::IprevResult::TempError(err) => {
|
||||
Error::new(EventType::Iprev(IprevEvent::TempError)).caused_by(Error::from(err))
|
||||
}
|
||||
mail_auth::IprevResult::None => Error::new(EventType::Iprev(IprevEvent::None)),
|
||||
}
|
||||
.ctx_opt(
|
||||
Key::Details,
|
||||
value.ptr.as_ref().map(|s| {
|
||||
s.iter()
|
||||
.map(|v| Value::String(v.as_ref().into()))
|
||||
.collect::<Vec<_>>()
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mail_auth::SpfOutput> for Error {
|
||||
fn from(value: &mail_auth::SpfOutput) -> Self {
|
||||
Error::new(EventType::Spf(match value.result() {
|
||||
mail_auth::SpfResult::Pass => SpfEvent::Pass,
|
||||
mail_auth::SpfResult::Fail => SpfEvent::Fail,
|
||||
mail_auth::SpfResult::SoftFail => SpfEvent::SoftFail,
|
||||
mail_auth::SpfResult::Neutral => SpfEvent::Neutral,
|
||||
mail_auth::SpfResult::PermError => SpfEvent::PermError,
|
||||
mail_auth::SpfResult::TempError => SpfEvent::TempError,
|
||||
mail_auth::SpfResult::None => SpfEvent::None,
|
||||
}))
|
||||
.ctx_opt(
|
||||
Key::Details,
|
||||
value.explanation().map(|s| s.to_compact_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rkyv::rancor::Error> for Error {
|
||||
fn from(value: rkyv::rancor::Error) -> Self {
|
||||
Error::new(EventType::Store(StoreEvent::DeserializeError))
|
||||
.reason(value)
|
||||
.details("Rkyv de/serialization failed")
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AssertSuccess
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn assert_success(
|
||||
self,
|
||||
cause: EventType,
|
||||
) -> impl std::future::Future<Output = crate::Result<Self>> + Send;
|
||||
}
|
||||
|
||||
impl AssertSuccess for reqwest::Response {
|
||||
async fn assert_success(self, cause: EventType) -> crate::Result<Self> {
|
||||
let status = self.status();
|
||||
if status.is_success() {
|
||||
Ok(self)
|
||||
} else {
|
||||
Err(cause
|
||||
.ctx(Key::Code, status.as_u16())
|
||||
.details("HTTP request failed")
|
||||
.ctx_opt(Key::Reason, self.text().await.map(CompactString::from).ok()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for EventType {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
EventType::parse(s).ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Key {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
Key::parse(s).ok_or(())
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::Level;
|
||||
use std::{cmp::Ordering, fmt::Display, str::FromStr};
|
||||
|
||||
impl PartialOrd for Level {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Level) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &Level) -> bool {
|
||||
(*other as usize) < (*self as usize)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &Level) -> bool {
|
||||
(*other as usize) <= (*self as usize)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &Level) -> bool {
|
||||
(*other as usize) > (*self as usize)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &Level) -> bool {
|
||||
(*other as usize) >= (*self as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Level {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
(*other as usize).cmp(&(*self as usize))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Level {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
match s.to_ascii_lowercase().as_str() {
|
||||
"disable" => Ok(Self::Disable),
|
||||
"trace" => Ok(Self::Trace),
|
||||
"debug" => Ok(Self::Debug),
|
||||
"info" => Ok(Self::Info),
|
||||
"warn" => Ok(Self::Warn),
|
||||
"error" => Ok(Self::Error),
|
||||
_ => Err(s.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Level {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Disable => "DISABLE",
|
||||
Self::Trace => "TRACE",
|
||||
Self::Debug => "DEBUG",
|
||||
Self::Info => "INFO",
|
||||
Self::Warn => "WARN",
|
||||
Self::Error => "ERROR",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_contained(&self, other: Self) -> bool {
|
||||
*self >= other && other != Level::Disable && *self != Level::Disable
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Level {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.as_str().fmt(f)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,683 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
pub mod conv;
|
||||
pub mod level;
|
||||
|
||||
pub mod enums;
|
||||
#[allow(clippy::match_like_matches_macro)]
|
||||
pub mod enums_impl;
|
||||
|
||||
use compact_str::ToCompactString;
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::*;
|
||||
|
||||
impl<T> Event<T> {
|
||||
pub fn with_capacity(inner: T, capacity: usize) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
keys: Vec::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_keys(inner: T, keys: Vec<(Key, Value)>) -> Self {
|
||||
Self { inner, keys }
|
||||
}
|
||||
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
keys: Vec::with_capacity(5),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(&self, key: Key) -> Option<&Value> {
|
||||
self.keys
|
||||
.iter()
|
||||
.find_map(|(k, v)| if *k == key { Some(v) } else { None })
|
||||
}
|
||||
|
||||
pub fn value_as_str(&self, key: Key) -> Option<&str> {
|
||||
self.value(key).and_then(|v| v.as_str())
|
||||
}
|
||||
|
||||
pub fn value_as_uint(&self, key: Key) -> Option<u64> {
|
||||
self.value(key).and_then(|v| v.to_uint())
|
||||
}
|
||||
|
||||
pub fn take_value(&mut self, key: Key) -> Option<Value> {
|
||||
self.keys.iter_mut().find_map(|(k, v)| {
|
||||
if *k == key {
|
||||
Some(std::mem::take(v))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_boxed(self) -> Box<Self> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
#[inline(always)]
|
||||
pub fn new(inner: EventType) -> Self {
|
||||
Error(Box::new(Event::new(inner)))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_ctx(&mut self, key: Key, value: impl Into<Value>) {
|
||||
self.0.keys.push((key, value.into()));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ctx(mut self, key: Key, value: impl Into<Value>) -> Self {
|
||||
self.0.keys.push((key, value.into()));
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ctx_unique(mut self, key: Key, value: impl Into<Value>) -> Self {
|
||||
if self.0.keys.iter().all(|(k, _)| *k != key) {
|
||||
self.0.keys.push((key, value.into()));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ctx_opt(self, key: Key, value: Option<impl Into<Value>>) -> Self {
|
||||
match value {
|
||||
Some(value) => self.ctx(key, value),
|
||||
None => self,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn matches(&self, inner: EventType) -> bool {
|
||||
self.0.inner == inner
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn event_type(&self) -> EventType {
|
||||
self.0.inner
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn span_id(self, session_id: u64) -> Self {
|
||||
self.ctx(Key::SpanId, session_id)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Self {
|
||||
self.ctx(Key::CausedBy, error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn details(self, error: impl Into<Value>) -> Self {
|
||||
self.ctx(Key::Details, error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn code(self, error: impl Into<Value>) -> Self {
|
||||
self.ctx(Key::Code, error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn id(self, error: impl Into<Value>) -> Self {
|
||||
self.ctx(Key::Id, error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Self {
|
||||
self.ctx(Key::Reason, error.to_compact_string())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn document_id(self, id: u32) -> Self {
|
||||
self.ctx(Key::DocumentId, id)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn account_id(self, id: u32) -> Self {
|
||||
self.ctx(Key::AccountId, id)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn collection(self, id: impl Into<u8>) -> Self {
|
||||
self.ctx(Key::Collection, id.into() as u64)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn wrap(self, cause: EventType) -> Self {
|
||||
Error::new(cause).caused_by(self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn keys(&self) -> &[(Key, Value)] {
|
||||
&self.0.keys
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn value(&self, key: Key) -> Option<&Value> {
|
||||
self.0.value(key)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn value_as_str(&self, key: Key) -> Option<&str> {
|
||||
self.0.value_as_str(key)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn value_as_uint(&self, key: Key) -> Option<u64> {
|
||||
self.0.value_as_uint(key)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn take_value(&mut self, key: Key) -> Option<Value> {
|
||||
self.0.take_value(key)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_assertion_failure(&self) -> bool {
|
||||
self.0.inner == EventType::Store(StoreEvent::AssertValueFailed)
|
||||
}
|
||||
|
||||
pub fn key(&self, key: Key) -> Option<&Value> {
|
||||
self.0
|
||||
.keys
|
||||
.iter()
|
||||
.find_map(|(k, v)| if *k == key { Some(v) } else { None })
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_jmap_method_error(&self) -> bool {
|
||||
!matches!(
|
||||
self.0.inner,
|
||||
EventType::Jmap(
|
||||
JmapEvent::UnknownCapability | JmapEvent::NotJson | JmapEvent::NotRequest
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn must_disconnect(&self) -> bool {
|
||||
matches!(
|
||||
self.0.inner,
|
||||
EventType::Network(_)
|
||||
| EventType::Auth(AuthEvent::TooManyAttempts)
|
||||
| EventType::Limit(LimitEvent::ConcurrentRequest | LimitEvent::TooManyRequests)
|
||||
| EventType::Security(_)
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn should_write_err(&self) -> bool {
|
||||
!matches!(self.0.inner, EventType::Network(_) | EventType::Security(_))
|
||||
}
|
||||
|
||||
pub fn corrupted_key(key: &[u8], value: Option<&[u8]>, caused_by: &'static str) -> Error {
|
||||
EventType::Store(StoreEvent::DataCorruption)
|
||||
.ctx(Key::Key, key)
|
||||
.ctx_opt(Key::Value, value)
|
||||
.ctx(Key::CausedBy, caused_by)
|
||||
}
|
||||
}
|
||||
|
||||
impl Event<EventDetails> {
|
||||
pub fn span_id(&self) -> Option<u64> {
|
||||
for (key, value) in &self.keys {
|
||||
match (key, value) {
|
||||
(Key::SpanId, Value::UInt(value)) => return Some(*value),
|
||||
(Key::SpanId, Value::Int(value)) => return Some(*value as u64),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl EventType {
|
||||
#[inline(always)]
|
||||
pub fn is_span_start(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
EventType::Smtp(SmtpEvent::ConnectionStart)
|
||||
| EventType::Imap(ImapEvent::ConnectionStart)
|
||||
| EventType::ManageSieve(ManageSieveEvent::ConnectionStart)
|
||||
| EventType::Pop3(Pop3Event::ConnectionStart)
|
||||
| EventType::Http(HttpEvent::ConnectionStart)
|
||||
| EventType::Delivery(DeliveryEvent::AttemptStart)
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_span_end(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
EventType::Smtp(SmtpEvent::ConnectionEnd)
|
||||
| EventType::Imap(ImapEvent::ConnectionEnd)
|
||||
| EventType::ManageSieve(ManageSieveEvent::ConnectionEnd)
|
||||
| EventType::Pop3(Pop3Event::ConnectionEnd)
|
||||
| EventType::Http(HttpEvent::ConnectionEnd)
|
||||
| EventType::Delivery(DeliveryEvent::AttemptEnd)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_raw_io(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
EventType::Imap(ImapEvent::RawInput | ImapEvent::RawOutput)
|
||||
| EventType::Smtp(SmtpEvent::RawInput | SmtpEvent::RawOutput)
|
||||
| EventType::Pop3(Pop3Event::RawInput | Pop3Event::RawOutput)
|
||||
| EventType::ManageSieve(ManageSieveEvent::RawInput | ManageSieveEvent::RawOutput)
|
||||
| EventType::Delivery(DeliveryEvent::RawInput | DeliveryEvent::RawOutput)
|
||||
| EventType::Milter(MilterEvent::Read | MilterEvent::Write)
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl StoreEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Store(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsEvent {
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Dns(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl AcmeEvent {
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Acme(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl DkimEvent {
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Dkim(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl SecurityEvent {
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Security(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl AuthEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Auth(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl JmapEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Jmap(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl LimitEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Limit(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Resource(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl SmtpEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Smtp(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl SieveEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Sieve(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl SpamEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Spam(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl ImapEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Imap(self))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn caused_by(self, error: impl Into<Value>) -> Error {
|
||||
self.into_err().caused_by(error)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn reason(self, error: impl Display) -> Error {
|
||||
self.into_err().reason(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl Pop3Event {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Pop3(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl ManageSieveEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::ManageSieve(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkEvent {
|
||||
#[inline(always)]
|
||||
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
|
||||
self.into_err().ctx(key, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_err(self) -> Error {
|
||||
Error::new(EventType::Network(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn from_maybe_string(value: &[u8]) -> Self {
|
||||
if let Ok(value) = std::str::from_utf8(value) {
|
||||
Self::String(value.into())
|
||||
} else {
|
||||
Self::Bytes(value.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_uint(&self) -> Option<u64> {
|
||||
match self {
|
||||
Self::UInt(value) => Some(*value),
|
||||
Self::Int(value) => Some(*value as u64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> Option<&str> {
|
||||
match self {
|
||||
Self::String(value) => Some(value.as_str()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_string(self) -> Option<CompactString> {
|
||||
match self {
|
||||
Self::String(value) => Some(value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddContext<T> for Result<T> {
|
||||
#[inline(always)]
|
||||
fn caused_by(self, location: &'static str) -> Result<T> {
|
||||
match self {
|
||||
Ok(value) => Ok(value),
|
||||
Err(mut err) => {
|
||||
err.set_ctx(Key::CausedBy, location);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn add_context<F>(self, f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(Error) -> Error,
|
||||
{
|
||||
match self {
|
||||
Ok(value) => Ok(value),
|
||||
Err(err) => Err(f(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
impl Eq for Error {}
|
||||
impl PartialEq for Error {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.0.inner == other.0.inner && self.0.keys.len() == other.0.keys.len() {
|
||||
for kv in self.0.keys.iter() {
|
||||
if !other.0.keys.iter().any(|okv| kv == okv) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Value {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::String(l0), Self::String(r0)) => l0 == r0,
|
||||
(Self::UInt(l0), Self::UInt(r0)) => l0 == r0,
|
||||
(Self::Int(l0), Self::Int(r0)) => l0 == r0,
|
||||
(Self::Float(l0), Self::Float(r0)) => l0 == r0,
|
||||
(Self::Bytes(l0), Self::Bytes(r0)) => l0 == r0,
|
||||
(Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
|
||||
(Self::Ipv4(l0), Self::Ipv4(r0)) => l0 == r0,
|
||||
(Self::Ipv6(l0), Self::Ipv6(r0)) => l0 == r0,
|
||||
(Self::Event(l0), Self::Event(r0)) => l0 == r0,
|
||||
(Self::Array(l0), Self::Array(r0)) => l0 == r0,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Value {}
|
||||
|
||||
impl From<EventType> for usize {
|
||||
fn from(value: EventType) -> Self {
|
||||
value.to_id() as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Event<EventDetails>> for Event<EventDetails> {
|
||||
fn as_ref(&self) -> &Event<EventDetails> {
|
||||
self
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user