nuts_tool_api/
msg.rs

1// MIT License
2//
3// Copyright (c) 2024 Robin Doer
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to
7// deal in the Software without restriction, including without limitation the
8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9// sell copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21// IN THE SOFTWARE.
22
23use nuts_backend::Backend;
24use serde::{Deserialize, Serialize};
25use std::collections::HashMap;
26use std::fmt;
27
28macro_rules! as_into_impls {
29    ($as_name:ident + $into_name:ident => $variant:ident) => {
30        pub fn $as_name(&self) -> Option<()> {
31            match self {
32                Self::$variant => Some(()),
33                _ => None,
34            }
35        }
36
37        pub fn $into_name(self) -> Option<()> {
38            match self {
39                Self::$variant => Some(()),
40                _ => None,
41            }
42        }
43    };
44
45    ($as_name:ident + $into_name:ident => $variant:ident ( $arg:ident : $type:ty )) => {
46        pub fn $as_name(&self) -> Option<&$type> {
47            match self {
48                Self::$variant($arg) => Some($arg),
49                _ => None,
50            }
51        }
52
53        pub fn $into_name(self) -> Option<$type> {
54            match self {
55                Self::$variant($arg) => Some($arg),
56                _ => None,
57            }
58        }
59    };
60
61    ($as_name:ident + $into_name:ident => $variant:ident ( $( $arg:ident : $type:ty ),+ )) => {
62        pub fn $as_name(&self) -> Option<( $( &$type ),+)> {
63            match self {
64                Self::$variant($( $arg ),+) => Some(($( $arg ),+)),
65                _ => None,
66            }
67        }
68
69        pub fn $into_name(self) -> Option<( $( $type ),+)> {
70            match self {
71                Self::$variant($( $arg ),+) => Some(($( $arg ),+)),
72                _ => None,
73            }
74        }
75    };
76}
77
78struct VecDebug<'a>(&'a Vec<u8>);
79
80#[cfg(feature = "debug-condensed")]
81impl<'a> fmt::Debug for VecDebug<'a> {
82    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
83        write!(fmt, "<{} bytes>", self.0.len())
84    }
85}
86
87#[cfg(not(feature = "debug-condensed"))]
88impl<'a> fmt::Debug for VecDebug<'a> {
89    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
90        fmt::Debug::fmt(self.0, fmt)
91    }
92}
93
94/// The request message.
95#[derive(Deserialize, Serialize)]
96#[serde(tag = "op", content = "args", rename_all = "kebab-case")]
97pub enum Request {
98    /// Ask for plugin information.
99    ///
100    /// * The response must be a [`OkResponse::Map`] variant.
101    PluginInfo,
102
103    /// Ask for settings.
104    ///
105    /// * The response must be a [`OkResponse::Bytes`] variant.
106    Settings,
107
108    /// Ask for the size of the id of the backend.
109    ///
110    /// * The response must be a [`OkResponse::Usize`] variant.
111    IdSize,
112
113    /// Ask for the block-size of the backend.
114    ///
115    /// * The response must be a [`OkResponse::U32`] variant.
116    BlockSize,
117
118    /// Ask to convert a string-representation of an id into bytes.
119    ///
120    /// * The argument contains the string representation.
121    /// * The response must be a [`OkResponse::Bytes`] variant.
122    IdToBytes(String),
123
124    /// Ask to convert the bytes representation of an id into a string.
125    ///
126    /// * The argument contains the byte data.
127    /// * The response must be a [`OkResponse::String`] variant.
128    IdToString(Vec<u8>),
129
130    /// Request to open a backend-instance.
131    ///
132    /// * The argument contains binary data of the settings of the backend.
133    /// * The response must be a [`OkResponse::Void`] variant.
134    Open(Vec<u8>),
135
136    /// Request to create a new backend-instance.
137    ///
138    /// * The first argument contains the binary data of the header.
139    /// * The second argument contains the overwrite flag.
140    /// * The response must be a [`OkResponse::Void`] variant.
141    Create(Vec<u8>, bool),
142
143    /// Ask for backend information.
144    ///
145    /// * The response must be a [`OkResponse::Map`] variant.
146    Info,
147
148    /// Request to aquire a new block in the backend.
149    ///
150    /// * The argument contains the initial data of the block.
151    /// * The response must be a [`OkResponse::Bytes`] variant.
152    Aquire(Vec<u8>),
153
154    /// Request to release a block in the backend.
155    ///
156    /// * The argument contains the binary data of the id to release.
157    /// * The response must be a [`OkResponse::Void`] variant.
158    Release(Vec<u8>),
159
160    /// Request to read the header data of the backend.
161    ///
162    /// * The response must be a [`OkResponse::Bytes`] variant.
163    ReadHeader,
164
165    /// Requerst to write the header of the backend.
166    ///
167    /// * The argument contains the header data to be written.
168    /// * The response must be a [`OkResponse::Void`] variant.
169    WriteHeader(Vec<u8>),
170
171    /// Request to read a block in the backend.
172    ///
173    /// * The argument contains the binary data of the id to read.
174    /// * The response must be a [`OkResponse::Bytes`] variant.
175    Read(Vec<u8>),
176
177    /// Request to write a block in the backend.
178    ///
179    /// * The first argument contains the binary data of the id to read.
180    /// * The second argument contains the data to be written.
181    /// * The response must be a [`OkResponse::Usize`] variant.
182    Write(Vec<u8>, Vec<u8>),
183
184    /// Asks to delete the backend.
185    ///
186    /// * The response must be a [`OkResponse::Void`] variant.
187    Delete,
188
189    /// Asks to quit the connection.
190    ///
191    /// * The response must be a [`OkResponse::Void`] variant.
192    Quit,
193}
194
195impl Request {
196    as_into_impls!(as_plugin_info + into_plugin_info => PluginInfo);
197    as_into_impls!(as_settings + into_settings => Settings);
198    as_into_impls!(as_id_size + into_id_size => IdSize);
199    as_into_impls!(as_block_size + into_block_size => BlockSize);
200    as_into_impls!(as_id_to_bytes + into_id_to_bytes => IdToBytes(arg1: String));
201    as_into_impls!(as_id_to_string + into_id_to_string => IdToString(arg1: Vec<u8>));
202    as_into_impls!(as_open + into_open => Open (arg1: Vec<u8>));
203    as_into_impls!(as_create + into_create => Create (arg1: Vec<u8>, args: bool));
204    as_into_impls!(as_info + into_info => Info);
205    as_into_impls!(as_aquire + into_aquire => Aquire (arg1: Vec<u8>));
206    as_into_impls!(as_release + into_release => Release (arg1: Vec<u8>));
207    as_into_impls!(as_read_header + into_read_header => ReadHeader);
208    as_into_impls!(as_write_header + into_write_header => WriteHeader (arg1: Vec<u8>));
209    as_into_impls!(as_read + into_read => Read (arg1: Vec<u8>));
210    as_into_impls!(as_write + into_write => Write (arg1: Vec<u8>, arg2: Vec<u8>));
211    as_into_impls!(as_delete + into_delete => Delete);
212    as_into_impls!(as_quit + into_quit => Quit);
213}
214
215impl fmt::Debug for Request {
216    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
217        match self {
218            Self::PluginInfo => write!(fmt, "PluginInfo"),
219            Self::Settings => write!(fmt, "Settings"),
220            Self::IdSize => write!(fmt, "IdSize"),
221            Self::BlockSize => write!(fmt, "BlockSize"),
222            Self::IdToBytes(arg) => fmt.debug_tuple("IdToBytes").field(arg).finish(),
223            Self::IdToString(arg) => fmt.debug_tuple("IdToString").field(&VecDebug(arg)).finish(),
224            Self::Open(arg) => fmt.debug_tuple("Open").field(&VecDebug(arg)).finish(),
225            Self::Create(arg1, arg2) => fmt
226                .debug_tuple("Create")
227                .field(&VecDebug(arg1))
228                .field(arg2)
229                .finish(),
230            Self::Info => write!(fmt, "Info"),
231            Self::Aquire(arg) => fmt.debug_tuple("Aquire").field(&VecDebug(arg)).finish(),
232            Self::Release(arg) => fmt.debug_tuple("Release").field(&VecDebug(arg)).finish(),
233            Self::ReadHeader => write!(fmt, "ReadHeader"),
234            Self::WriteHeader(arg) => fmt
235                .debug_tuple("WriteHeader")
236                .field(&VecDebug(arg))
237                .finish(),
238            Self::Read(arg) => fmt.debug_tuple("Read").field(&VecDebug(arg)).finish(),
239            Self::Write(arg1, arg2) => fmt
240                .debug_tuple("Write")
241                .field(&VecDebug(arg1))
242                .field(&VecDebug(arg2))
243                .finish(),
244            Self::Delete => write!(fmt, "Delete"),
245            Self::Quit => write!(fmt, "Quit"),
246        }
247    }
248}
249
250/// The response message.
251#[derive(Debug, Deserialize, Serialize)]
252#[serde(tag = "code", content = "args", rename_all = "kebab-case")]
253pub enum Response {
254    /// A successful response.
255    Ok(OkResponse),
256
257    /// An error response.
258    Err(ErrorResponse),
259}
260
261impl Response {
262    /// Creates a successful response with an attached [`OkResponse::Void`].
263    pub fn ok_void() -> Response {
264        Self::Ok(OkResponse::Void)
265    }
266
267    /// Creates a successful response with an attached [`OkResponse::U32`].
268    pub fn ok_u32(value: u32) -> Response {
269        Self::Ok(OkResponse::U32(value))
270    }
271
272    /// Creates a successful response with an attached [`OkResponse::Usize`].
273    pub fn ok_usize(value: usize) -> Response {
274        Self::Ok(OkResponse::Usize(value))
275    }
276
277    /// Creates a successful response with an attached [`OkResponse::Bytes`].
278    pub fn ok_bytes(value: Vec<u8>) -> Response {
279        Self::Ok(OkResponse::Bytes(value))
280    }
281
282    /// Creates a successful response with an attached [`OkResponse::String`].
283    pub fn ok_string(value: String) -> Response {
284        Self::Ok(OkResponse::String(value))
285    }
286
287    /// Creates a successful response with an attached [`OkResponse::Map`].
288    pub fn ok_map(value: HashMap<String, String>) -> Response {
289        Self::Ok(OkResponse::Map(value))
290    }
291
292    /// Creates an error response with an attached
293    /// [`ErrorResponse::NotApplicable`].
294    pub fn err_not_applicable() -> Response {
295        Self::Err(ErrorResponse::NotApplicable)
296    }
297
298    /// Creates an error response with an attached [`ErrorResponse::Message`].
299    pub fn err_message<M: AsRef<str>>(msg: M) -> Response {
300        Self::Err(ErrorResponse::Message(msg.as_ref().to_string()))
301    }
302
303    as_into_impls!(as_ok + into_ok => Ok (ok: OkResponse));
304    as_into_impls!(as_error + into_error => Err (err: ErrorResponse));
305}
306
307/// A successful response.
308///
309/// This is a container for various return types.
310#[derive(Deserialize, Serialize)]
311#[serde(tag = "type", content = "args", rename_all = "kebab-case")]
312pub enum OkResponse {
313    /// A successful response without an attached value.
314    Void,
315
316    /// A successful response with an attached [`u32`].
317    U32(u32),
318
319    /// A successful response with an attached [`usize`].
320    Usize(usize),
321
322    /// A successful response with an attached [`Vec<u8>`].
323    Bytes(Vec<u8>),
324
325    /// A successful response with an attached [`String`].
326    String(String),
327
328    /// A successful response with an attached [`HashMap`].
329    Map(HashMap<String, String>),
330}
331
332impl fmt::Debug for OkResponse {
333    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
334        match self {
335            Self::Void => write!(fmt, "Void"),
336            Self::U32(arg) => fmt.debug_tuple("U32").field(arg).finish(),
337            Self::Usize(arg) => fmt.debug_tuple("Usize").field(arg).finish(),
338            Self::Bytes(arg) => fmt.debug_tuple("Bytes").field(&VecDebug(arg)).finish(),
339            Self::String(arg) => fmt.debug_tuple("String").field(arg).finish(),
340            Self::Map(arg) => fmt.debug_tuple("Map").field(arg).finish(),
341        }
342    }
343}
344
345/// An error response.
346#[derive(Debug, Deserialize, Serialize)]
347#[serde(tag = "code", content = "args", rename_all = "kebab-case")]
348pub enum ErrorResponse {
349    /// The call is not applicable in the current backend state.
350    ///
351    /// I.e. you need an open backend instance for a request call but the
352    /// backend was not opened yet.
353    NotApplicable,
354
355    /// Could not convert an id into its binary representation.
356    InvalidId,
357
358    /// Could not create an id from its binary representation.
359    InvalidIdData,
360
361    /// Could not create the settings from its binary representation.
362    InvalidSettingsData,
363
364    /// Could not convert backend information into a hash representation.
365    InvalidInfo,
366
367    /// The header data has an invalid length.
368    InvalidHeaderBytes,
369
370    /// The attached backend raised an error.
371    Backend(String),
372
373    /// An arbitrary error with the given message occured.
374    Message(String),
375}
376
377impl ErrorResponse {
378    pub fn message<T: AsRef<str>>(msg: T) -> ErrorResponse {
379        Self::Message(msg.as_ref().to_string())
380    }
381
382    pub fn backend<B: Backend>(err: B::Err) -> ErrorResponse {
383        Self::Backend(err.to_string())
384    }
385}
386
387impl fmt::Display for ErrorResponse {
388    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
389        match self {
390            Self::NotApplicable => write!(fmt, "the call is not applicable"),
391            Self::InvalidId => write!(fmt, "could not parse id"),
392            Self::InvalidIdData => write!(fmt, "could not create id"),
393            Self::InvalidSettingsData => write!(fmt, "could not create settings"),
394            Self::InvalidInfo => write!(fmt, "could not collect backend information"),
395            Self::InvalidHeaderBytes => write!(fmt, "invalid header bytes"),
396            Self::Backend(msg) => write!(fmt, "the backend created an error: {}", msg),
397            Self::Message(msg) => write!(fmt, "{}", msg),
398        }
399    }
400}