nuts_tool_api/plugin/
handler.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 clap::Args;
24use log::debug;
25use nuts_backend::{Backend, Binary, Create, IdSize, Open, ReceiveHeader, HEADER_MAX_SIZE};
26use std::collections::HashMap;
27use std::convert::TryInto;
28use std::marker::PhantomData;
29use std::str::FromStr;
30use std::{cmp, io};
31
32use crate::bson::{BsonError, BsonReader, BsonWriter};
33use crate::msg::{ErrorResponse, Request, Response};
34use crate::plugin::cli::{CreateArgs, Format, InfoArgs, OpenArgs, PluginCommand};
35use crate::PluginInfo;
36
37fn into_header_bytes(bytes: &[u8]) -> Result<[u8; HEADER_MAX_SIZE], ErrorResponse> {
38    match bytes.try_into() {
39        Ok(header) => Ok(header),
40        Err(_err) => Err(ErrorResponse::InvalidHeaderBytes),
41    }
42}
43
44/// Trait enriches the generic implementation of the plugin with
45/// plugin-specific behavior.
46///
47/// You need to implement a set of functions that provide plugin-specific
48/// information.
49///
50/// There are several `handle_*` functions, which are already implemented. They
51/// encapsulates the handling for all the [request types](Request).
52pub trait PluginHandler<B: Backend> {
53    /// Extra (plugin-specific) arguments passed to the `create` command.
54    type CreateArgs: Args;
55
56    /// The create builder for the attached backend.
57    type Create: Create<B>;
58
59    /// The open builder for the attached backend.
60    type Open: Open<B>;
61
62    /// Returns information of the plugin.
63    fn plugin_info(&self) -> PluginInfo;
64
65    /// Converts the given [`info`](Backend::Info) into a [`HashMap`].
66    ///
67    /// The hash is send back to the *nuts-tool* and displayed to the user. So
68    /// you are advised to choose good, human readable keys.
69    ///
70    /// On success the info-hash wrapped into a [`Some`] value is returned. If
71    /// you cannot create the hash [`None`] is returned.
72    fn info_to_hash(&self, info: B::Info) -> Option<HashMap<String, String>>;
73
74    /// Creates a builder instance used to open an already existing backend
75    /// instance.
76    fn open_builder(&self, args: &OpenArgs) -> Option<Self::Open>;
77
78    /// Creates a builder instance used to create a new backend instance.
79    fn create_builder(&self, args: &CreateArgs<Self::CreateArgs>) -> Option<Self::Create>;
80
81    /// Handles the [`Request::PluginInfo`] command.
82    fn handle_plugin_info(&self) -> Result<HashMap<String, String>, ErrorResponse> {
83        let info = self.plugin_info();
84
85        Ok([
86            ("name".to_string(), info.name().to_string()),
87            ("version".to_string(), info.version().to_string()),
88            ("revision".to_string(), info.revision().to_string()),
89        ]
90        .into())
91    }
92
93    /// Handles the [`Request::Settings`] command.
94    fn handle_settings(
95        &self,
96        args: &CreateArgs<Self::CreateArgs>,
97    ) -> Result<Vec<u8>, ErrorResponse> {
98        match self.create_builder(args) {
99            Some(builder) => {
100                let settings = builder.settings();
101
102                Ok(<B::Settings as Binary>::as_bytes(&settings))
103            }
104            None => Err(ErrorResponse::message("unable to make a create-builder")),
105        }
106    }
107
108    /// Handles the [`Request::Open`] command.
109    fn handle_open(&self, args: &OpenArgs, settings: &[u8]) -> Result<B, ErrorResponse> {
110        let settings = <B::Settings as Binary>::from_bytes(settings)
111            .ok_or(ErrorResponse::InvalidSettingsData)?;
112
113        match self.open_builder(args) {
114            Some(builder) => builder
115                .build(settings)
116                .map_err(|err| ErrorResponse::backend::<B>(err)),
117            None => Err(ErrorResponse::message("unable to make an open-builder")),
118        }
119    }
120
121    /// Handles the [`Request::Create`] command.
122    fn handle_create(
123        &self,
124        args: &CreateArgs<Self::CreateArgs>,
125        header: &[u8],
126        overwrite: bool,
127    ) -> Result<B, ErrorResponse> {
128        let header = into_header_bytes(header)?;
129
130        match self.create_builder(args) {
131            Some(builder) => builder
132                .build(header, overwrite)
133                .map_err(|err| ErrorResponse::backend::<B>(err)),
134            None => Err(ErrorResponse::message("unable to make a create-builder")),
135        }
136    }
137
138    /// Handles the [`Request::IdSize`] command.
139    fn handle_id_size(&self) -> Result<usize, ErrorResponse> {
140        Ok(<B::Id as IdSize>::size())
141    }
142
143    /// Handles the [`Request::BlockSize`] command.
144    fn handle_block_size(&self, backend: &B) -> Result<u32, ErrorResponse> {
145        Ok(B::block_size(backend))
146    }
147
148    /// Handles the [`Request::IdToBytes`] command.
149    fn handle_id_to_bytes(&self, str: &str) -> Result<Vec<u8>, ErrorResponse> {
150        let id = <B::Id as FromStr>::from_str(str).map_err(|_| ErrorResponse::InvalidId)?;
151
152        Ok(<B::Id as Binary>::as_bytes(&id))
153    }
154
155    /// Handles the [`Request::IdToString`] command.
156    fn handle_id_to_string(&self, bytes: &[u8]) -> Result<String, ErrorResponse> {
157        let id = <B::Id as Binary>::from_bytes(bytes).ok_or(ErrorResponse::InvalidIdData)?;
158
159        Ok(id.to_string())
160    }
161
162    /// Handles the [`Request::Info`] command.
163    fn handle_info(&self, backend: &B) -> Result<HashMap<String, String>, ErrorResponse> {
164        match backend.info() {
165            Ok(info) => Ok(self.info_to_hash(info).ok_or(ErrorResponse::InvalidInfo)?),
166            Err(err) => Err(ErrorResponse::backend::<B>(err)),
167        }
168    }
169
170    /// Handles the [`Request::Aquire`] command.
171    fn handle_aquire(&self, backend: &mut B, bytes: &[u8]) -> Result<Vec<u8>, ErrorResponse> {
172        match B::aquire(backend, bytes) {
173            Ok(id) => Ok(<B::Id as Binary>::as_bytes(&id)),
174            Err(err) => Err(ErrorResponse::backend::<B>(err)),
175        }
176    }
177
178    /// Handles the [`Request::Release`] command.
179    fn handle_release(&self, backend: &mut B, id: &[u8]) -> Result<(), ErrorResponse> {
180        let id = <B::Id as Binary>::from_bytes(id).ok_or(ErrorResponse::InvalidIdData)?;
181
182        B::release(backend, id).map_err(|err| ErrorResponse::backend::<B>(err))
183    }
184
185    /// Handles the [`Request::ReadHeader`] command.
186    fn handle_read_header<T: ReceiveHeader<B>>(
187        &self,
188        header: &mut T,
189    ) -> Result<Vec<u8>, ErrorResponse> {
190        let mut bytes = [0; HEADER_MAX_SIZE];
191
192        match header.get_header_bytes(&mut bytes) {
193            Ok(()) => Ok(bytes.to_vec()),
194            Err(err) => Err(ErrorResponse::backend::<B>(err)),
195        }
196    }
197
198    /// Handles the [`Request::WriteHeader`] command.
199    fn handle_write_header(&self, backend: &mut B, header: &[u8]) -> Result<(), ErrorResponse> {
200        let header = into_header_bytes(header)?;
201
202        B::write_header(backend, &header).map_err(|err| ErrorResponse::backend::<B>(err))
203    }
204
205    /// Handles the [`Request::Read`] command.
206    fn handle_read(&self, backend: &mut B, id: &[u8]) -> Result<Vec<u8>, ErrorResponse> {
207        let id = <B::Id as Binary>::from_bytes(id).ok_or(ErrorResponse::InvalidIdData)?;
208        let bsize = B::block_size(backend) as usize;
209        let mut buf = vec![0; bsize];
210
211        let nread =
212            B::read(backend, &id, &mut buf).map_err(|err| ErrorResponse::backend::<B>(err))?;
213
214        Ok(buf[..nread].to_vec())
215    }
216
217    /// Handles the [`Request::Write`] command.
218    fn handle_write(
219        &self,
220        backend: &mut B,
221        id: &[u8],
222        bytes: &[u8],
223    ) -> Result<usize, ErrorResponse> {
224        let id = <B::Id as Binary>::from_bytes(id).ok_or(ErrorResponse::InvalidIdData)?;
225
226        let bsize = B::block_size(backend) as usize;
227        let nbytes = cmp::min(bytes.len(), bsize);
228        let bytes = &bytes[..nbytes];
229
230        B::write(backend, &id, bytes).map_err(|err| ErrorResponse::backend::<B>(err))
231    }
232
233    fn handle_delete(&self, backend: B) -> Result<(), ErrorResponse> {
234        B::delete(backend);
235        Ok(())
236    }
237
238    fn handle_quit(&self) -> Result<(), ErrorResponse> {
239        Ok(())
240    }
241}
242
243/// Handler for the `info` command.
244pub struct InfoHandler<B, T> {
245    handler: T,
246    _data: PhantomData<B>,
247}
248
249impl<B: Backend, T: PluginHandler<B>> InfoHandler<B, T> {
250    /// Creates a new `InfoHandler` and attaches the given [`PluginHandler`] to
251    /// the instance.
252    pub fn new(handler: T) -> InfoHandler<B, T> {
253        InfoHandler {
254            handler,
255            _data: PhantomData,
256        }
257    }
258
259    /// Runs the handler.
260    ///
261    /// The `args` arguments contains arguments passed to the command line.
262    pub fn run(&self, args: &InfoArgs) -> Result<(), BsonError> {
263        let info = self.handler.plugin_info();
264
265        match args.format {
266            Format::Text => {
267                println!("name:     {}", info.name());
268                println!("version:  {}", info.version());
269                println!("revision: {}", info.revision());
270            }
271            Format::Bson => {
272                BsonWriter::new(io::stdout()).write(info)?;
273            }
274        };
275
276        Ok(())
277    }
278}
279
280/// Handler for the `open` and `create` commands.
281pub struct OpenCreateHandler<'a, B: Backend, T: PluginHandler<B>> {
282    command: &'a PluginCommand<T::CreateArgs>,
283    handler: T,
284    backend: Option<B>,
285}
286
287impl<'a, B: Backend, T: PluginHandler<B>> OpenCreateHandler<'a, B, T> {
288    /// Creates a new `OpenCreateHandler` and attaches the given
289    /// [`PluginHandler`] to the instance. `command` is the command, which is
290    /// executed on the command line. It can be eiter `open` or `create`.
291    pub fn new(
292        command: &'a PluginCommand<T::CreateArgs>,
293        handler: T,
294    ) -> OpenCreateHandler<'a, B, T> {
295        OpenCreateHandler {
296            command,
297            handler,
298            backend: None,
299        }
300    }
301
302    /// Runs the handler.
303    pub fn run(&mut self) -> Result<(), BsonError> {
304        let mut reader = BsonReader::new(io::stdin());
305        let mut writer = BsonWriter::new(io::stdout());
306
307        let mut leave_loop = false;
308
309        while !leave_loop {
310            match reader.read::<Request>() {
311                Ok(Some(request)) => {
312                    debug!("request: {:?}", request);
313
314                    let response = match request {
315                        Request::PluginInfo => self.on_plugin_info(),
316                        Request::Settings => self.on_settings(),
317                        Request::Open(ref settings) => self.on_open(settings),
318                        Request::Create(ref header, overwrite) => self.on_create(header, overwrite),
319                        Request::IdSize => self.on_id_size(),
320                        Request::BlockSize => self.on_block_size(),
321                        Request::IdToBytes(ref str) => self.on_id_to_bytes(str),
322                        Request::IdToString(ref bytes) => self.on_id_to_string(bytes),
323                        Request::Info => self.on_info(),
324                        Request::Aquire(ref bytes) => self.on_aquire(bytes),
325                        Request::Release(ref id) => self.on_release(id),
326                        Request::ReadHeader => self.on_read_header(),
327                        Request::WriteHeader(ref header) => self.on_write_header(header),
328                        Request::Read(ref id) => self.on_read(id),
329                        Request::Write(ref id, ref bytes) => self.on_write(id, bytes),
330                        Request::Delete => self.on_delete(),
331                        Request::Quit => self.on_quit(),
332                    };
333
334                    leave_loop = request.as_quit().is_some() || response.as_error().is_some();
335                    debug!("response: {:?}, leave: {}", response, leave_loop);
336
337                    writer.write(response)?;
338                }
339                Ok(None) => {
340                    leave_loop = true;
341                }
342                Err(err) => return Err(err),
343            }
344        }
345
346        Ok(())
347    }
348
349    fn on_plugin_info(&mut self) -> Response {
350        match self.handler.handle_plugin_info() {
351            Ok(info) => Response::ok_map(info),
352            Err(err) => Response::Err(err),
353        }
354    }
355
356    fn on_settings(&mut self) -> Response {
357        if let Some(args) = self.command.as_create() {
358            match self.handler.handle_settings(args) {
359                Ok(settings) => Response::ok_bytes(settings),
360                Err(err) => Response::Err(err),
361            }
362        } else {
363            Response::err_not_applicable()
364        }
365    }
366
367    fn on_open(&mut self, settings: &[u8]) -> Response {
368        if let Some(args) = self.command.as_open() {
369            match self.handler.handle_open(args, settings) {
370                Ok(backend) => {
371                    self.backend = Some(backend);
372                    Response::ok_void()
373                }
374                Err(err) => Response::Err(err),
375            }
376        } else {
377            Response::err_not_applicable()
378        }
379    }
380
381    fn on_create(&mut self, header: &[u8], overwrite: bool) -> Response {
382        if let Some(args) = self.command.as_create() {
383            match self.handler.handle_create(args, header, overwrite) {
384                Ok(backend) => {
385                    self.backend = Some(backend);
386                    Response::ok_void()
387                }
388                Err(err) => Response::Err(err),
389            }
390        } else {
391            Response::err_not_applicable()
392        }
393    }
394
395    fn on_id_size(&mut self) -> Response {
396        match self.handler.handle_id_size() {
397            Ok(size) => Response::ok_usize(size),
398            Err(err) => Response::Err(err),
399        }
400    }
401
402    fn on_block_size(&mut self) -> Response {
403        if let Some(backend) = self.backend.as_ref() {
404            match self.handler.handle_block_size(backend) {
405                Ok(size) => Response::ok_u32(size),
406                Err(err) => Response::Err(err),
407            }
408        } else {
409            Response::err_not_applicable()
410        }
411    }
412
413    fn on_id_to_bytes(&mut self, str: &str) -> Response {
414        match self.handler.handle_id_to_bytes(str) {
415            Ok(bytes) => Response::ok_bytes(bytes),
416            Err(err) => Response::Err(err),
417        }
418    }
419
420    fn on_id_to_string(&mut self, bytes: &[u8]) -> Response {
421        match self.handler.handle_id_to_string(bytes) {
422            Ok(str) => Response::ok_string(str),
423            Err(err) => Response::Err(err),
424        }
425    }
426
427    fn on_info(&mut self) -> Response {
428        if let Some(backend) = self.backend.as_ref() {
429            match self.handler.handle_info(backend) {
430                Ok(info) => Response::ok_map(info),
431                Err(err) => Response::Err(err),
432            }
433        } else {
434            Response::err_not_applicable()
435        }
436    }
437
438    fn on_aquire(&mut self, bytes: &[u8]) -> Response {
439        if let Some(backend) = self.backend.as_mut() {
440            match self.handler.handle_aquire(backend, bytes) {
441                Ok(id) => Response::ok_bytes(id),
442                Err(err) => Response::Err(err),
443            }
444        } else {
445            Response::err_not_applicable()
446        }
447    }
448
449    fn on_release(&mut self, id: &[u8]) -> Response {
450        if let Some(backend) = self.backend.as_mut() {
451            match self.handler.handle_release(backend, id) {
452                Ok(()) => Response::ok_void(),
453                Err(err) => Response::Err(err),
454            }
455        } else {
456            Response::err_not_applicable()
457        }
458    }
459
460    fn on_read_header(&mut self) -> Response {
461        if let Some(args) = self.command.as_open() {
462            if let Some(mut builder) = self.handler.open_builder(args) {
463                match self.handler.handle_read_header(&mut builder) {
464                    Ok(header) => Response::ok_bytes(header),
465                    Err(err) => Response::Err(err),
466                }
467            } else {
468                Response::err_message("unable to build an open-builder")
469            }
470        } else if let Some(backend) = self.backend.as_mut() {
471            match self.handler.handle_read_header(backend) {
472                Ok(header) => Response::ok_bytes(header),
473                Err(err) => Response::Err(err),
474            }
475        } else {
476            Response::err_not_applicable()
477        }
478    }
479
480    fn on_write_header(&mut self, header: &[u8]) -> Response {
481        if let Some(backend) = self.backend.as_mut() {
482            match self.handler.handle_write_header(backend, header) {
483                Ok(()) => Response::ok_void(),
484                Err(err) => Response::Err(err),
485            }
486        } else {
487            Response::err_not_applicable()
488        }
489    }
490
491    fn on_read(&mut self, id: &[u8]) -> Response {
492        if let Some(backend) = self.backend.as_mut() {
493            match self.handler.handle_read(backend, id) {
494                Ok(data) => Response::ok_bytes(data),
495                Err(err) => Response::Err(err),
496            }
497        } else {
498            Response::err_not_applicable()
499        }
500    }
501
502    fn on_write(&mut self, id: &[u8], bytes: &[u8]) -> Response {
503        if let Some(backend) = self.backend.as_mut() {
504            match self.handler.handle_write(backend, id, bytes) {
505                Ok(n) => Response::ok_usize(n),
506                Err(err) => Response::Err(err),
507            }
508        } else {
509            Response::err_not_applicable()
510        }
511    }
512
513    fn on_delete(&mut self) -> Response {
514        if let Some(backend) = self.backend.take() {
515            match self.handler.handle_delete(backend) {
516                Ok(()) => Response::ok_void(),
517                Err(err) => Response::Err(err),
518            }
519        } else {
520            Response::err_not_applicable()
521        }
522    }
523
524    fn on_quit(&self) -> Response {
525        match self.handler.handle_quit() {
526            Ok(()) => Response::ok_void(),
527            Err(err) => Response::Err(err),
528        }
529    }
530}