flippico_cache/lib.rs
1use crate::types::provider::{Provider, ProviderEither};
2
3pub mod core;
4pub mod providers;
5pub mod types;
6
7pub struct Cache {
8 provider: ProviderEither,
9}
10
11impl Cache {
12 pub fn new() -> Self {
13 Self {
14 provider: Provider::Redis.create_provider(),
15 }
16 }
17
18 pub fn pub_sub(
19 self,
20 ) -> Result<
21 Box<
22 dyn types::provider::ConnectablePubSubProvider<
23 Channels = types::channels::SubscriptionChannel,
24 > + Send
25 + Sync,
26 >,
27 &'static str,
28 > {
29 self.provider.pub_sub()
30 }
31
32 pub fn fifo(
33 self,
34 ) -> Result<Box<dyn types::provider::ConnectableFifoProvider + Send + Sync>, &'static str> {
35 self.provider.fifo()
36 }
37
38 pub fn cache(
39 self,
40 ) -> Result<Box<dyn types::provider::ConnectableCacheProvider + Send + Sync>, &'static str>
41 {
42 self.provider.cache()
43 }
44
45 pub fn sorted_set(
46 self,
47 ) -> Result<Box<dyn types::provider::ConnectableSortedSetProvider + Send + Sync>, &'static str>
48 {
49 self.provider.sorted_set()
50 }
51
52 /// Build the BullMQ capability.
53 ///
54 /// This builder is `async` while the other four are not. That is
55 /// deliberate: BullMQ's job lifecycle cannot be driven from a blocking
56 /// call. See the design spec, section 4.1.
57 #[cfg(feature = "bullmq")]
58 pub async fn bullmq(
59 self,
60 ) -> Result<Box<dyn types::bullmq::BullMqProvider + Send + Sync>, types::queues::BullMqError>
61 {
62 self.provider.bullmq().await
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use crate::types::channels::{
69 CacheSpace, ChannelMessage, ListChannel, ListMessage, SubscriptionChannel,
70 };
71 use std::sync::Arc;
72
73 use super::*;
74
75 fn get_test_msg() -> ChannelMessage {
76 ChannelMessage {
77 channel: SubscriptionChannel::BajkomatApi,
78 meta: None,
79 body: None,
80 }
81 }
82
83 fn get_test_list_msg() -> ListMessage {
84 ListMessage {
85 meta: None,
86 body: serde_json::json!({"body": "test"}).into(),
87 }
88 }
89
90 #[tokio::test]
91 async fn fifo_test() {
92 let cache = Arc::new(Cache::new().fifo().unwrap());
93 let cache_clone = cache.clone();
94 cache.push(
95 ListChannel::BajkomatApi,
96 "job_key",
97 serde_json::json!({"body": "test"}),
98 );
99 let fifo_value = cache_clone.pop(ListChannel::BajkomatApi, "job_key");
100 let msg2 = get_test_list_msg();
101 assert_eq!(fifo_value.unwrap(), msg2);
102 }
103
104 #[test]
105 fn publish_test() {
106 let mut cache = Cache::new().pub_sub().unwrap();
107 cache.publish(SubscriptionChannel::BajkomatApi, get_test_msg());
108 }
109
110 #[test]
111 fn cache_test_set() {
112 let cache = Cache::new().cache().unwrap();
113 let test_data = serde_json::json!({"data": "test"});
114 cache.set(CacheSpace::Shopify, "SomeKey", test_data, None);
115 let value = cache.get(CacheSpace::Shopify, "SomeKey", None);
116 assert_eq!("{\"meta\":null,\"value\":{\"data\":\"test\"}}", value);
117 }
118
119 #[test]
120 fn cache_test_del() {
121 let cache = Cache::new().cache().unwrap();
122 let test_data = serde_json::json!({"data": "test"});
123 cache.set(CacheSpace::Shopify, "SomeKey", test_data, None);
124 let value = cache.get(CacheSpace::Shopify, "SomeKey", None);
125 assert_eq!("{\"meta\":null,\"value\":{\"data\":\"test\"}}", value);
126 cache.delete(CacheSpace::Shopify, "SomeKey", None);
127 let value = cache.get(CacheSpace::Shopify, "SomeKey", None);
128 assert_eq!("", value);
129 }
130
131 // #[tokio::test]
132 // async fn subscribe_test() {
133 // let subscriber_cache = Cache::new().pub_sub().unwrap();
134 // let mut publisher_cache = Cache::new().pub_sub().unwrap();
135
136 // // Use a channel to signal when the callback is executed
137 // let (tx, rx) = tokio::sync::oneshot::channel();
138 // let tx = std::sync::Arc::new(std::sync::Mutex::new(Some(tx)));
139
140 // let sub_clbk = move |msg: ChannelMessage| {
141 // let tx_clone = tx.clone();
142 // Box::pin(async move {
143 // let msg2 = get_test_msg();
144 // assert_eq!(msg, msg2);
145 // if let Ok(mut tx_guard) = tx_clone.lock() {
146 // if let Some(sender) = tx_guard.take() {
147 // let _ = sender.send(());
148 // }
149 // }
150 // }) as Pin<Box<dyn std::future::Future<Output = ()> + Send + Sync>>
151 // };
152
153 // // Start the subscription task by moving the cache into the spawned task
154 // let _handle = tokio::spawn(async move {
155 // let subscription_task =
156 // subscriber_cache.subscribe(Box::new(sub_clbk), SubscriptionChannel::BajkomatApi);
157 // let _ = subscription_task.await;
158 // });
159
160 // // Wait a moment for subscription to be established
161 // tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
162
163 // // Publish the message
164 // publisher_cache.publish(SubscriptionChannel::BajkomatApi, get_test_msg());
165
166 // // Wait for the callback to be executed with timeout
167 // let timeout_result = tokio::time::timeout(tokio::time::Duration::from_secs(10), rx).await;
168 // match timeout_result {
169 // Ok(Ok(())) => {
170 // // Test passed
171 // }
172 // Ok(Err(e)) => {
173 // panic!("Callback channel error: {:?}", e);
174 // }
175 // Err(_error) => {
176 // // Check if Redis is available - if not, skip the test
177 // println!("Test timed out - Redis may not be available, skipping test");
178 // return;
179 // }
180 // }
181 // }
182}