1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::messages::Dict;
use crate::messages::WampError;
use crate::ErrorKind;
use actix::MailboxError;
use failure::Fail;
use std::borrow::Cow;
use std::error;

#[derive(Debug, Fail)]
pub enum Error {
    #[fail(display = "{}", _0)]
    WampError(WampError),

    #[fail(display = "protocol error: {}", _0)]
    ProtocolError(Cow<'static, str>),

    #[fail(display = "mailbox")]
    MailboxError(MailboxError),

    #[fail(display = "connection closed")]
    ConnectionClosed,

    /// Throwed by connection actor in cases when you request action in wrong momment.
    ///
    /// For example:
    ///
    /// * RPC call before WAMP session is opened
    /// * Opening session when she is already opened.
    ///
    #[fail(display = "{}", _0)]
    InvalidState(&'static str),

    #[fail(display = "{}: {}", context, cause)]
    ProcessingError {
        context: Cow<'static, str>,
        cause: Box<dyn error::Error + 'static + Sync + Send>,
    },

    #[fail(display = "{}", _0)]
    WsClientError(String),
}

impl Error {
    #[inline]
    pub fn protocol_err(msg: &'static str) -> Error {
        Error::ProtocolError(Cow::Borrowed(msg))
    }

    pub fn wamp_error(code: ErrorKind, message: String) -> Self {
        let extra = Dict::new();

        Error::WampError(WampError {
            code,
            message,
            extra,
        })
    }

    pub fn from_abort(uri: &str, extra: &Vec<(rmpv::Value, rmpv::Value)>) -> Self {
        let code = ErrorKind::from_uri(uri);
        let extra: Dict = extra
            .into_iter()
            .filter_map(|(k, v)| {
                let key = match k {
                    rmpv::Value::String(key) => key.clone().into_str()?,
                    _ => return None,
                };
                let value = serde_json::to_value(v).ok()?;

                Some((key, value))
            })
            .collect();
        let message = extra
            .get("message")
            .and_then(|v| v.as_str())
            .unwrap_or_else(|| code.uri())
            .to_string();

        Error::WampError(WampError {
            code,
            message,
            extra,
        })
    }

    pub fn from_wamp_error_message(uri: &str, args: &rmpv::Value, kwargs: &rmpv::Value) -> Self {
        let code = ErrorKind::from_uri(uri);
        let extra: Dict = kwargs
            .as_map()
            .map(|v| {
                v.into_iter()
                    .filter_map(|(k, v)| {
                        let key = match k {
                            rmpv::Value::String(key) => key.clone().into_str()?,
                            _ => return None,
                        };
                        let value = serde_json::to_value(v).ok()?;

                        Some((key, value))
                    })
                    .collect()
            })
            .unwrap_or_else(|| Dict::new());
        let message = extra
            .get("message")
            .and_then(|v| v.as_str())
            .or_else(|| args[0].as_str())
            .unwrap_or_else(|| code.uri())
            .to_string();

        Error::WampError(WampError {
            code,
            message,
            extra,
        })
    }
}

impl<E: error::Error + 'static + Sync + Send> From<E> for Error {
    fn from(err: E) -> Self {
        Error::ProcessingError {
            context: Cow::Borrowed(""),
            cause: Box::new(err),
        }
    }
}