use super::caller::Caller;
use crate::error::ServiceError;
use crate::host_identity::{
verify_peer_process, HostExpectation, HostIdentityError, HostIdentityReason, HostProcess,
};
use crate::peer::PeerIdentity;
use serde_json::Value;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
pub type Emit = Arc<dyn Fn(Value) + Send + Sync>;
#[derive(Clone)]
pub struct CallContext {
conn: u64,
caller: Caller,
pub(crate) closed: Arc<AtomicBool>,
handoff: Arc<AtomicBool>,
}
pub(crate) fn new_context(
conn: u64,
caller: Caller,
closed: Arc<AtomicBool>,
handoff: Arc<AtomicBool>,
) -> CallContext {
CallContext {
conn,
caller,
closed,
handoff,
}
}
impl CallContext {
pub fn conn_id(&self) -> u64 {
self.conn
}
pub fn origin(&self) -> &Caller {
&self.caller
}
pub fn role(&self) -> Option<&str> {
self.caller.role()
}
pub fn app(&self) -> &str {
self.caller.label()
}
pub fn peer(&self) -> Option<&PeerIdentity> {
self.caller.peer()
}
pub fn verify_peer_executable(
&self,
expect: &HostExpectation,
) -> Result<HostProcess, HostIdentityError> {
let host = verify_peer_process(self.peer(), expect)?;
if self.peer_closed() {
return Err(HostIdentityError {
expected: expect.executables().to_vec(),
found_pid: Some(host.pid),
found_executable: Some(host.executable),
reason: HostIdentityReason::HostChanged(
"the connection closed while the peer was identified".to_string(),
),
});
}
Ok(host)
}
pub fn peer_closed(&self) -> bool {
self.closed.load(Ordering::SeqCst)
}
pub fn handoff_requested(&self) -> bool {
self.handoff.load(Ordering::SeqCst)
}
}
pub trait Handler: Send + Sync + 'static {
fn call(
&self,
cx: &CallContext,
method: &str,
params: &Value,
emit: &Emit,
) -> Result<Value, ServiceError>;
fn on_handoff(&self) {}
fn connection_closed(&self, _conn: u64) {}
}