1use std::collections::HashSet;
4use std::marker::PhantomData;
5use std::sync::atomic::AtomicI64;
6use std::sync::Arc;
7use std::time::Duration;
8
9use redis::{cmd, AsyncTypedCommands};
10use serde::de::DeserializeOwned;
11use serde::Serialize;
12use tracing::instrument;
13
14use crate::{RedisObjects, ErrorTypes, retry_call};
15
16const DROP_CARD_SCRIPT: &str = r#"
17local set_name = KEYS[1]
18local key = ARGV[1]
19
20redis.call('srem', set_name, key)
21return redis.call('scard', set_name)
22"#;
23
24const LIMITED_ADD: &str = r#"
25local set_name = KEYS[1]
26local key = ARGV[1]
27local limit = tonumber(ARGV[2])
28
29if redis.call('scard', set_name) < limit then
30 redis.call('sadd', set_name, key)
31 return true
32end
33return false
34"#;
35
36pub struct Set<T> {
38 name: String,
39 store: Arc<RedisObjects>,
40 drop_card_script: redis::Script,
41 limited_add: redis::Script,
42 ttl: Option<i64>,
43 last_expire_time: AtomicI64,
44 _data: PhantomData<T>
45}
46
47impl<T> std::fmt::Debug for Set<T> {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 f.debug_struct("Set").field("name", &self.name).field("store", &self.store).finish()
50 }
51}
52
53impl<T: Serialize + DeserializeOwned> Set<T> {
54 pub (crate) fn new(name: String, store: Arc<RedisObjects>, ttl: Option<Duration>) -> Self {
55 Self {
56 name,
57 store,
58 drop_card_script: redis::Script::new(DROP_CARD_SCRIPT),
59 limited_add: redis::Script::new(LIMITED_ADD),
60 ttl: ttl.map(|v| v.as_secs() as i64),
61 last_expire_time: AtomicI64::new(i64::MIN),
62 _data: PhantomData,
63 }
64 }
65
66 async fn _conditional_expire(&self) -> Result<(), ErrorTypes> {
68 if let Some(ttl) = self.ttl {
69 let ctime = chrono::Utc::now().timestamp();
70 let last_expire_time: i64 = self.last_expire_time.load(std::sync::atomic::Ordering::Acquire);
71 if ctime > last_expire_time + (ttl / 2) {
72 let _: bool = retry_call!(self.store.pool, expire, &self.name, ttl)?;
73 self.last_expire_time.store(ctime, std::sync::atomic::Ordering::Release);
74 }
75 }
76 Ok(())
77 }
78
79 #[instrument(skip(value))]
82 pub async fn add(&self, value: &T) -> Result<bool, ErrorTypes> {
83 let data = serde_json::to_string(&value)?;
84 let result = retry_call!(self.store.pool, sadd, &self.name, &data)?;
85 self._conditional_expire().await?;
86 Ok(result > 0)
87 }
88
89 #[instrument(skip(values))]
92 pub async fn add_batch(&self, values: &[T]) -> Result<usize, ErrorTypes> {
93 let mut data = vec![];
94 for item in values {
95 data.push(serde_json::to_string(&item)?);
96 }
97 let result = retry_call!(self.store.pool, sadd, &self.name, &data)?;
98 self._conditional_expire().await?;
99 Ok(result)
100 }
101
102 #[instrument(skip(value))]
104 pub async fn limited_add(&self, value: &T, size_limit: usize) -> Result<bool, ErrorTypes> {
105 let data = serde_json::to_vec(&value)?;
106 let result = retry_call!(method, self.store.pool,
107 self.limited_add.key(&self.name).arg(&data).arg(size_limit), invoke_async)?;
108 self._conditional_expire().await?;
109 Ok(result)
110 }
111
112 #[instrument(skip(value))]
114 pub async fn exist(&self, value: &T) -> Result<bool, ErrorTypes> {
115 let data = serde_json::to_vec(&value)?;
116 retry_call!(self.store.pool, sismember, &self.name, &data)
117 }
118
119 #[instrument]
121 pub async fn length(&self) -> Result<usize, ErrorTypes> {
122 retry_call!(self.store.pool, scard, &self.name)
123 }
124
125 #[instrument]
127 pub async fn members(&self) -> Result<Vec<T>, ErrorTypes> {
128 let data: HashSet<String> = retry_call!(self.store.pool, smembers, &self.name)?;
129 Ok(data.into_iter()
130 .map(|v| serde_json::from_str::<T>(&v))
131 .collect::<Result<Vec<T>, _>>()?)
132 }
133
134 #[instrument(skip(value))]
136 pub async fn remove(&self, value: &T) -> Result<bool, ErrorTypes> {
137 let data = serde_json::to_vec(&value)?;
138 let rem: usize = retry_call!(self.store.pool, srem, &self.name, &data)?;
139 Ok(rem > 0)
140 }
141
142 #[instrument(skip(values))]
145 pub async fn remove_batch(&self, values: &[T]) -> Result<usize, ErrorTypes> {
146 let mut data = vec![];
147 for item in values {
148 data.push(serde_json::to_vec(&item)?);
149 }
150 retry_call!(self.store.pool, srem, &self.name, &data)
151 }
152
153 #[instrument(skip(value))]
155 pub async fn drop(&self, value: &T) -> Result<usize, ErrorTypes> {
156 let data = serde_json::to_vec(&value)?;
157 let size: Option<usize> = retry_call!(method, self.store.pool,
158 self.drop_card_script.key(&self.name).arg(&data), invoke_async)?;
159 Ok(size.unwrap_or_default())
160 }
161
162 #[instrument]
164 pub async fn random(&self) -> Result<Option<T>, ErrorTypes>{
165 let ret_val: Option<String> = retry_call!(self.store.pool, srandmember, &self.name)?;
166 match ret_val {
167 Some(data) => Ok(Some(serde_json::from_str(&data)?)),
168 None => Ok(None),
169 }
170 }
171
172 #[instrument]
182 pub async fn pop(&self) -> Result<Option<T>, ErrorTypes> {
183 let data: Option<String> = retry_call!(self.store.pool, spop, &self.name)?;
184 match data {
185 Some(data) => Ok(Some(serde_json::from_str(&data)?)),
186 None => Ok(None),
187 }
188 }
189
190 #[instrument]
192 pub async fn pop_all(&self) -> Result<Vec<T>, ErrorTypes> {
193 let length = self.length().await?;
194 let mut command = cmd("SPOP");
195 let command = command.arg(&self.name).arg(length);
196 let data: Vec<String> = retry_call!(method, self.store.pool, command, query_async)?;
197 Ok(data.into_iter()
198 .map(|v| serde_json::from_str::<T>(&v))
199 .collect::<Result<Vec<T>, _>>()?)
200 }
201
202 #[instrument]
204 pub async fn delete(&self) -> Result<usize, ErrorTypes> {
205 retry_call!(self.store.pool, del, &self.name)
206 }
207}
208