use iceoryx2_bb_container::queue::RelocatableContainer;
use iceoryx2_bb_elementary::CallbackProgression;
use iceoryx2_bb_lock_free::mpmc::{
container::{Container, ContainerHandle},
unique_index_set_enums::ReleaseMode,
};
use iceoryx2_bb_memory::bump_allocator::BumpAllocator;
use iceoryx2_log::{error, fatal_panic};
use crate::{
identifiers::{UniqueClientId, UniqueNodeId, UniquePortId, UniqueServerId},
port::details::data_segment::DataSegmentType,
};
use super::PortCleanupAction;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ServerDetails {
pub server_id: UniqueServerId,
pub node_id: UniqueNodeId,
pub request_buffer_size: usize,
pub number_of_responses: usize,
pub max_slice_len: usize,
pub data_segment_type: DataSegmentType,
pub max_number_of_segments: u8,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ClientDetails {
pub client_id: UniqueClientId,
pub node_id: UniqueNodeId,
pub number_of_requests: usize,
pub response_buffer_size: usize,
pub max_slice_len: usize,
pub data_segment_type: DataSegmentType,
pub max_number_of_segments: u8,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub(crate) struct DynamicConfigSettings {
pub number_of_servers: usize,
pub number_of_clients: usize,
}
#[repr(C)]
#[derive(Debug)]
pub struct DynamicConfig {
pub(crate) servers: Container<ServerDetails>,
pub(crate) clients: Container<ClientDetails>,
}
impl DynamicConfig {
pub(crate) fn new(config: &DynamicConfigSettings) -> Self {
Self {
servers: unsafe { Container::new_uninit(config.number_of_servers) },
clients: unsafe { Container::new_uninit(config.number_of_clients) },
}
}
pub(crate) unsafe fn init(&mut self, allocator: &BumpAllocator) {
unsafe {
fatal_panic!(from self,
when self.servers.init(allocator),
"This should never happen! Unable to initialize servers port id container.");
fatal_panic!(from self,
when self.clients.init(allocator),
"This should never happen! Unable to initialize clients port id container.");
}
}
pub(crate) fn memory_size(config: &DynamicConfigSettings) -> usize {
Container::<ServerDetails>::memory_size(config.number_of_servers)
+ Container::<ClientDetails>::memory_size(config.number_of_clients)
}
pub fn number_of_clients(&self) -> usize {
self.clients.len()
}
pub fn number_of_servers(&self) -> usize {
self.servers.len()
}
pub(crate) unsafe fn remove_dead_node_id<
PortCleanup: FnMut(UniquePortId) -> PortCleanupAction,
>(
&self,
node_id: &UniqueNodeId,
mut port_cleanup_callback: PortCleanup,
) {
unsafe {
self.servers.recover(
node_id.owner_id(),
|registered_server| {
registered_server.node_id == *node_id
&& port_cleanup_callback(UniquePortId::Server(registered_server.server_id))
== PortCleanupAction::RemovePort
},
ReleaseMode::Default,
);
self.clients.recover(
node_id.owner_id(),
|registered_client| {
registered_client.node_id == *node_id
&& port_cleanup_callback(UniquePortId::Client(registered_client.client_id))
== PortCleanupAction::RemovePort
},
ReleaseMode::Default,
);
}
}
pub(crate) fn add_client_id(&self, details: ClientDetails) -> Option<ContainerHandle> {
unsafe { self.clients.add(details, details.node_id.owner_id()).ok() }
}
pub(crate) fn release_client_handle(&self, handle: ContainerHandle) {
if let Err(e) = unsafe { self.clients.remove(handle, ReleaseMode::Default) } {
error!(from self, "Unable to deregister client from service. This could indicate a corrupted system! [{e:?}]");
}
}
pub(crate) fn add_server_id(&self, details: ServerDetails) -> Option<ContainerHandle> {
unsafe { self.servers.add(details, details.node_id.owner_id()).ok() }
}
pub(crate) fn release_server_handle(&self, handle: ContainerHandle) {
if let Err(e) = unsafe { self.servers.remove(handle, ReleaseMode::Default) } {
error!(from self, "Unable to deregister server from service. This could indicate a corrupted system! [{e:?}]");
}
}
pub fn list_servers<F: FnMut(&ServerDetails) -> CallbackProgression>(&self, mut callback: F) {
let state = unsafe { self.servers.get_state() };
state.for_each(|_, details| callback(details));
}
pub fn list_clients<F: FnMut(&ClientDetails) -> CallbackProgression>(&self, mut callback: F) {
let state = unsafe { self.clients.get_state() };
state.for_each(|_, details| callback(details));
}
}