1
use std::{collections::HashMap, error::Error as StdError, sync::Arc};
2

            
3
use axum::Router;
4
use reqwest;
5

            
6
use general_mq::Queue;
7
use sylvia_iot_corelib::constants::DbEngine;
8

            
9
use crate::{
10
    libs::{
11
        config::{self, Config},
12
        mq::{self, Connection},
13
    },
14
    models::{self, ConnOptions, Model, MongoDbOptions, SqliteOptions},
15
};
16

            
17
pub mod middleware;
18
mod v1;
19

            
20
/// The resources used by this service.
21
#[derive(Clone)]
22
pub struct State {
23
    /// The scope root path for the service.
24
    ///
25
    /// For example `/data`, the APIs are
26
    /// - `http://host:port/data/api/v1/application-uldata/xxx`
27
    /// - `http://host:port/data/api/v1/network-uldata/xxx`
28
    pub scope_path: &'static str,
29
    /// The database model.
30
    pub model: Arc<dyn Model>,
31
    /// The sylvia-iot-auth base API path with host.
32
    ///
33
    /// For example, `http://localhost:1080/auth`.
34
    pub auth_base: String,
35
    /// The sylvia-iot-broker base API path with host.
36
    ///
37
    /// For example, `http://localhost:2080/broker`.
38
    pub broker_base: String,
39
    /// The client for internal HTTP requests.
40
    pub client: reqwest::Client,
41
    /// Queue connections. Key is uri.
42
    pub mq_conns: HashMap<String, Connection>,
43
    /// Data channel receivers. Key is data channel name such as `broker.data`, `coremgr.data`, ...
44
    pub data_receivers: HashMap<String, Queue>,
45
}
46

            
47
/// The sylvia-iot module specific error codes in addition to standard
48
/// [`sylvia_iot_corelib::err::ErrResp`].
49
pub struct ErrReq;
50

            
51
impl ErrReq {
52
    pub const UNIT_NOT_EXIST: (u16, &'static str) = (400, "err_data_unit_not_exist");
53
    pub const USER_NOT_EXIST: (u16, &'static str) = (400, "err_data_user_not_exist");
54
}
55

            
56
/// To create resources for the service.
57
16
pub async fn new_state(
58
16
    scope_path: &'static str,
59
16
    conf: &Config,
60
16
) -> Result<State, Box<dyn StdError>> {
61
16
    let conf = config::apply_default(conf);
62
16
    let db_opts = match conf.db.as_ref().unwrap().engine.as_ref().unwrap().as_str() {
63
16
        DbEngine::MONGODB => {
64
6
            let conf = conf.db.as_ref().unwrap().mongodb.as_ref().unwrap();
65
6
            ConnOptions::MongoDB(MongoDbOptions {
66
6
                url: conf.url.as_ref().unwrap().to_string(),
67
6
                db: conf.database.as_ref().unwrap().to_string(),
68
6
                pool_size: conf.pool_size,
69
6
            })
70
        }
71
        _ => {
72
10
            let conf = conf.db.as_ref().unwrap().sqlite.as_ref().unwrap();
73
10
            ConnOptions::Sqlite(SqliteOptions {
74
10
                path: conf.path.as_ref().unwrap().to_string(),
75
10
            })
76
        }
77
    };
78
16
    let model = models::new(&db_opts).await?;
79
16
    let auth_base = conf.auth.as_ref().unwrap().clone();
80
16
    let broker_base = conf.broker.as_ref().unwrap().clone();
81
16
    let mut mq_conns = HashMap::new();
82
16
    let ch_conf = conf.mq_channels.as_ref().unwrap();
83
16
    let data_receivers = new_data_receivers(&model, &mut mq_conns, ch_conf)?;
84
16
    let state = State {
85
16
        scope_path,
86
16
        model,
87
16
        auth_base,
88
16
        broker_base,
89
16
        client: reqwest::Client::new(),
90
16
        mq_conns,
91
16
        data_receivers,
92
16
    };
93
16
    Ok(state)
94
16
}
95

            
96
/// To register service URIs in the specified root path.
97
2526
pub fn new_service(state: &State) -> Router {
98
2526
    Router::new().nest(
99
2526
        &state.scope_path,
100
2526
        Router::new()
101
2526
            .merge(v1::application_uldata::new_service(
102
2526
                "/api/v1/application-uldata",
103
2526
                state,
104
            ))
105
2526
            .merge(v1::application_dldata::new_service(
106
2526
                "/api/v1/application-dldata",
107
2526
                state,
108
            ))
109
2526
            .merge(v1::network_uldata::new_service(
110
2526
                "/api/v1/network-uldata",
111
2526
                state,
112
            ))
113
2526
            .merge(v1::network_dldata::new_service(
114
2526
                "/api/v1/network-dldata",
115
2526
                state,
116
            ))
117
2526
            .merge(v1::coremgr_opdata::new_service(
118
2526
                "/api/v1/coremgr-opdata",
119
2526
                state,
120
            )),
121
    )
122
2526
}
123

            
124
16
pub fn new_data_receivers(
125
16
    model: &Arc<dyn Model>,
126
16
    mq_conns: &mut HashMap<String, Connection>,
127
16
    ch_conf: &config::MqChannels,
128
16
) -> Result<HashMap<String, Queue>, Box<dyn StdError>> {
129
16
    let mut data_receivers = HashMap::<String, Queue>::new();
130

            
131
16
    let conf = ch_conf.broker.as_ref().unwrap();
132
16
    let q = mq::broker::new(model.clone(), mq_conns, &conf)?;
133
16
    data_receivers.insert("broker.data".to_string(), q);
134

            
135
16
    let conf = ch_conf.coremgr.as_ref().unwrap();
136
16
    let q = mq::coremgr::new(model.clone(), mq_conns, &conf)?;
137
16
    data_receivers.insert("coremgr.data".to_string(), q);
138

            
139
16
    Ok(data_receivers)
140
16
}