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

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

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

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

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

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

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