diff options
author | 2025-04-01 21:13:25 +0100 | |
---|---|---|
committer | 2025-04-01 21:13:25 +0100 | |
commit | 448208337c3a404403e6b312dbe38555a2bf8ad5 (patch) | |
tree | 8a9ec3bd1948848897a0740d20ddaf040f3b4f90 | |
parent | f7b88569987026bcfec6132ca97b1d8122f44edd (diff) | |
download | luz-448208337c3a404403e6b312dbe38555a2bf8ad5.tar.gz luz-448208337c3a404403e6b312dbe38555a2bf8ad5.tar.bz2 luz-448208337c3a404403e6b312dbe38555a2bf8ad5.zip |
fix(stanza): stanza errors pubsub error variant
-rw-r--r-- | stanza/src/client/error.rs | 32 | ||||
-rw-r--r-- | stanza/src/xep_0060/errors.rs | 62 |
2 files changed, 86 insertions, 8 deletions
diff --git a/stanza/src/client/error.rs b/stanza/src/client/error.rs index 33bc85e..c4ab517 100644 --- a/stanza/src/client/error.rs +++ b/stanza/src/client/error.rs @@ -14,14 +14,18 @@ use super::XMLNS; pub struct Error { by: Option<String>, r#type: ErrorType, - // children (sequence) - error: StanzaError, + // TODO: children (sequence) + errors: Vec<StanzaError>, text: Option<Text>, } impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}, {}", self.r#type, self.error)?; + write!(f, "{},", self.r#type)?; + + for error in &self.errors { + write!(f, "{}: ", error)?; + } if let Some(text) = &self.text { if let Some(text) = &text.text { @@ -42,13 +46,13 @@ impl FromElement for Error { let by = element.attribute_opt("by")?; let r#type = element.attribute("type")?; - let error = element.pop_child_one()?; - let text = element.pop_child_opt()?; + let errors = element.children()?; + let text = element.child_opt()?; Ok(Error { by, r#type, - error, + errors, text, }) } @@ -59,7 +63,7 @@ impl IntoElement for Error { Element::builder("error", Some(XMLNS)) .push_attribute_opt("by", self.by.clone()) .push_attribute("type", self.r#type) - .push_child(self.error.clone()) + .push_children(self.errors.clone()) .push_child_opt(self.text.clone()) } } @@ -128,12 +132,24 @@ impl From<StanzaError> for Error { StanzaError::UndefinedCondition => ErrorType::Cancel, // wait or modify StanzaError::UnexpectedRequest => ErrorType::Modify, + #[cfg(feature = "xep_0060")] + StanzaError::PubSub(ref error) => error.r#type(), }; Self { by: None, r#type: error_type, - error: value, + errors: value.into(), text: None, } } } + +impl From<StanzaError> for Vec<StanzaError> { + fn from(value: StanzaError) -> Self { + match value { + #[cfg(feature = "xep_0060")] + StanzaError::PubSub(error) => error.stanza_errors(), + _ => vec![value], + } + } +} diff --git a/stanza/src/xep_0060/errors.rs b/stanza/src/xep_0060/errors.rs index 10d1483..e6817ac 100644 --- a/stanza/src/xep_0060/errors.rs +++ b/stanza/src/xep_0060/errors.rs @@ -6,6 +6,8 @@ use peanuts::{ }; use thiserror::Error; +use crate::{client::error::ErrorType, stanza_error::Error as StanzaError}; + pub const XMLNS: &str = "http://jabber.org/protocol/pubsub#errors"; #[derive(Error, Clone, Debug)] @@ -58,6 +60,66 @@ pub enum Error { UnsupportedAccessModel, } +impl Error { + pub fn r#type(&self) -> ErrorType { + match self { + Error::ClosedNode => ErrorType::Cancel, + Error::ConfigurationRequired => ErrorType::Modify, + Error::InvalidJID => ErrorType::Modify, + Error::InvalidOptions => ErrorType::Modify, + Error::InvalidPayload => ErrorType::Modify, + Error::InvalidSubID => ErrorType::Modify, + Error::ItemForbidden => ErrorType::Modify, + Error::ItemRequired => ErrorType::Modify, + Error::JIDRequired => ErrorType::Modify, + Error::MaxItemsExceeded => ErrorType::Cancel, + Error::MaxNodesExceeded => ErrorType::Cancel, + Error::NodeIDRequired => ErrorType::Modify, + Error::NotInRosterGroup => ErrorType::Auth, + Error::NotSubscribed => ErrorType::Cancel, + Error::PayloadTooBig => ErrorType::Modify, + Error::PayloadRequired => ErrorType::Modify, + Error::PendingSubscription => ErrorType::Auth, + Error::PreconditionNotMet => ErrorType::Cancel, + Error::PresenceSubscriptionRequired => ErrorType::Auth, + Error::SubIDRequired => ErrorType::Modify, + Error::TooManySubscriptions => ErrorType::Wait, + Error::Unsupported(_feature) => ErrorType::Cancel, + Error::UnsupportedAccessModel => ErrorType::Modify, + } + } + + pub fn stanza_errors(self) -> Vec<StanzaError> { + match self { + Error::ClosedNode => vec![StanzaError::NotAllowed, self.into()], + Error::ConfigurationRequired => vec![StanzaError::NotAcceptable, self.into()], + Error::InvalidJID => vec![StanzaError::BadRequest, self.into()], + Error::InvalidOptions => vec![StanzaError::BadRequest, self.into()], + Error::InvalidPayload => vec![StanzaError::BadRequest, self.into()], + Error::InvalidSubID => vec![StanzaError::NotAcceptable, self.into()], + Error::ItemForbidden => vec![StanzaError::BadRequest, self.into()], + Error::ItemRequired => vec![StanzaError::BadRequest, self.into()], + Error::JIDRequired => vec![StanzaError::BadRequest, self.into()], + Error::MaxItemsExceeded => vec![StanzaError::NotAllowed, self.into()], + Error::MaxNodesExceeded => vec![StanzaError::NotAllowed, self.into()], + Error::NodeIDRequired => vec![StanzaError::BadRequest, self.into()], + Error::NotInRosterGroup => vec![StanzaError::NotAuthorized, self.into()], + Error::NotSubscribed => vec![StanzaError::UnexpectedRequest, self.into()], + Error::PayloadTooBig => vec![StanzaError::NotAcceptable, self.into()], + Error::PayloadRequired => vec![StanzaError::BadRequest, self.into()], + Error::PendingSubscription => vec![StanzaError::NotAuthorized, self.into()], + Error::PreconditionNotMet => vec![StanzaError::Conflict, self.into()], + Error::PresenceSubscriptionRequired => vec![StanzaError::NotAuthorized, self.into()], + Error::SubIDRequired => vec![StanzaError::BadRequest, self.into()], + Error::TooManySubscriptions => vec![StanzaError::PolicyViolation, self.into()], + Error::Unsupported(ref _feature) => { + vec![StanzaError::FeatureNotImplemented, self.into()] + } + Error::UnsupportedAccessModel => vec![StanzaError::NotAcceptable, self.into()], + } + } +} + impl FromElement for Error { fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { match element.identify() { |