1#![allow(improper_ctypes_definitions)]
2#![allow(non_upper_case_globals)]
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5#![allow(clippy::all)]
6#![allow(unused_unsafe)]
7#![allow(unused_variables)]
8#![doc = include_str!("../README.md")]
9#[allow(improper_ctypes_definitions)]
19#[allow(unpredictable_function_pointer_comparisons)]
20pub mod bindings {
21 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
22}
23
24use bindings::*;
25use log::info;
26use std::path::Path;
27use std::sync::atomic::{AtomicBool, Ordering};
28use std::sync::Arc;
29use std::thread::{sleep, JoinHandle};
30use std::time::Duration;
31
32include!(concat!(env!("OUT_DIR"), "/aeron.rs"));
33include!(concat!(env!("OUT_DIR"), "/aeron_custom.rs"));
34
35unsafe impl Sync for AeronDriverContext {}
36unsafe impl Send for AeronDriverContext {}
37unsafe impl Sync for AeronDriver {}
38unsafe impl Send for AeronDriver {}
39
40pub struct EmbeddedMediaDriver {
44 stop: Option<Arc<AtomicBool>>,
45 handle: Option<JoinHandle<Result<(), AeronCError>>>,
46}
47
48impl EmbeddedMediaDriver {
49 pub fn stop(&self) {
52 if let Some(stop) = &self.stop {
53 stop.store(true, Ordering::SeqCst);
54 }
55 }
56
57 pub fn is_finished(&self) -> bool {
59 self.handle.as_ref().map_or(true, |h| h.is_finished())
60 }
61
62 pub fn join(mut self) -> Result<(), AeronCError> {
64 self.stop();
65 if let Some(h) = self.handle.take() {
66 return h.join().map_err(|_| AeronCError::from_code(-1)).and_then(|r| r);
69 }
70 Ok(())
71 }
72}
73
74impl Drop for EmbeddedMediaDriver {
75 fn drop(&mut self) {
76 if let Some(stop) = &self.stop {
77 stop.store(true, Ordering::SeqCst);
78 }
79 if let Some(h) = self.handle.take() {
80 let _ = h.join();
81 }
82 }
83}
84
85pub mod testing;
86
87impl AeronDriverContext {
88 pub fn set_conductor_idle_strategy_kind(&self, kind: AeronIdleStrategyKind) -> Result<i32, AeronCError> {
90 self.set_conductor_idle_strategy(kind.name_c())
91 }
92
93 pub fn set_sender_idle_strategy_kind(&self, kind: AeronIdleStrategyKind) -> Result<i32, AeronCError> {
95 self.set_sender_idle_strategy(kind.name_c())
96 }
97
98 pub fn set_receiver_idle_strategy_kind(&self, kind: AeronIdleStrategyKind) -> Result<i32, AeronCError> {
100 self.set_receiver_idle_strategy(kind.name_c())
101 }
102
103 pub fn set_sharednetwork_idle_strategy_kind(&self, kind: AeronIdleStrategyKind) -> Result<i32, AeronCError> {
105 self.set_sharednetwork_idle_strategy(kind.name_c())
106 }
107
108 pub fn set_shared_idle_strategy_kind(&self, kind: AeronIdleStrategyKind) -> Result<i32, AeronCError> {
110 self.set_shared_idle_strategy(kind.name_c())
111 }
112}
113
114impl AeronDriver {
115 pub fn launch_embedded(
116 aeron_context: AeronDriverContext,
117 register_sigint: bool,
118 ) -> (Arc<AtomicBool>, JoinHandle<Result<(), AeronCError>>) {
119 AeronDriver::wait_for_previous_media_driver_to_timeout(&aeron_context);
120
121 let stop = Arc::new(AtomicBool::new(false));
122 let stop_copy = stop.clone();
123 if register_sigint {
125 let stop_copy2 = stop.clone();
126 ctrlc::set_handler(move || {
127 stop_copy2.store(true, Ordering::SeqCst);
128 })
129 .expect("Error setting Ctrl-C handler");
130 }
131
132 let started = Arc::new(AtomicBool::new(false));
133 let started2 = started.clone();
134
135 let dir = aeron_context.get_dir().to_string();
136 info!("Starting media driver [dir={}]", dir);
137 let handle = std::thread::spawn(move || {
138 let aeron_context = aeron_context.clone();
139 let aeron_driver = AeronDriver::new(&aeron_context)?;
140 aeron_driver.start(true)?;
141
142 info!("Aeron driver started [dir={}]", aeron_driver.context().get_dir());
143
144 started2.store(true, Ordering::SeqCst);
145
146 while !stop.load(Ordering::Acquire) {
148 aeron_driver.main_idle_strategy(aeron_driver.main_do_work()?);
149 }
150
151 info!("stopping media driver");
152
153 Ok::<_, AeronCError>(())
154 });
155
156 while !started.load(Ordering::SeqCst) && !handle.is_finished() {
157 sleep(Duration::from_millis(100));
158 }
159
160 if handle.is_finished() {
161 panic!("failed to start media driver {:?}", handle.join())
162 }
163 info!("started media driver [dir={}]", dir);
164
165 (stop_copy, handle)
166 }
167
168 pub fn launch_embedded_guard(aeron_context: AeronDriverContext, register_sigint: bool) -> EmbeddedMediaDriver {
175 let (stop, handle) = Self::launch_embedded(aeron_context, register_sigint);
176 EmbeddedMediaDriver {
177 stop: Some(stop),
178 handle: Some(handle),
179 }
180 }
181
182 pub fn wait_for_previous_media_driver_to_timeout(aeron_context: &AeronDriverContext) {
185 if !aeron_context.get_dir_delete_on_start() {
186 let cnc_file = Path::new(aeron_context.get_dir()).join("cnc.dat");
187
188 if cnc_file.exists() {
189 let timeout = Duration::from_millis(aeron_context.get_driver_timeout_ms() * 2).as_nanos() as i64;
190
191 let mut duration = timeout;
192
193 if let Ok(md) = cnc_file.metadata() {
194 if let Ok(modified_time) = md.modified() {
195 if let Ok(took) = modified_time.elapsed() {
196 duration = took.as_nanos() as i64;
197 }
198 }
199 }
200
201 let delay = timeout - duration;
202
203 if delay > 0 {
204 let sleep_duration = Duration::from_nanos((delay + 1_000_000) as u64);
205 info!(
206 "cnc file already exists, will need to wait {sleep_duration:?} for timeout [file={cnc_file:?}]"
207 );
208 sleep(sleep_duration);
209 }
210 }
211 }
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218 use log::error;
219 use std::os::raw::c_int;
220 use std::sync::atomic::Ordering;
221 use std::time::Duration;
222
223 #[test]
224 fn driver_idle_strategy_kinds_round_trip() {
225 let ctx = AeronDriverContext::new().unwrap();
226 for (kind, name) in [
227 (AeronIdleStrategyKind::Sleeping, "sleeping"),
228 (AeronIdleStrategyKind::Yielding, "yield"),
229 (AeronIdleStrategyKind::BusySpin, "spin"),
230 (AeronIdleStrategyKind::NoOp, "noop"),
231 (AeronIdleStrategyKind::Backoff, "backoff"),
232 ] {
233 ctx.set_conductor_idle_strategy_kind(kind).unwrap();
234 assert_eq!(name, ctx.get_conductor_idle_strategy(), "conductor {kind:?}");
235 ctx.set_sender_idle_strategy_kind(kind).unwrap();
236 ctx.set_receiver_idle_strategy_kind(kind).unwrap();
237 ctx.set_sharednetwork_idle_strategy_kind(kind).unwrap();
238 ctx.set_shared_idle_strategy_kind(kind).unwrap();
239 }
240 }
241
242 #[test]
243 fn version_check() {
244 let major = unsafe { crate::aeron_version_major() };
245 let minor = unsafe { crate::aeron_version_minor() };
246 let patch = unsafe { crate::aeron_version_patch() };
247
248 let aeron_version = format!("{}.{}.{}", major, minor, patch);
249 let cargo_version = "1.52.0";
250 assert_eq!(aeron_version, cargo_version);
251 }
252
253 #[test]
254 fn send_message() -> Result<(), AeronCError> {
255 rusteron_code_gen::test_logger::init(log::LevelFilter::Info);
256 let topic = AERON_IPC_STREAM;
257 let stream_id = 32;
258
259 let aeron_context = AeronDriverContext::new()?;
260 aeron_context.set_dir_delete_on_shutdown(true)?;
261 aeron_context.set_dir_delete_on_start(true)?;
262
263 let (stop, _driver_handle) = AeronDriver::launch_embedded(aeron_context.clone(), false);
264
265 info!("aeron dir: {:?}", aeron_context.get_dir());
271
272 let dir = aeron_context.get_dir().to_string();
273 let ctx = AeronContext::new()?;
274 ctx.set_dir(&dir.into_c_string())?;
275
276 let client = Aeron::new(&ctx)?;
277
278 #[derive(Default, Debug)]
279 struct ErrorCount {
280 error_count: usize,
281 }
282
283 impl AeronErrorHandlerCallback for ErrorCount {
284 fn handle_aeron_error_handler(&mut self, error_code: c_int, msg: &str) {
285 error!("Aeron error {}: {}", error_code, msg);
286 self.error_count += 1;
287 }
288 }
289
290 let error_handler = Handler::new(ErrorCount::default());
291 ctx.set_error_handler(Some(error_handler.clone()))?;
292
293 struct Test {}
294 impl AeronAvailableCounterCallback for Test {
295 fn handle_aeron_on_available_counter(
296 &mut self,
297 counters_reader: AeronCountersReader,
298 registration_id: i64,
299 counter_id: i32,
300 ) -> () {
301 info!("new counter counters_reader={counters_reader:?} registration_id={registration_id} counter_id={counter_id}");
302 }
303 }
304
305 impl AeronNewPublicationCallback for Test {
306 fn handle_aeron_on_new_publication(
307 &mut self,
308 channel: &str,
309 stream_id: i32,
310 session_id: i32,
311 correlation_id: i64,
312 ) -> () {
313 info!("on new publication {channel} {stream_id} {session_id} {correlation_id}")
314 }
315 }
316 let handler = Handler::new(Test {});
317 ctx.set_on_available_counter(Some(handler.clone()))?;
318 ctx.set_on_new_publication(Some(handler.clone()))?;
319
320 client.start()?;
321 info!("aeron driver started");
322 assert!(Aeron::epoch_clock() > 0);
323 assert!(Aeron::nano_clock() > 0);
324
325 let counter_async = AeronAsyncAddCounter::new(&client, 2543543, "12312312".as_bytes(), "abcd")?;
326
327 let counter = counter_async.poll_blocking(Duration::from_secs(15))?;
328 unsafe {
329 *counter.addr() += 1;
330 }
331
332 let result = AeronAsyncAddPublication::new(&client, topic, stream_id)?;
333
334 let publication = result.poll_blocking(std::time::Duration::from_secs(15))?;
335
336 info!("publication channel: {:?}", publication.channel());
337 info!("publication stream_id: {:?}", publication.stream_id());
338 info!("publication status: {:?}", publication.channel_status());
339
340 drop(publication);
341 drop(counter);
342 drop(client);
343 stop.store(true, Ordering::SeqCst);
344
345 Ok(())
346 }
347
348 #[test]
349 pub fn test_debug() -> Result<(), Box<dyn std::error::Error>> {
350 let ctx = AeronDriverContext::new()?;
351
352 println!("{:#?}", ctx);
353
354 struct AgentStartHandler {
361 ctx_ptr: *mut aeron_driver_context_t,
362 }
363 unsafe impl Send for AgentStartHandler {}
366
367 impl AeronAgentStartFuncCallback for AgentStartHandler {
368 fn handle_aeron_agent_on_start_func(&mut self, role: &str) -> () {
369 unsafe {
370 aeron_set_thread_affinity_on_start(
371 self.ctx_ptr as *mut _,
372 std::ffi::CString::new(role).unwrap().into_raw(),
373 );
374 }
375 }
376 }
377
378 let agent_handler = Handler::new(AgentStartHandler {
379 ctx_ptr: ctx.get_inner(),
380 });
381 ctx.set_agent_on_start_function(Some(agent_handler.clone()))?;
382
383 println!("{:#?}", ctx);
384
385 Ok(())
386 }
387}