rsiot/components_config/http_server/
put_endpoint.rs

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
use std::{collections::HashMap, fmt::Debug};

use serde::{de::DeserializeOwned, Serialize};
use serde_json::from_str;

use crate::message::{Message, MsgDataBound};

/// Конфигурация отдельной точки PUT
#[derive(Clone, Debug)]
pub struct PutEndpointConfig<TMsg, TData>
where
    TMsg: MsgDataBound,
{
    /// Путь
    ///
    /// Примеры:
    ///
    /// ```rust
    /// path: `/data`
    /// ```
    pub path: &'static str,

    /// Функция создания исходящих сообщений на основе входящих данных
    pub fn_output: fn(data: TData) -> Option<Message<TMsg>>,
}

impl<TMsg, TData> PutEndpoint<TMsg> for PutEndpointConfig<TMsg, TData>
where
    TData: 'static + Clone + Debug + DeserializeOwned + Serialize + Send + Sync,
    TMsg: 'static + MsgDataBound,
{
    fn get_path(&self) -> &str {
        self.path
    }

    fn fn_output(&self, request_body: &str) -> Result<Option<Message<TMsg>>, serde_json::Error> {
        let data: TData = from_str(request_body)?;
        let msg = (self.fn_output)(data);
        Ok(msg)
    }

    fn clone_dyn(&self) -> Box<dyn PutEndpoint<TMsg>> {
        Box::new(self.clone())
    }
}

/// Создать коллекцию точек PUT на основе конфигурации
pub fn create_put_endpoints_hashmap<TMsg>(
    config_endpoints: &[Box<dyn PutEndpoint<TMsg>>],
) -> HashMap<String, Box<dyn PutEndpoint<TMsg>>>
where
    TMsg: MsgDataBound,
{
    let mut endpoints = HashMap::new();
    for endpoint in config_endpoints {
        endpoints.insert(endpoint.get_path().to_string(), endpoint.clone());
    }
    endpoints
}

/// Трейт для обеспечения логики работы отдельной точик PUT
///
/// В разных точках хранят данные в разных структурах (поле `data`). Трейт нужен для обработки в
/// массиве
pub trait PutEndpoint<TMsg>
where
    Self: Debug + Send + Sync,
{
    /// Получить путь для роутера
    fn get_path(&self) -> &str;

    /// Создание исходящих сообщений на основе входящих данных
    fn fn_output(&self, request_body: &str) -> Result<Option<Message<TMsg>>, serde_json::Error>;

    /// Поддержка клонирования
    fn clone_dyn(&self) -> Box<dyn PutEndpoint<TMsg>>;
}

impl<TMsg> Clone for Box<dyn PutEndpoint<TMsg>> {
    fn clone(&self) -> Self {
        self.clone_dyn()
    }
}