flippico_cache/types/
provider.rs

1use 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 {
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}