1
use std::{error::Error as StdError, num::NonZeroUsize, sync::Arc};
2

            
3
use async_trait::async_trait;
4
use lru::LruCache;
5
use tokio::sync::RwLock;
6

            
7
use super::super::{
8
    network_route::{ListOptions, ListQueryCond, NetworkRouteCache, NetworkRouteCacheUlData},
9
    Model,
10
};
11

            
12
pub struct Cache {
13
    model: Arc<dyn Model>,
14
    uldata: Arc<RwLock<LruCache<String, Option<NetworkRouteCacheUlData>>>>,
15
}
16

            
17
pub struct Options {
18
    pub uldata_size: usize,
19
}
20

            
21
const DEF_SIZE: usize = 10_000;
22

            
23
impl Cache {
24
20
    pub fn new(opts: &Options, model: Arc<dyn Model>) -> Self {
25
20
        let uldata = unsafe { NonZeroUsize::new_unchecked(opts.uldata_size) };
26
20
        Cache {
27
20
            model,
28
20
            uldata: Arc::new(RwLock::new(LruCache::new(uldata))),
29
20
        }
30
20
    }
31
}
32

            
33
#[async_trait]
34
impl NetworkRouteCache for Cache {
35
96
    async fn clear(&self) -> Result<(), Box<dyn StdError>> {
36
96
        let mut lock = self.uldata.write().await;
37
96
        lock.clear();
38
96
        Ok(())
39
192
    }
40

            
41
    async fn get_uldata(
42
        &self,
43
        network_id: &str,
44
48
    ) -> Result<Option<NetworkRouteCacheUlData>, Box<dyn StdError>> {
45
        {
46
48
            let mut lock = self.uldata.write().await;
47
48
            if let Some(value) = lock.get(network_id) {
48
32
                match value {
49
30
                    None => return Ok(None),
50
2
                    Some(value) => return Ok(Some(value.clone())),
51
                }
52
16
            }
53
16
        }
54
16

            
55
16
        let opts = ListOptions {
56
16
            cond: &ListQueryCond {
57
16
                network_id: Some(network_id),
58
16
                ..Default::default()
59
16
            },
60
16
            offset: None,
61
16
            limit: None,
62
16
            sort: None,
63
16
            cursor_max: None,
64
16
        };
65
16
        let (routes, _) = self.model.network_route().list(&opts, None).await?;
66
16
        let data = match routes.len() {
67
10
            0 => None,
68
            _ => {
69
6
                let mut routes_data = vec![];
70
10
                for r in routes.iter() {
71
10
                    routes_data.push(format!("{}.{}", r.unit_code, r.application_code))
72
                }
73
6
                Some(NetworkRouteCacheUlData {
74
6
                    app_mgr_keys: routes_data,
75
6
                })
76
            }
77
        };
78
16
        let _ = self.set_uldata(network_id, data.as_ref()).await;
79
16
        Ok(data)
80
96
    }
81

            
82
    async fn set_uldata(
83
        &self,
84
        network_id: &str,
85
        value: Option<&NetworkRouteCacheUlData>,
86
16
    ) -> Result<(), Box<dyn StdError>> {
87
16
        let key = network_id.to_string();
88
16
        let mut lock = self.uldata.write().await;
89
16
        let _ = match value {
90
10
            None => lock.push(key, None),
91
6
            Some(value) => lock.push(key, Some(value.clone())),
92
        };
93
16
        Ok(())
94
32
    }
95

            
96
32
    async fn del_uldata(&self, network_id: &str) -> Result<(), Box<dyn StdError>> {
97
32
        let mut lock = self.uldata.write().await;
98
32
        lock.pop(network_id);
99
32
        Ok(())
100
64
    }
101
}
102

            
103
impl Default for Options {
104
10
    fn default() -> Self {
105
10
        Options {
106
10
            uldata_size: DEF_SIZE,
107
10
        }
108
10
    }
109
}