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
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::util::cfg_wasm;

#[repr(u32)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub enum ErrorCode {
    // Use none-zero value to avoid uninitialized memory or bad input being treated as proper
    // value
    UNKNOWN             = u32::MAX,

    InvalidEventId      = 1,
    UnsupportedWallet   = 2,
    InvalidJWTToken     = 3,
    UnsupportedJWTLogin = 4,
    InvalidPubkey       = 5,
    UnsupportedPubkeyLogin = 6,
}

#[derive(Debug, Error)]
pub enum Error {
    #[error("Serde JSON error: {0}")]
    SerdeJson(#[from] serde_json::Error),

    #[error("Invalid message type: expect {expect}, got {got}")]
    InvalidMessageType { expect: &'static str, got: String },
}
pub type Result<T> = std::result::Result<T, Error>;

#[derive(Serialize, Deserialize, Clone, Debug, Error)]
pub struct ErrorType {
    pub error_code: ErrorCode,
    pub error_message: Vec<String>,
}

cfg_wasm! {
    impl From<ErrorType> for wasm_bindgen::JsValue {
        fn from(val: ErrorType) -> Self {
            serde_wasm_bindgen::to_value(&val).unwrap()
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ErrorMessageDisplayWrapper<'a, T: 'a>(pub &'a [T]);

impl<'a, T: std::fmt::Display> std::fmt::Display for ErrorMessageDisplayWrapper<'a, T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self.0.len() {
            0 => {}
            1 => write!(f, ": {}", self.0[0])?,
            _ => {
                let mut first = true;
                write!(f, ": [")?;

                for item in self.0 {
                    if first {
                        first = false;
                    } else {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", item)?;
                }
                write!(f, "]")?;
            }
        }
        Ok(())
    }
}

impl std::fmt::Display for ErrorType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{:?}(error code {}){}",
            self.error_code,
            self.error_code as u32,
            ErrorMessageDisplayWrapper(&self.error_message)
        )
    }
}

#[test]
fn test_error_code() {
    let err = ErrorType {
        error_code: ErrorCode::InvalidEventId,
        error_message: vec!["test".to_string(), "oops".to_string()],
    };

    assert_eq!(
        err.to_string(),
        "InvalidEventId(error code 1): [test, oops]"
    );

    let err = ErrorType {
        error_code: ErrorCode::InvalidEventId,
        error_message: vec!["test".to_string()],
    };

    assert_eq!(err.to_string(), "InvalidEventId(error code 1): test");

    let err = ErrorType {
        error_code: ErrorCode::InvalidEventId,
        error_message: vec![],
    };

    assert_eq!(err.to_string(), "InvalidEventId(error code 1)");
}