use std::env;
use std::ffi::CString;
use std::sync::Arc;
use crate::cnc_file_descriptor;
use crate::concurrent::counters::CountersReader;
use crate::concurrent::logbuffer::term_reader::ErrorHandler;
use crate::concurrent::ring_buffer::ManyToOneRingBuffer;
use crate::driver_proxy::DriverProxy;
use crate::image::Image;
use crate::utils::errors::{AeronError, GenericError};
use crate::utils::memory_mapped_file::MemoryMappedFile;
use crate::utils::misc::{semantic_version_major, semantic_version_to_string};
use crate::utils::types::{Index, Moment};
const AGENT_NAME: &str = "client-conductor";
pub const NULL_VALUE: i32 = -1;
pub trait OnAvailableImage {
fn call(&self, image: &Image);
fn clone_box(&self) -> Box<dyn OnAvailableImage>;
}
impl<T> OnAvailableImage for T
where
T: Fn(&Image) + Clone + 'static,
{
fn clone_box(&self) -> Box<dyn OnAvailableImage> {
Box::new(self.clone())
}
fn call(&self, image: &Image) {
self(image)
}
}
impl Clone for Box<dyn OnAvailableImage> {
fn clone(&self) -> Box<dyn OnAvailableImage> {
self.clone_box()
}
}
pub trait OnUnavailableImage {
fn call(&self, image: &Image);
fn clone_box(&self) -> Box<dyn OnUnavailableImage>;
}
impl Clone for Box<dyn OnUnavailableImage> {
fn clone(&self) -> Box<dyn OnUnavailableImage> {
self.clone_box()
}
}
impl<F> OnUnavailableImage for F
where
F: Fn(&Image) + Clone + 'static,
{
fn call(&self, image: &Image) {
self(image)
}
fn clone_box(&self) -> Box<dyn OnUnavailableImage> {
Box::new(self.clone())
}
}
pub trait OnNewPublication {
fn call(&self, channel: CString, stream_id: i32, session_id: i32, correlation_id: i64);
fn clone_box(&self) -> Box<dyn OnNewPublication>;
}
impl Clone for Box<dyn OnNewPublication> {
fn clone(&self) -> Box<dyn OnNewPublication> {
self.clone_box()
}
}
impl<F> OnNewPublication for F
where
F: Fn(CString, i32, i32, i64) + Clone + 'static,
{
fn call(&self, channel: CString, stream_id: i32, session_id: i32, correlation_id: i64) {
self(channel, stream_id, session_id, correlation_id)
}
fn clone_box(&self) -> Box<dyn OnNewPublication> {
Box::new(self.clone())
}
}
pub trait OnNewSubscription {
fn call(&self, channel: CString, stream_id: i32, correlation_id: i64);
fn clone_box(&self) -> Box<dyn OnNewSubscription>;
}
impl Clone for Box<dyn OnNewSubscription> {
fn clone(&self) -> Box<dyn OnNewSubscription> {
self.clone_box()
}
}
impl<F> OnNewSubscription for F
where
F: Fn(CString, i32, i64) + Clone + 'static,
{
fn call(&self, channel: CString, stream_id: i32, correlation_id: i64) {
self(channel, stream_id, correlation_id)
}
fn clone_box(&self) -> Box<dyn OnNewSubscription> {
Box::new(self.clone())
}
}
pub trait OnAvailableCounter {
fn call(&self, counters_reader: &CountersReader, registration_id: i64, counter_id: i32);
fn clone_box(&self) -> Box<dyn OnAvailableCounter>;
}
impl Clone for Box<dyn OnAvailableCounter> {
fn clone(&self) -> Box<dyn OnAvailableCounter> {
self.clone_box()
}
}
impl<F> OnAvailableCounter for F
where
F: Fn(&CountersReader, i64, i32) + Clone + 'static,
{
fn call(&self, counters_reader: &CountersReader, registration_id: i64, counter_id: i32) {
self(counters_reader, registration_id, counter_id)
}
fn clone_box(&self) -> Box<dyn OnAvailableCounter> {
Box::new(self.clone())
}
}
pub trait OnUnavailableCounter {
fn call(&self, counters_reader: &CountersReader, registration_id: i64, counter_id: i32);
fn clone_box(&self) -> Box<dyn OnUnavailableCounter>;
}
impl Clone for Box<dyn OnUnavailableCounter> {
fn clone(&self) -> Box<dyn OnUnavailableCounter> {
self.clone_box()
}
}
impl<F> OnUnavailableCounter for F
where
F: Fn(&CountersReader, i64, i32) + Clone + 'static,
{
fn call(&self, counters_reader: &CountersReader, registration_id: i64, counter_id: i32) {
self(counters_reader, registration_id, counter_id)
}
fn clone_box(&self) -> Box<dyn OnUnavailableCounter> {
Box::new(self.clone())
}
}
pub trait OnCloseClient {
fn call(&self);
fn clone_box(&self) -> Box<dyn OnCloseClient>;
}
impl Clone for Box<dyn OnCloseClient> {
fn clone(&self) -> Box<dyn OnCloseClient> {
self.clone_box()
}
}
impl<F> OnCloseClient for F
where
F: Fn() + Clone + 'static,
{
fn call(&self) {
self()
}
fn clone_box(&self) -> Box<dyn OnCloseClient> {
Box::new(self.clone())
}
}
const DEFAULT_MEDIA_DRIVER_TIMEOUT_MS: Moment = 10000;
const DEFAULT_RESOURCE_LINGER_MS: Moment = 5000;
fn default_error_handler(exception: AeronError) {
panic!("AeronError: {:?}", exception);
}
fn default_on_new_publication_handler(_channel: CString, _stream_id: i32, _session_id: i32, _correlation_id: i64) {}
fn default_on_available_image_handler(_img: &Image) {}
fn default_on_new_subscription_handler(_channel: CString, _stream_id: i32, _correlation_id: i64) {}
fn default_on_unavailable_image_handler(_img: &Image) {}
fn default_on_available_counter_handler(_counters_reader: &CountersReader, _registration_id: i64, _counter_id: i32) {}
fn default_on_unavailable_counter_handler(_counters_reader: &CountersReader, _registration_id: i64, _counter_id: i32) {}
fn default_on_close_client_handler() {}
#[derive(Clone)]
pub struct Context {
dir_name: String,
error_handler: Box<dyn ErrorHandler + Send>,
on_new_publication_handler: Box<dyn OnNewPublication>,
on_new_exclusive_publication_handler: Box<dyn OnNewPublication>,
on_new_subscription_handler: Box<dyn OnNewSubscription>,
on_available_image_handler: Box<dyn OnAvailableImage>,
on_unavailable_image_handler: Box<dyn OnUnavailableImage>,
on_available_counter_handler: Box<dyn OnAvailableCounter>,
on_unavailable_counter_handler: Box<dyn OnUnavailableCounter>,
on_close_client_handler: Box<dyn OnCloseClient>,
media_driver_timeout: Moment,
resource_linger_timeout: Moment,
use_conductor_agent_invoker: bool,
is_on_new_exclusive_publication_handler_set: bool,
pre_touch_mapped_memory: bool,
agent_name: String,
conductor_cpu_affinity: Option<usize>,
}
unsafe impl Send for Context {}
unsafe impl Sync for Context {}
impl Default for Context {
fn default() -> Self {
Self::new()
}
}
impl Context {
pub fn new() -> Self {
Self {
dir_name: Context::default_aeron_path(),
error_handler: Box::new(default_error_handler),
on_new_publication_handler: Box::new(default_on_new_publication_handler),
on_new_exclusive_publication_handler: Box::new(default_on_new_publication_handler),
on_new_subscription_handler: Box::new(default_on_new_subscription_handler),
on_available_image_handler: Box::new(default_on_available_image_handler),
on_unavailable_image_handler: Box::new(default_on_unavailable_image_handler),
on_available_counter_handler: Box::new(default_on_available_counter_handler),
on_unavailable_counter_handler: Box::new(default_on_unavailable_counter_handler),
on_close_client_handler: Box::new(default_on_close_client_handler),
media_driver_timeout: DEFAULT_MEDIA_DRIVER_TIMEOUT_MS,
resource_linger_timeout: DEFAULT_RESOURCE_LINGER_MS,
use_conductor_agent_invoker: false,
is_on_new_exclusive_publication_handler_set: false,
pre_touch_mapped_memory: false,
agent_name: String::from(AGENT_NAME),
conductor_cpu_affinity: None,
}
}
pub fn conclude(&mut self) -> &Self {
if !self.is_on_new_exclusive_publication_handler_set {
self.on_new_exclusive_publication_handler = self.on_new_publication_handler.clone_box();
}
self
}
pub fn agent_name(&self) -> String {
self.agent_name.clone()
}
pub fn set_agent_name(&mut self, name: &str) {
self.agent_name = String::from(name);
}
pub fn set_aeron_dir(&mut self, directory: String) -> &Self {
self.dir_name = directory;
self
}
pub fn aeron_dir(&self) -> String {
self.dir_name.clone()
}
pub fn cnc_file_name(&self) -> String {
self.dir_name.clone() + "/" + cnc_file_descriptor::CNC_FILE
}
pub fn set_error_handler(&mut self, handler: impl ErrorHandler + Send + 'static) -> &Self {
self.error_handler = Box::new(handler);
self
}
pub fn error_handler(&self) -> Box<dyn ErrorHandler + Send + 'static> {
self.error_handler.clone()
}
pub fn set_new_publication_handler(&mut self, handler: impl OnNewPublication + 'static) -> &Self {
self.on_new_publication_handler = Box::new(handler);
self
}
pub fn new_publication_handler(&self) -> Box<dyn OnNewPublication> {
self.on_new_publication_handler.clone_box()
}
pub fn set_new_exclusive_publication_handler(&mut self, handler: Box<dyn OnNewPublication>) -> &Self {
self.on_new_exclusive_publication_handler = handler;
self.is_on_new_exclusive_publication_handler_set = true;
self
}
pub fn new_exclusive_publication_handler(&self) -> Box<dyn OnNewPublication> {
self.on_new_exclusive_publication_handler.clone_box()
}
pub fn set_new_subscription_handler(&mut self, handler: impl OnNewSubscription + 'static) -> &Self {
self.on_new_subscription_handler = Box::new(handler);
self
}
pub fn new_subscription_handler(&self) -> Box<dyn OnNewSubscription> {
self.on_new_subscription_handler.clone_box()
}
pub fn set_available_image_handler(&mut self, handler: impl OnAvailableImage + 'static) -> &Self {
self.on_available_image_handler = Box::new(handler);
self
}
pub fn available_image_handler(&self) -> Box<dyn OnAvailableImage> {
self.on_available_image_handler.clone_box()
}
pub fn set_unavailable_image_handler(&mut self, handler: impl OnUnavailableImage + 'static) -> &Self {
self.on_unavailable_image_handler = Box::new(handler);
self
}
pub fn unavailable_image_handler(&self) -> Box<dyn OnUnavailableImage> {
self.on_unavailable_image_handler.clone_box()
}
pub fn set_available_counter_handler(&mut self, handler: impl OnAvailableCounter + 'static) -> &Self {
self.on_available_counter_handler = Box::new(handler);
self
}
pub fn available_counter_handler(&self) -> Box<dyn OnAvailableCounter> {
self.on_available_counter_handler.clone_box()
}
pub fn set_unavailable_counter_handler(&mut self, handler: impl OnUnavailableCounter + 'static) -> &Self {
self.on_unavailable_counter_handler = Box::new(handler);
self
}
pub fn unavailable_counter_handler(&self) -> Box<dyn OnUnavailableCounter> {
self.on_unavailable_counter_handler.clone_box()
}
pub fn set_close_client_handler(&mut self, handler: impl OnCloseClient + 'static) -> &Self {
self.on_close_client_handler = Box::new(handler);
self
}
pub fn close_client_handler(&self) -> Box<dyn OnCloseClient> {
self.on_close_client_handler.clone_box()
}
pub fn set_media_driver_timeout(&mut self, value: Moment) -> &Self {
self.media_driver_timeout = value;
self
}
pub fn media_driver_timeout(&self) -> Moment {
self.media_driver_timeout
}
pub fn set_resource_linger_timeout(&mut self, value: Moment) -> &Self {
self.resource_linger_timeout = value;
self
}
pub fn resource_linger_timeout(&self) -> Moment {
self.resource_linger_timeout
}
pub fn set_use_conductor_agent_invoker(&mut self, use_conductor_agent_invoker: bool) -> &Self {
self.use_conductor_agent_invoker = use_conductor_agent_invoker;
self
}
pub fn use_conductor_agent_invoker(&self) -> bool {
self.use_conductor_agent_invoker
}
pub fn set_conductor_cpu_affinity(&mut self, cpu_id: usize) -> &Self {
self.conductor_cpu_affinity = Some(cpu_id);
self
}
pub fn conductor_cpu_affinity(&self) -> Option<usize> {
self.conductor_cpu_affinity
}
pub fn set_pre_touch_mapped_memory(&mut self, pre_touch_mapped_memory: bool) -> &Self {
self.pre_touch_mapped_memory = pre_touch_mapped_memory;
self
}
pub fn pre_touch_mapped_memory(&self) -> bool {
self.pre_touch_mapped_memory
}
pub unsafe fn request_driver_termination(
directory: &str,
token_buffer: *mut u8,
token_length: Index,
) -> Result<(), AeronError> {
let cnc_filename = String::from(directory) + "/" + cnc_file_descriptor::CNC_FILE;
if MemoryMappedFile::get_file_size(cnc_filename.clone()).expect("Error getting CnC file size") > 0 {
let cnc_file = MemoryMappedFile::map_existing(cnc_filename, false).expect("Unable to map file");
let cnc_version = cnc_file_descriptor::cnc_version_volatile(&cnc_file);
if semantic_version_major(cnc_version) != semantic_version_major(cnc_file_descriptor::CNC_VERSION) {
return Err(GenericError::CncVersionDoesntMatch {
app_version: semantic_version_to_string(cnc_file_descriptor::CNC_VERSION),
file_version: semantic_version_to_string(cnc_version),
}
.into());
}
let to_driver_buffer = cnc_file_descriptor::create_to_driver_buffer(&cnc_file);
let ring_buffer = ManyToOneRingBuffer::new(to_driver_buffer).expect("ManyToOneRingBuffer creation failed");
let driver_proxy = DriverProxy::new(Arc::new(ring_buffer));
unsafe {
driver_proxy.terminate_driver(token_buffer, token_length)?;
}
}
Ok(())
}
pub fn tmp_dir() -> String {
let mut dir = String::from("/tmp");
if let Ok(env_dir) = env::var("TMPDIR") {
dir = env_dir;
}
dir
}
pub fn get_user_name() -> String {
if let Ok(user) = env::var("USER") {
user
} else {
String::from("default")
}
}
pub fn default_aeron_path() -> String {
String::from("/dev/shm/aeron-") + &Context::get_user_name()
}
}