use std::sync::{Arc, Mutex};
use crate::atom::Atom;
use crate::distribution::control_lifecycle::ControlOp;
use crate::process::{ExitReason, RemotePid};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum RemoteLinkError {
NoConnection,
BadTarget,
}
pub trait DistributionControlFacility: Send + Sync {
fn link_remote(&self, caller_pid: u64, target: RemotePid) -> Result<(), RemoteLinkError>;
fn unlink_remote(&self, caller_pid: u64, target: RemotePid) -> Result<(), RemoteLinkError>;
fn exit_remote(
&self,
caller_pid: u64,
target: RemotePid,
reason: ExitReason,
) -> Result<(), RemoteLinkError>;
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ControlMessage {
pub op: ControlOp,
pub from: RemotePid,
pub to: RemotePid,
pub reason: Option<ExitReason>,
}
#[derive(Clone, Debug, Default)]
pub struct ControlRouter {
messages: Arc<Mutex<Vec<ControlMessage>>>,
}
impl ControlRouter {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn send_link(&self, local_node: Atom, caller_pid: u64, target: RemotePid) {
self.push(ControlMessage {
op: ControlOp::Link,
from: local_remote_pid(local_node, caller_pid),
to: target,
reason: None,
});
}
pub fn send_unlink(&self, local_node: Atom, caller_pid: u64, target: RemotePid) {
self.push(ControlMessage {
op: ControlOp::Unlink,
from: local_remote_pid(local_node, caller_pid),
to: target,
reason: None,
});
}
pub fn send_exit(
&self,
local_node: Atom,
caller_pid: u64,
target: RemotePid,
reason: ExitReason,
) {
self.push(ControlMessage {
op: ControlOp::Exit,
from: local_remote_pid(local_node, caller_pid),
to: target,
reason: Some(reason),
});
}
#[must_use]
pub fn messages(&self) -> Vec<ControlMessage> {
self.messages
.lock()
.unwrap_or_else(|error| error.into_inner())
.clone()
}
fn push(&self, message: ControlMessage) {
self.messages
.lock()
.unwrap_or_else(|error| error.into_inner())
.push(message);
}
}
fn local_remote_pid(local_node: Atom, pid_number: u64) -> RemotePid {
RemotePid {
node: local_node,
pid_number,
serial: 0,
}
}