extern crate alloc;
use core::fmt::Debug;
use core::time::Duration;
use iceoryx2_bb_elementary::CallbackProgression;
use iceoryx2_bb_elementary_traits::testing::abandonable::Abandonable;
use iceoryx2_log::{debug, warn};
use crate::config::Config;
use crate::identifiers::UniqueServiceId;
use crate::node::{CleanupState, NodeCleanupFailure, NodeListFailure, NodeState, NodeView};
use crate::service::service_hash::ServiceHash;
use super::dynamic_config::DynamicConfig;
use super::{attribute::AttributeSet, service_name::ServiceName};
pub mod blackboard;
pub mod reader;
pub mod writer;
pub mod request_response;
pub mod client;
pub mod server;
pub mod event;
pub mod listener;
pub mod notifier;
pub mod publish_subscribe;
pub mod publisher;
pub mod subscriber;
pub trait PortFactory: Debug + Abandonable {
type Service: crate::service::Service;
type StaticConfig;
type DynamicConfig;
fn name(&self) -> &ServiceName;
fn unique_service_id(&self) -> UniqueServiceId;
fn service_hash(&self) -> &ServiceHash;
fn attributes(&self) -> &AttributeSet;
fn static_config(&self) -> &Self::StaticConfig;
fn dynamic_config(&self) -> &Self::DynamicConfig;
fn nodes<F: FnMut(NodeState<Self::Service>) -> CallbackProgression>(
&self,
callback: F,
) -> Result<(), NodeListFailure>;
fn try_cleanup_dead_nodes(&self) -> CleanupState {
blocking_cleanup_dead_nodes_in_service(self, Duration::ZERO)
}
fn blocking_cleanup_dead_nodes(&self, timeout: Duration) -> CleanupState {
blocking_cleanup_dead_nodes_in_service(self, timeout)
}
}
pub(crate) fn blocking_cleanup_dead_nodes_in_service<T: PortFactory>(
port_factory: &T,
timeout: Duration,
) -> CleanupState {
let mut cleanup_state = CleanupState {
failed_cleanups: 0,
cleanups: 0,
};
if let Err(e) = port_factory.nodes(|node_state| {
if let NodeState::Dead(node) = node_state {
let node_id = *node.id();
debug!(from port_factory, "Dead node ({:?}) detected", node_id);
match node.blocking_remove_stale_resources(timeout) {
Ok(()) => cleanup_state.cleanups +=1,
Err(NodeCleanupFailure::AnotherInstanceIsCleaningUpTheNode) => {
cleanup_state.failed_cleanups += 1;
warn!(from port_factory,
"Stop waiting on another process to cleanup the dead node ({:?}) since the {timeout:?} expired. Abandoned ports of the dead node might block the creation of new ports! Try increasing the `global.node.creation_timeout` config parameter to mitigate this problem.",
node_id);
}
Err(e) => {
cleanup_state.failed_cleanups += 1;
warn!(from port_factory,
"Failed to remove dead node ({:?}) from service. Abandoned ports of the dead node might block the creation of new ports! [{e:?}]",
node_id);
}
}
}
CallbackProgression::Continue
}) {
warn!(from port_factory,
"Unable to iterate through service nodes to detect dead nodes. This might cause that abandoned ports of dead nodes block the creation of new ports! [{e:?}]");
}
cleanup_state
}
pub(crate) fn nodes<
Service: crate::service::Service,
F: FnMut(NodeState<Service>) -> CallbackProgression,
>(
dynamic_config: &DynamicConfig,
config: &Config,
mut callback: F,
) -> Result<(), NodeListFailure> {
let mut ret_val = Ok(());
dynamic_config.list_node_ids(|node_id| {
match crate::node::NodeState::<Service>::new(node_id, config) {
Ok(Some(node_state)) => callback(node_state),
Ok(None) => CallbackProgression::Continue,
Err(e) => {
ret_val = Err(e);
CallbackProgression::Stop
}
}
});
ret_val
}