cardinal_rs/
lib.rs

1mod tests;
2
3use cardinal_base::context::CardinalContext;
4use cardinal_base::destinations::container::DestinationContainer;
5use cardinal_base::provider::{Provider, ProviderScope};
6use cardinal_config::{load_config, CardinalConfig};
7use cardinal_errors::internal::CardinalInternalError;
8use cardinal_errors::CardinalError;
9use cardinal_plugins::container::PluginContainer;
10use cardinal_proxy::{CardinalContextProvider, CardinalProxy, StaticContextProvider};
11use pingora::prelude::Server;
12use pingora::proxy::http_proxy_service;
13use std::sync::Arc;
14
15pub struct Cardinal {
16    context: Arc<CardinalContext>,
17    context_provider: Arc<dyn CardinalContextProvider>,
18}
19
20impl Cardinal {
21    pub fn builder(config: CardinalConfig) -> CardinalBuilder {
22        CardinalBuilder::new(config)
23    }
24
25    pub fn from_paths(config_paths: &[String]) -> Result<Self, CardinalError> {
26        Ok(CardinalBuilder::from_paths(config_paths)?.build())
27    }
28
29    pub fn new(config: CardinalConfig) -> Self {
30        CardinalBuilder::new(config).build()
31    }
32
33    pub fn context(&self) -> Arc<CardinalContext> {
34        self.context.clone()
35    }
36
37    pub fn run(&self) -> Result<(), CardinalError> {
38        let mut server = Server::new(None).map_err(|e| {
39            CardinalError::InternalError(CardinalInternalError::FailedToInitiateServer(
40                e.to_string(),
41            ))
42        })?;
43        server.bootstrap();
44
45        let proxy = CardinalProxy::with_provider(self.context_provider.clone());
46        let mut proxy_service = http_proxy_service(&server.configuration, proxy);
47
48        let server_addr = self.context.config.server.address.clone();
49
50        proxy_service.add_tcp(&server_addr);
51
52        tracing::info!(addr = %server_addr, "Listening on address");
53
54        server.add_service(proxy_service);
55        server.run_forever();
56    }
57}
58
59pub struct CardinalBuilder {
60    context: Arc<CardinalContext>,
61    auto_register_defaults: bool,
62    context_provider: Option<Arc<dyn CardinalContextProvider>>,
63}
64
65impl CardinalBuilder {
66    pub fn new(config: CardinalConfig) -> Self {
67        let context = Arc::new(CardinalContext::new(config));
68        Self {
69            context,
70            auto_register_defaults: true,
71            context_provider: None,
72        }
73    }
74
75    pub fn new_empty(config: CardinalConfig) -> Self {
76        let context = Arc::new(CardinalContext::new(config));
77        Self {
78            context,
79            auto_register_defaults: false,
80            context_provider: None,
81        }
82    }
83
84    pub fn from_paths(config_paths: &[String]) -> Result<Self, CardinalError> {
85        let config = load_config(config_paths)?;
86        Ok(Self::new(config))
87    }
88
89    pub fn context(&self) -> Arc<CardinalContext> {
90        self.context.clone()
91    }
92
93    pub fn register_provider<T>(self, scope: ProviderScope) -> Self
94    where
95        T: Provider + Send + Sync + 'static,
96    {
97        self.context.register::<T>(scope);
98        self
99    }
100    pub fn register_provider_with_factory<T, F>(self, scope: ProviderScope, factory: F) -> Self
101    where
102        T: Provider + Send + Sync + 'static,
103        F: Fn(Arc<CardinalContext>) -> Result<T, CardinalError> + Send + Sync + 'static,
104    {
105        let ctx = Arc::clone(&self.context);
106        let factory: Arc<dyn Fn(Arc<CardinalContext>) -> Result<T, CardinalError> + Send + Sync> =
107            Arc::new(factory);
108        self.context
109            .register_with_factory::<T, _, _>(scope, move |_ctx| {
110                let ctx_clone = Arc::clone(&ctx);
111                let factory = Arc::clone(&factory);
112                async move { (factory)(ctx_clone) }
113            });
114        self
115    }
116
117    pub fn register_singleton_instance<T>(self, instance: Arc<T>) -> Self
118    where
119        T: Provider + Send + Sync + 'static,
120    {
121        self.context.register_singleton_instance::<T>(instance);
122        self
123    }
124
125    pub fn with_context_provider(mut self, provider: Arc<dyn CardinalContextProvider>) -> Self {
126        self.context_provider = Some(provider);
127        self
128    }
129
130    pub fn build(self) -> Cardinal {
131        if self.auto_register_defaults {
132            if !self.context.is_registered::<DestinationContainer>() {
133                self.context
134                    .register::<DestinationContainer>(ProviderScope::Singleton);
135            }
136
137            if !self.context.is_registered::<PluginContainer>() {
138                self.context
139                    .register::<PluginContainer>(ProviderScope::Singleton);
140            }
141        }
142
143        let provider = self
144            .context_provider
145            .unwrap_or_else(|| Arc::new(StaticContextProvider::new(self.context.clone())));
146
147        Cardinal {
148            context: self.context,
149            context_provider: provider,
150        }
151    }
152}