diff --git a/Cargo.toml b/Cargo.toml index c352206..7d82096 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,14 @@ edition = "2018" repository = "https://github.com/bspeice/aeron-rs" readme = "README.md" license = "Apache-2.0" + +[badges] travis-ci = { repository = "bspeice/aeron-rs", branch = "master" } maintenance = { status = "actively-developed" } [dependencies] -aeron_driver-sys = { path = "./aeron_driver-sys" } \ No newline at end of file +aeron_driver-sys = { path = "./aeron_driver-sys" } + +[dev-dependencies] +clap = "2.33" +ctrlc = "3.1.3" diff --git a/README.md b/README.md index ab2fe79..a9f83ae 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,8 @@ ![](https://img.shields.io/travis/bspeice/aeron-rs?style=flat-square) -A Rust port of the [Aeron client](https://github.com/real-logic/Aeron). \ No newline at end of file + + +[Aeron](https://github.com/real-logic/aeron) client for Rust + + diff --git a/aeron_driver-sys/bindings.h b/aeron_driver-sys/bindings.h index f9b4222..39072ee 100644 --- a/aeron_driver-sys/bindings.h +++ b/aeron_driver-sys/bindings.h @@ -1,2 +1,3 @@ #include +#include #include diff --git a/aeron_driver-sys/build.rs b/aeron_driver-sys/build.rs index a5c1231..a8fa6d2 100644 --- a/aeron_driver-sys/build.rs +++ b/aeron_driver-sys/build.rs @@ -95,6 +95,8 @@ pub fn main() { let bindings = bindgen::Builder::default() .clang_arg(&format!("-I{}", header_path.display())) .header("bindings.h") + .whitelist_function("aeron_.*") + .whitelist_type("aeron_.*") .generate() .expect("Unable to generate aeron_driver bindings"); diff --git a/examples/aeronmd.rs b/examples/aeronmd.rs new file mode 100644 index 0000000..9d91217 --- /dev/null +++ b/examples/aeronmd.rs @@ -0,0 +1,96 @@ +//! Media driver startup example based on +//! [aeronmd.c](https://github.com/real-logic/aeron/blob/master/aeron-driver/src/main/c/aeronmd.c) +#![deny(missing_docs)] + +use aeron_driver_sys::*; +use clap; +use ctrlc; +use std::ffi::CStr; +use std::os::raw::c_void; +use std::ptr; +use std::sync::atomic::{AtomicBool, Ordering}; + +static RUNNING: AtomicBool = AtomicBool::new(true); + +unsafe extern "C" fn termination_hook(_clientd: *mut c_void) { + RUNNING.store(false, Ordering::SeqCst); +} + +fn main() { + let version = unsafe { CStr::from_ptr(aeron_version_full()) }; + let _cmdline = clap::App::new("aeronmd") + .version(version.to_str().unwrap()) + .get_matches(); + + // TODO: Handle -D switches + + ctrlc::set_handler(move || { + // TODO: Actually understand atomic ordering + RUNNING.store(false, Ordering::SeqCst); + }) + .unwrap(); + + let mut init_success = true; + let mut context: *mut aeron_driver_context_t = ptr::null_mut(); + let mut driver: *mut aeron_driver_t = ptr::null_mut(); + + if init_success { + let context_init = unsafe { aeron_driver_context_init(&mut context) }; + if context_init < 0 { + let err_code = unsafe { aeron_errcode() }; + let err_str = unsafe { CStr::from_ptr(aeron_errmsg()) }.to_str().unwrap(); + eprintln!("ERROR: context init ({}) {}", err_code, err_str); + init_success = false; + } + } + + if init_success { + let term_hook = unsafe { + aeron_driver_context_set_driver_termination_hook( + context, + Some(termination_hook), + ptr::null_mut(), + ) + }; + if term_hook < 0 { + let err_code = unsafe { aeron_errcode() }; + let err_str = unsafe { CStr::from_ptr(aeron_errmsg()) }.to_str().unwrap(); + eprintln!( + "ERROR: context set termination hook ({}) {}", + err_code, err_str + ); + init_success = false; + } + } + + if init_success { + let driver_init = unsafe { aeron_driver_init(&mut driver, context) }; + if driver_init < 0 { + let err_code = unsafe { aeron_errcode() }; + let err_str = unsafe { CStr::from_ptr(aeron_errmsg()) }.to_str().unwrap(); + eprintln!("ERROR: driver init ({}) {}", err_code, err_str); + init_success = false; + } + } + + if init_success { + let driver_start = unsafe { aeron_driver_start(driver, true) }; + if driver_start < 0 { + let err_code = unsafe { aeron_errcode() }; + let err_str = unsafe { CStr::from_ptr(aeron_errmsg()) }.to_str().unwrap(); + eprintln!("ERROR: driver start ({}) {}", err_code, err_str); + init_success = false; + } + } + + if init_success { + println!("Press Ctrl-C to exit."); + + while RUNNING.load(Ordering::SeqCst) { + unsafe { aeron_driver_main_idle_strategy(driver, aeron_driver_main_do_work(driver)) }; + } + } + + unsafe { aeron_driver_close(driver) }; + unsafe { aeron_driver_context_close(context) }; +} diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..0c1e5a9 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,44 @@ +use std::env; +use std::path::PathBuf; + +const DEFAULT_MEDIA_DRIVER_TIMEOUT_MS: u16 = 10_000; +const DEFAULT_RESOURCE_LINGER_MS: u16 = 5_000; + +pub struct Context { + aeron_dir: PathBuf, + media_driver_timeout_ms: i32, + resource_linger_timeout_ms: i32, + use_conductor_agent_invoker: bool, + pre_touch_mapped_memory: bool, +} + +impl Context { + pub fn get_user_name() -> String { + env::var("USER") + .or_else(|_| env::var("USERNAME")) + .unwrap_or("default".to_string()) + } + + pub fn default_aeron_path() -> PathBuf { + let base_path = if cfg!(target_os = "linux") { + PathBuf::from("/dev/shm") + } else { + // Uses TMPDIR on Unix-like, and GetTempPath on Windows + env::temp_dir() + }; + + base_path.join(format!("aeron-{}", Context::get_user_name())) + } +} + +impl Default for Context { + fn default() -> Self { + Context { + aeron_dir: Context::default_aeron_path(), + media_driver_timeout_ms: DEFAULT_MEDIA_DRIVER_TIMEOUT_MS.into(), + resource_linger_timeout_ms: DEFAULT_RESOURCE_LINGER_MS.into(), + use_conductor_agent_invoker: false, + pre_touch_mapped_memory: false, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index d195ab8..966a11a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ -//! Aeron client for Rust +//! [Aeron](https://github.com/real-logic/aeron) client for Rust #![deny(missing_docs)] +mod context; + /// Retrieve the C library version in (major, minor, patch) format pub fn aeron_version() -> (u32, u32, u32) { unsafe {