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}