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}