sylvia_iot_broker/models/
mod.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Traits and implementations for accessing databases and caches.
//!
//! Currently we only provide pure MongoDB/SQLite implementation. Mixing implementation is
//! possible. For example, put units/devices in MongoDB and put routes in Redis. Then use a
//! model struct and impl to mix both databases.

use std::{error::Error as StdError, sync::Arc};

use async_trait::async_trait;

pub mod application;
pub mod device;
pub mod device_route;
pub mod dldata_buffer;
pub mod network;
pub mod network_route;
pub mod unit;

mod cache_memory;
mod memory;
mod model_mongodb;
mod model_sqlite;
mod mongodb;
mod sqlite;

pub use self::{
    cache_memory::{Cache as MemoryCache, Options as MemoryOptions},
    memory::{
        device::Options as DeviceOptions, device_route::Options as DeviceRouteOptions,
        network_route::Options as NetworkRouteOptions,
    },
    mongodb::conn::{self as mongodb_conn, Options as MongoDbOptions},
    sqlite::conn::{self as sqlite_conn, Options as SqliteOptions},
};
pub use model_mongodb::Model as MongoDbModel;
pub use model_sqlite::Model as SqliteModel;

/// Database connection options for model implementation.
pub enum ConnOptions {
    // Pure MongoDB model implementation.
    MongoDB(MongoDbOptions),
    /// Pure SQLite model implementation.
    Sqlite(SqliteOptions),
}

/// Database connection options for cache implementation.
pub enum CacheConnOptions {
    Memory {
        device: DeviceOptions,
        device_route: DeviceRouteOptions,
        network_route: NetworkRouteOptions,
    },
}

/// The top level trait to get all models (tables/collections).
#[async_trait]
pub trait Model: Send + Sync {
    /// Close database connection.
    async fn close(&self) -> Result<(), Box<dyn StdError>>;

    /// To get the unit model.
    fn unit(&self) -> &dyn unit::UnitModel;

    /// To get the application model.
    fn application(&self) -> &dyn application::ApplicationModel;

    /// To get the network model.
    fn network(&self) -> &dyn network::NetworkModel;

    /// To get the device model.
    fn device(&self) -> &dyn device::DeviceModel;

    /// To get the device route model.
    fn device_route(&self) -> &dyn device_route::DeviceRouteModel;

    /// To get the network route model.
    fn network_route(&self) -> &dyn network_route::NetworkRouteModel;

    /// To get the downlink data buffer model.
    fn dldata_buffer(&self) -> &dyn dldata_buffer::DlDataBufferModel;
}

/// The top level trait to get all caches.
#[async_trait]
pub trait Cache: Send + Sync {
    /// Close database connection.
    async fn close(&self) -> Result<(), Box<dyn StdError>>;

    /// To get the device cache.
    fn device(&self) -> &dyn device::DeviceCache;

    /// To get the device route cache.
    fn device_route(&self) -> &dyn device_route::DeviceRouteCache;

    /// To get the network route cache.
    fn network_route(&self) -> &dyn network_route::NetworkRouteCache;
}

/// To create the database model with the specified database implementation.
pub async fn new(opts: &ConnOptions) -> Result<Arc<dyn Model>, Box<dyn StdError>> {
    let model: Arc<dyn Model> = match opts {
        ConnOptions::MongoDB(opts) => Arc::new(MongoDbModel::new(opts).await?),
        ConnOptions::Sqlite(opts) => Arc::new(SqliteModel::new(opts).await?),
    };
    model.unit().init().await?;
    model.application().init().await?;
    model.network().init().await?;
    model.device().init().await?;
    model.device_route().init().await?;
    model.network_route().init().await?;
    model.dldata_buffer().init().await?;
    Ok(model)
}

/// To create the database cache with the specified database implementation.
pub async fn new_cache(
    opts: &CacheConnOptions,
    model: &Arc<dyn Model>,
) -> Result<Arc<dyn Cache>, Box<dyn StdError>> {
    let cache: Arc<dyn Cache> = match opts {
        CacheConnOptions::Memory {
            device,
            device_route,
            network_route,
        } => {
            let opts = MemoryOptions {
                device: &device,
                device_route: &device_route,
                network_route: &network_route,
            };
            Arc::new(MemoryCache::new(&opts, model))
        }
    };
    Ok(cache)
}