use super::{ConnectionControl, ConnectionRuntime, PushReplyAwaiter, ServerError, lock};
use std::sync::{Arc, Weak};
pub(in crate::server::connection) struct RoutedPush {
pub(in crate::server::connection) awaiter: PushReplyAwaiter,
pub(in crate::server::connection) station: Option<Arc<str>>,
}
impl ConnectionRuntime {
pub(in crate::server::connection) fn route_push(
&self,
pid: u64,
subject: &str,
payload: Vec<u8>,
wake: Option<crate::server::connection::wake::ReadyWaker>,
) -> Result<RoutedPush, ServerError> {
let station = self.route_station(pid);
let correlation_id = self.next_push_correlation_id();
let receiver =
self.register_push(pid, correlation_id, None, Some(subject.to_owned()), wake)?;
if !self.confirm_push_registration(pid, correlation_id) {
return Err(ServerError::ListenerAccept {
message: format!(
"cannot route to connection process {pid}: the connection closed during push registration"
),
});
}
let Some(scheduler) = self.scheduler.upgrade() else {
self.cancel_push(correlation_id);
return Err(ServerError::ListenerAccept {
message: format!(
"cannot route to connection process {pid}: the connection scheduler is gone"
),
});
};
let control = ConnectionControl::Push {
correlation_id,
payload,
};
if self.publish_control(&scheduler, pid, control) {
Ok(RoutedPush {
station,
awaiter: PushReplyAwaiter {
correlation_id,
receiver,
deadline: None,
runtime: Weak::new(),
},
})
} else {
self.cancel_push(correlation_id);
Err(ServerError::ListenerAccept {
message: format!(
"cannot route to connection process {pid}: the control was not published"
),
})
}
}
fn route_station(&self, pid: u64) -> Option<Arc<str>> {
let console = self.signals.get()?.console()?;
let recorded = lock(&self.records, "connection registry").map(|records| {
records
.connections
.get(&pid)
.and_then(|record| record.registration.as_ref())
.filter(|registration| console.tap().reserved(®istration.identity).is_none())
.map(|registration| Arc::from(registration.identity.as_str()))
});
match recorded {
Ok(station) => station,
Err(error) => {
console.observe_failed();
tracing::warn!(%error, "SERVICE_TAP_TARGET_FAILED");
None
}
}
}
}