use crate::node::Node; use crate::routing::TopicPath;
use crate::services::PublishOptions; use crate::NodeDelegate; use anyhow::Result;
use runar_common::logging::{Component, Logger, LoggingContext}; use runar_macros_common::{log_debug, log_error, log_info, log_warn};
use runar_serializer::arc_value::AsArcValue;
use runar_serializer::ArcValue;
use std::fmt;
use std::sync::Arc;
pub struct EventContext {
pub topic_path: TopicPath,
pub logger: Arc<Logger>,
pub(crate) node_delegate: Arc<Node>,
pub delivery_options: Option<PublishOptions>,
is_local: bool,
}
impl fmt::Debug for EventContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EventContext")
.field("topic_path", &self.topic_path)
.field("logger", &"<Logger>") .field("delivery_options", &self.delivery_options)
.finish()
}
}
impl Clone for EventContext {
fn clone(&self) -> Self {
panic!("EventContext should not be cloned directly. Use new instead");
}
}
impl Default for EventContext {
fn default() -> Self {
panic!("EventContext should not be created with default. Use new instead");
}
}
impl EventContext {
pub fn new(
topic_path: &TopicPath,
node_delegate: Arc<Node>,
is_local: bool,
logger: Arc<Logger>,
) -> Self {
let event_path = topic_path.action_path();
let event_logger = if !event_path.is_empty() {
Arc::new(logger.with_event_path(event_path))
} else {
logger
};
Self {
topic_path: topic_path.clone(),
logger: event_logger,
node_delegate,
delivery_options: None,
is_local,
}
}
pub fn with_node_delegate(mut self, delegate: Arc<Node>) -> Self {
self.node_delegate = delegate;
self
}
pub fn with_delivery_options(mut self, options: PublishOptions) -> Self {
self.delivery_options = Some(options);
self
}
pub fn debug(&self, message: impl Into<String>) {
log_debug!(self.logger, "{}", message.into());
}
pub fn info(&self, message: impl Into<String>) {
log_info!(self.logger, "{}", message.into());
}
pub fn warn(&self, message: impl Into<String>) {
log_warn!(self.logger, "{}", message.into());
}
pub fn error(&self, message: impl Into<String>) {
log_error!(self.logger, "{}", message.into());
}
pub fn is_local(&self) -> bool {
self.is_local
}
pub async fn publish(&self, topic: &str, data: Option<ArcValue>) -> Result<()> {
let topic_string = topic.to_string();
let full_topic = if topic_string.contains(':') {
topic_string
} else if topic_string.contains('/') {
format!(
"{network_id}:{topic_string}",
network_id = self.topic_path.network_id()
)
} else {
format!(
"{}:{}/{}",
self.topic_path.network_id(),
self.topic_path.service_path(),
topic_string
)
};
self.logger
.debug(format!("Publishing to processed topic: {full_topic}"));
self.node_delegate.publish(&full_topic, data).await
}
pub async fn remote_request<P>(
&self,
path: impl Into<String>,
payload: Option<P>,
) -> Result<ArcValue>
where
P: AsArcValue + Send + Sync,
{
let path_string = path.into();
let full_path = if path_string.contains(':') {
path_string
} else if path_string.contains('/') {
format!(
"{network_id}:{path_string}",
network_id = self.topic_path.network_id()
)
} else {
format!(
"{}:{}/{}",
self.topic_path.network_id(),
self.topic_path.service_path(),
path_string
)
};
log_debug!(self.logger, "Making request to processed path: {full_path}");
self.node_delegate
.remote_request::<P>(&full_path, payload)
.await
}
pub async fn request<P>(&self, path: &str, payload: Option<P>) -> Result<ArcValue>
where
P: AsArcValue + Send + Sync,
{
let path_string = path.to_string();
let full_path = if path_string.contains(':') {
path_string
} else if path_string.contains('/') {
format!(
"{network_id}:{path_string}",
network_id = self.topic_path.network_id()
)
} else {
format!(
"{}:{}/{}",
self.topic_path.network_id(),
self.topic_path.service_path(),
path_string
)
};
log_debug!(self.logger, "Making request to processed path: {full_path}");
self.node_delegate.request::<P>(&full_path, payload).await
}
pub async fn on(
&self,
topic: impl Into<String>,
options: Option<crate::services::OnOptions>,
) -> Result<Option<ArcValue>> {
let handle = self.node_delegate.on(topic, options);
let inner = handle.await.map_err(|e| anyhow::anyhow!(e))?;
inner
}
}
impl LoggingContext for EventContext {
fn component(&self) -> Component {
Component::Service
}
fn service_path(&self) -> Option<&str> {
let path = self.topic_path.service_path();
Some(Box::leak(path.into_boxed_str()))
}
fn event_path(&self) -> Option<&str> {
self.logger.event_path()
}
fn logger(&self) -> &Logger {
&self.logger
}
}