meta_secret_core/sdk/
api.rs

1use serde::{Deserialize, Serialize};
2
3use crate::models::{
4    MembershipStatus, MetaPasswordsData, PasswordRecoveryRequest, RegistrationStatus,
5    SecretDistributionDocData, VaultInfoData, VaultInfoStatus, FindSharesResult
6};
7
8#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
9#[serde(rename_all = "camelCase")]
10pub enum MessageType {
11    Ok,
12    Err,
13}
14
15#[derive(Debug, Serialize, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct GenericMessage<T> {
18    pub msg_type: MessageType,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub data: Option<T>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub err: Option<ErrorMessage>,
23}
24
25#[derive(Debug, Serialize, Deserialize)]
26#[serde(rename_all = "camelCase")]
27pub struct ErrorMessage {
28    stacktrace: Vec<String>,
29}
30
31impl From<&anyhow::Error> for ErrorMessage {
32    fn from(err: &anyhow::Error) -> Self {
33        let mut stacktrace = vec![];
34        for cause in err.chain() {
35            stacktrace.push(cause.to_string().trim().to_string());
36        }
37
38        Self { stacktrace }
39    }
40}
41
42impl From<&dyn std::error::Error> for ErrorMessage {
43    fn from(err: &dyn std::error::Error) -> Self {
44        let mut stacktrace = vec![];
45
46        let mut current_error = err;
47        while let Some(source) = current_error.source() {
48            let err_msg = format!("{}", current_error);
49            stacktrace.push(err_msg);
50
51            current_error = source;
52        }
53
54        Self { stacktrace }
55    }
56}
57
58impl<T> GenericMessage<T> {
59    pub fn just_ok() -> Self {
60        GenericMessage {
61            msg_type: MessageType::Ok,
62            data: None,
63            err: None,
64        }
65    }
66
67    pub fn data(data: T) -> Self {
68        GenericMessage {
69            msg_type: MessageType::Ok,
70            data: Some(data),
71            err: None,
72        }
73    }
74
75    pub fn err(err: anyhow::Error) -> Self {
76        let err_msg = ErrorMessage::from(&err);
77
78        GenericMessage {
79            msg_type: MessageType::Err,
80            data: None,
81            err: Some(err_msg),
82        }
83    }
84
85    pub fn std_err(err: &dyn std::error::Error) -> Self {
86        let err_msg = ErrorMessage::from(err);
87
88        GenericMessage {
89            msg_type: MessageType::Err,
90            data: None,
91            err: Some(err_msg),
92        }
93    }
94}
95
96pub type SecretDistributionDocResponse = GenericMessage<SecretDistributionDocData>;
97
98pub type RegistrationResponse = GenericMessage<RegistrationStatus>;
99
100pub type VaultInfoResponse = GenericMessage<VaultInfoData>;
101
102
103impl VaultInfoData {
104    pub fn pending() -> Self {
105        Self::empty(VaultInfoStatus::Pending)
106    }
107
108    pub fn declined() -> Self {
109        Self::empty(VaultInfoStatus::Declined)
110    }
111
112    pub fn unknown() -> Self {
113        Self::empty(VaultInfoStatus::Unknown)
114    }
115
116    pub fn empty(vault_info: VaultInfoStatus) -> Self {
117        Self {
118            vault_info: Some(vault_info),
119            vault: None,
120        }
121    }
122}
123
124pub type MetaPasswordsResponse = GenericMessage<MetaPasswordsData>;
125
126pub type PasswordRecoveryClaimsResponse = GenericMessage<Vec<PasswordRecoveryRequest>>;
127
128pub type UserSharesResponse = GenericMessage<FindSharesResult>;
129
130pub mod basic {
131    use serde::{Deserialize, Serialize};
132
133    #[derive(Debug, Serialize, Deserialize)]
134    #[serde(rename_all = "camelCase")]
135    pub struct MongoDbStats {
136        pub connection: bool,
137        pub registrations: usize,
138    }
139
140    #[derive(Debug, Serialize, Deserialize)]
141    #[serde(rename_all = "camelCase")]
142    pub struct HttpStatusDetails {
143        pub http_status: String,
144        pub http_status_code: u16,
145        pub uri: String,
146        pub method: String,
147        #[serde(skip_serializing_if = "Option::is_none")]
148        pub content_type: Option<String>,
149    }
150}
151
152pub type MembershipResponse = GenericMessage<MembershipStatus>;
153
154#[cfg(test)]
155mod test {
156    use anyhow::anyhow;
157    use serde::{Deserialize, Serialize};
158    use serde_json::error::Result;
159    use thiserror::__private::AsDynError;
160    use crate::models::MembershipStatus;
161
162    use crate::sdk::api::{ErrorMessage, GenericMessage, MembershipResponse};
163
164    #[test]
165    fn test_generic_message() -> Result<()> {
166        let msg: GenericMessage<String> = GenericMessage::just_ok();
167        let msg = serde_json::to_string(&msg)?;
168        assert_eq!(r#"{"msgType":"ok"}"#.to_string(), msg);
169
170        let msg = MembershipResponse::data(MembershipStatus::AlreadyMember);
171        let msg = serde_json::to_string(&msg)?;
172        assert_eq!(r#"{"msgType":"ok","data":"AlreadyMember"}"#, msg);
173
174        #[derive(Debug, Serialize, Deserialize)]
175        #[serde(rename_all = "camelCase")]
176        struct TestTest {
177            pub xxx: String,
178        }
179
180        let msg = GenericMessage::data(TestTest { xxx: "yay".to_string() });
181        let msg = serde_json::to_string(&msg)?;
182        assert_eq!(r#"{"msgType":"ok","data":{"xxx":"yay"}}"#, msg);
183
184        Ok(())
185    }
186
187    #[test]
188    fn error_message_test() -> Result<()> {
189        let err_msg = ErrorMessage::from(anyhow!("yay").context("my root cause").as_dyn_error());
190        assert_eq!(r#"{"stacktrace":["my root cause"]}"#, serde_json::to_string(&err_msg)?);
191
192        Ok(())
193    }
194}