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