1pub mod config;
9pub mod date_time;
10pub mod event;
11pub mod hash;
12pub mod keys;
13pub mod listeners;
14pub mod logs;
15pub mod size;
16pub mod sys;
17
18use std::{any::Any, env, fmt::Debug, sync::OnceLock};
19
20use figlet_rs::FIGfont;
21use rkyv::{
22 Archive,
23 bytecheck::CheckBytes,
24 de::Pool,
25 rancor::{Failure, Strategy},
26 util::AlignedVec,
27 validation::{Validator, archive::ArchiveValidator, shared::SharedValidator},
28};
29use threadpool::ThreadPool;
30use tracing::info;
31
32use crate as xaeroflux_core;
33use crate::{config::Config, logs::init_logging};
34
35pub trait XaeroData: Any + Send + Sync + Clone + Debug {}
43
44impl<T> XaeroData for T where T: Any + Send + Sync + Clone + Debug {}
45
46pub static CONF: OnceLock<config::Config> = OnceLock::new();
50
51pub static DISPATCHER_POOL: OnceLock<ThreadPool> = OnceLock::new();
53
54pub static IO_POOL: OnceLock<ThreadPool> = OnceLock::new();
56
57pub static P2P_RUNTIME: OnceLock<tokio::runtime::Runtime> = OnceLock::new();
59
60pub fn init_p2p_runtime() -> &'static tokio::runtime::Runtime {
65 P2P_RUNTIME.get_or_init(|| {
66 let conf = CONF.get_or_init(Config::default);
67 let threads = conf.threads.num_worker_threads.max(2);
68 tokio::runtime::Builder::new_multi_thread()
69 .worker_threads(threads)
70 .enable_all()
71 .thread_name("xaeroflux-p2p")
72 .build()
73 .expect("Failed to create P2P runtime")
74 })
75}
76
77pub fn init_global_dispatcher_pool() {
82 DISPATCHER_POOL.get_or_init(|| {
83 let conf = CONF.get_or_init(Config::default);
84 let no_of_worker_threads = conf.threads.num_worker_threads.max(1);
85
86 ThreadPool::new(no_of_worker_threads)
87 });
88}
89
90pub fn init_global_io_pool() {
95 IO_POOL.get_or_init(|| {
96 let conf = CONF.get_or_init(Config::default);
97 let num_io_threads = conf.threads.num_io_threads.max(1);
98
99 ThreadPool::new(num_io_threads)
100 });
101}
102
103pub fn initialize() {
112 #[cfg(not(test))]
113 xaeroflux_core::size::init(); xaeroflux_core::size::init();
115 let project_root = env!("CARGO_MANIFEST_DIR");
116 let cfg_path = format!("{}/xaeroflux.toml", project_root);
117 unsafe { env::set_var("XAERO_CONFIG", &cfg_path) };
118 let config = load_config();
119 if config.name != "xaeroflux" {
120 panic!("Invalid config file. Expected 'xaeroflux'.");
121 }
122 init_global_dispatcher_pool();
123 init_global_io_pool();
124 init_logging(); show_banner();
126 info!("XaeroFlux initialized");
127}
128
129pub fn serialize<T>(data: &T) -> Result<AlignedVec, Failure>
136where
137 T: XaeroData
138 + for<'a> rkyv::Serialize<
139 rkyv::rancor::Strategy<
140 rkyv::ser::Serializer<
141 rkyv::util::AlignedVec,
142 rkyv::ser::allocator::ArenaHandle<'a>,
143 rkyv::ser::sharing::Share,
144 >,
145 rkyv::rancor::Failure,
146 >,
147 >,
148{
149 rkyv::to_bytes::<Failure>(data)
150}
151
152pub fn deserialize<T>(data: &[u8]) -> Result<T, Failure>
159where
160 T: XaeroData + rkyv::Archive,
161 for<'a> <T as Archive>::Archived: CheckBytes<
162 Strategy<Validator<ArchiveValidator<'a>, SharedValidator>, rkyv::rancor::Failure>,
163 >,
164 <T as Archive>::Archived: rkyv::Deserialize<T, Strategy<Pool, Failure>>,
165{
166 rkyv::from_bytes::<T, Failure>(data)
167}
168pub fn load_config() -> &'static config::Config {
176 CONF.get_or_init(|| {
177 let path = std::env::var("XAERO_CONFIG").unwrap_or_else(|_| "xaeroflux.toml".into());
178 let s = std::fs::read_to_string(path).expect("read config");
179 toml::from_str(&s).expect("parse config")
180 })
181}
182
183pub fn show_banner() {
187 info!("XaeroFlux initializing...");
188 let slant = FIGfont::standard().expect("load slant font");
189 let v = env!("CARGO_PKG_VERSION");
190 let x = format!("XAER0FLUX v. {v}");
191 let s = x.as_str();
192 let figure = slant.convert(s).expect("convert text");
193 tracing::info!("\n{}", figure);
194}
195#[cfg(test)]
196mod tests {
197 use rkyv::{Archive, Deserialize, Serialize, rancor::Failure};
198 use xaeroflux_core::event;
199
200 use super::*;
201
202 #[test]
203 fn test_initialize() {
204 initialize();
205 assert!(CONF.get().is_some());
206 assert_eq!(CONF.get().expect("failed to load config").name, "xaeroflux");
207 assert_eq!(CONF.get().expect("failed to load config").version, 1_u64);
208 }
209
210 #[test]
211 fn test_load_config() {
212 initialize();
213 let config = load_config();
214 assert_eq!(config.name, "xaeroflux");
215 assert_eq!(config.version, 1_u64);
216 }
217 #[test]
218 fn test_xaero_data() {
219 initialize();
220 #[derive(Archive, Serialize, Deserialize, Debug, Clone, Default)]
221 struct TestData {
222 id: u32,
223 name: String,
224 }
225 let data = TestData {
227 id: 1,
228 name: "Test".to_string(),
229 };
230 assert_eq!(data.id, 1);
231 assert_eq!(data.name, "Test");
232 let d = rkyv::to_bytes::<Failure>(&data).expect("failed to serialize");
234 assert!(!d.is_empty());
235 }
236 #[test]
237 fn test_event_type() {
238 initialize();
239 let e = event::EventType::SystemEvent(event::SystemEventKind::Start);
240 let event = event::EventType::from_u8(1);
241 assert_eq!(event, e);
242 }
243 #[test]
244 fn test_event() {
245 initialize();
246 let data = event::EventType::from_u8(0);
247 let event = event::Event::<event::EventType>::new(data.clone(), 0);
248 assert_eq!(event.event_type, data);
249 assert_eq!(
250 event.version,
251 CONF.get().expect("failed to load config").version
252 );
253 }
254}