flippico_cache/types/
provider.rs1use redis::Client;
2
3use crate::{
4 providers::redis::Redis,
5 types::channels::{
6 CacheSpace, CacheValue, ChannelMessage, ListChannel, ListMessage, MessageMeta,
7 SubscriptionChannel,
8 },
9};
10use dotenv::dotenv;
11use std::env;
12use std::future::Future;
13use std::pin::Pin;
14
15pub trait ProviderTrait {
16 fn new(url: String) -> Self
17 where
18 Self: Sized;
19}
20
21pub trait Connectable {
22 fn set_client(&mut self);
23 fn get_connection(&self) -> &Client;
24 fn get_mut_connection(&mut self) -> &mut Client;
25}
26
27pub type PubSubProviderError = &'static str;
28
29pub type AsyncCallback<T> =
30 Box<dyn Fn(T) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>> + Send + Sync>;
31
32pub trait PubSubProvider {
33 type Channels;
34 fn subscribe(
35 &self,
36 callback: AsyncCallback<ChannelMessage>,
37 channel: Self::Channels,
38 ) -> Pin<Box<dyn Future<Output = Result<(), &'static str>> + Send + '_>>;
39 fn publish(&mut self, channel: Self::Channels, message: ChannelMessage);
40}
41
42pub trait FifoProvider {
43 fn push(&self, channel_name: ListChannel, job_key: &str, job_payload: serde_json::Value);
44 fn pop(
45 &self,
46 channel_name: ListChannel,
47 job_key: &str,
48 callback: AsyncCallback<ListMessage>,
49 ) -> Pin<Box<dyn Future<Output = Result<(), PubSubProviderError>> + Send + '_>>;
50
51 fn get_list_name(&self, channel_name: &str, job_key: &str) -> String {
52 format!("{}:{}", channel_name, job_key)
53 }
54}
55
56pub trait CacheProvider {
57 fn get(&self, cache_space: CacheSpace, key: &str, app_name: Option<String>) -> String;
58 fn delete(&self, cache_space: CacheSpace, key: &str, app_name: Option<String>);
59 fn set(
60 &self,
61 cache_space: CacheSpace,
62 key: &str,
63 value: serde_json::Value,
64 app_name: Option<String>,
65 );
66
67 fn get_key_name(&self, cache_space: CacheSpace, key: &str, app_name: Option<String>) -> String {
68 if app_name.is_none() {
69 return format!("{}:{}", cache_space.get_space(), key);
70 }
71
72 format!("{}:{}:{}", cache_space.get_space(), app_name.unwrap(), key)
73 }
74
75 fn get_value(&self, app_name: Option<String>, value: serde_json::Value) -> CacheValue<serde_json::Value> {
76 if app_name.is_none() {
77 return CacheValue {
78 meta: None,
79 value: Some(value),
80 };
81 }
82
83 CacheValue {
84 meta: Some(MessageMeta {
85 app_name: app_name.unwrap(),
86 }),
87 value: Some(value),
88 }
89 }
90}
91
92pub trait ConnectableProvider: ProviderTrait + Connectable {}
93impl<T> ConnectableProvider for T where T: ProviderTrait + Connectable {}
94
95pub trait ConnectablePubSubProvider: ConnectableProvider + PubSubProvider {}
96impl<T> ConnectablePubSubProvider for T where T: ConnectableProvider + PubSubProvider {}
97
98pub trait ConnectableFifoProvider: ConnectableProvider + FifoProvider {}
99impl<T> ConnectableFifoProvider for T where T: ConnectableProvider + FifoProvider {}
100
101pub trait ConnectableCacheProvider: ConnectableProvider + CacheProvider {}
102impl<T> ConnectableCacheProvider for T where T: ConnectableProvider + CacheProvider {}
103
104pub enum Provider {
105 Redis,
106}
107
108pub enum ProviderEither {
109 Redis(Box<Redis>),
110}
111
112impl ProviderEither {
113 pub fn pub_sub(
114 self,
115 ) -> Result<
116 Box<dyn ConnectablePubSubProvider<Channels = SubscriptionChannel> + Send + Sync>,
117 &'static str,
118 > {
119 match self {
120 ProviderEither::Redis(provider) => Ok(provider
121 as Box<
122 dyn ConnectablePubSubProvider<Channels = SubscriptionChannel> + Send + Sync,
123 >),
124 }
125 }
126
127 pub fn connectable(self) -> Result<Box<dyn ConnectableProvider + Send + Sync>, &'static str> {
128 match self {
129 ProviderEither::Redis(provider) => {
130 Ok(provider as Box<dyn ConnectableProvider + Send + Sync>)
131 }
132 }
133 }
134
135 pub fn fifo(self) -> Result<Box<dyn ConnectableFifoProvider + Send + Sync>, &'static str> {
136 match self {
137 ProviderEither::Redis(provider) => {
138 Ok(provider as Box<dyn ConnectableFifoProvider + Send + Sync>)
139 }
140 }
141 }
142
143 pub fn cache(self) -> Result<Box<dyn ConnectableCacheProvider + Send + Sync>, &'static str> {
144 match self {
145 ProviderEither::Redis(provider) => {
146 Ok(provider as Box<dyn ConnectableCacheProvider + Send + Sync>)
147 }
148 }
149 }
150}
151
152impl Provider {
153 pub(crate) fn create_provider(&self) -> ProviderEither {
154 match self {
155 Provider::Redis => {
156 dotenv().ok();
157 let url = env::var("FLIPPICO_CACHE_REDIS_URL");
158 if let Ok(url) = url {
159 let mut provider = Redis::new(url);
160 provider.set_client();
161 ProviderEither::Redis(Box::new(provider))
162 } else {
163 log::error!("FLIPPICO_CACHE_REDIS_URL is not set");
164 panic!("FLIPPICO_CACHE_REDIS_URL is not set");
165 }
166 }
167 }
168 }
169}