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
use crate::cache::{DataCacher, error::CacheError};
use async_trait::async_trait;
use std::time::Duration;
use mobc_redis::{redis, RedisConnectionManager};
use mobc::{Connection, Pool};
use mobc_redis::redis::{AsyncCommands, ToRedisArgs, FromRedisValue, RedisWrite, RedisResult, Value, from_redis_value, ErrorKind};
use crate::Data;
pub type MobcPool = Pool<RedisConnectionManager>;
pub type MobcCon = Connection<RedisConnectionManager>;
#[derive(Clone)]
pub struct RedisDataCacher {
pool: MobcPool,
cache_default_key_espiration_seconds: u64
}
pub struct RedisCacheConfig<'a> {
connection_string: &'a str,
cache_pool_timeout_seconds: u64,
cache_pool_max_open: u64,
cache_pool_max_idle: u64,
cache_pool_expire_seconds: u64,
cache_default_key_expiration_seconds: u64
}
impl RedisDataCacher {
pub fn new(config: RedisCacheConfig) -> Result<RedisDataCacher, CacheError> {
let client = redis::Client::open(config.connection_string).map_err(|e| CacheError::InternalError { source: Box::new(e), })?;
let manager = RedisConnectionManager::new(client);
let pool = Pool::builder()
.get_timeout(Some(Duration::from_secs(config.cache_pool_timeout_seconds)))
.max_open(config.cache_pool_max_open)
.max_idle(config.cache_pool_max_idle)
.max_lifetime(Some(Duration::from_secs(config.cache_pool_expire_seconds)))
.build(manager);
Ok(RedisDataCacher {
pool,
cache_default_key_espiration_seconds: config.cache_default_key_expiration_seconds
})
}
async fn get_con(pool: &MobcPool) -> Result<MobcCon, CacheError> {
pool.get().await.map_err(|e| {
CacheError::InternalError { source: Box::new(e), }
})
}
}
impl ToRedisArgs for Data {
fn write_redis_args<W>(&self, out: &mut W)
where
W: ?Sized + RedisWrite,
{
let s: String = serde_json::to_string(self).unwrap();
out.write_arg(s.as_bytes())
}
}
impl FromRedisValue for Data {
fn from_redis_value(v: &Value) -> RedisResult<Data> {
let s: String = from_redis_value(v)?;
let d: Data = serde_json::from_str(&s).map_err(|_e| (ErrorKind::TypeError, "deserialization error!"))?;
Ok(d)
}
}
#[async_trait]
impl DataCacher for RedisDataCacher {
async fn set(&self, key: &str, value: Data) -> Result<(), CacheError> {
let mut con = RedisDataCacher::get_con(&self.pool).await?;
con.set_ex(key, value, self.get_default_key_expiration_seconds())
.await
.map_err(|e| CacheError::InternalError { source: Box::new(e), })
}
async fn get(&self, key: &str) -> Result<Data, CacheError> {
let mut con = RedisDataCacher::get_con(&self.pool).await?;
con.get(key).await.map_err(|e| CacheError::InternalError { source: Box::new(e), })
}
async fn exists(&self, key: &str) -> Result<bool, CacheError> {
let mut con = RedisDataCacher::get_con(&self.pool).await?;
con.exists(key).await.map_err(|e| CacheError::InternalError { source: Box::new(e), })
}
async fn expire(&self, key: &str, seconds: usize) -> Result<bool, CacheError> {
let mut con = RedisDataCacher::get_con(&self.pool).await?;
con.expire(key, seconds).await.map_err(|e| CacheError::InternalError { source: Box::new(e), })
}
fn get_default_key_expiration_seconds(&self) -> usize {
self.cache_default_key_espiration_seconds as usize
}
}