use serde::{Deserialize, Serialize};
use crate::{RmuxError, RMUX_WIRE_VERSION};
pub const CAPABILITY_DETACHED_RPC: &str = "rpc.detached";
pub const CAPABILITY_HANDSHAKE: &str = "protocol.capabilities";
pub const CAPABILITY_FRAMED_ERRORS: &str = "protocol.framed_errors";
pub const CAPABILITY_ATTACH_STREAM: &str = "stream.attach";
pub const CAPABILITY_CONTROL_STREAM: &str = "stream.control";
pub const CAPABILITY_DAEMON_SHUTDOWN: &str = "daemon.shutdown";
pub const CAPABILITY_SDK_WAITS: &str = "sdk.waits";
pub const SUPPORTED_CAPABILITIES: &[&str] = &[
CAPABILITY_DETACHED_RPC,
CAPABILITY_HANDSHAKE,
CAPABILITY_FRAMED_ERRORS,
CAPABILITY_ATTACH_STREAM,
CAPABILITY_CONTROL_STREAM,
CAPABILITY_DAEMON_SHUTDOWN,
CAPABILITY_SDK_WAITS,
];
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HandshakeRequest {
pub minimum_wire_version: u32,
pub maximum_wire_version: u32,
pub required_capabilities: Vec<String>,
}
impl HandshakeRequest {
#[must_use]
pub fn current() -> Self {
Self::requiring(std::iter::empty::<&str>())
}
#[must_use]
pub fn requiring<I, S>(required_capabilities: I) -> Self
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
Self {
minimum_wire_version: RMUX_WIRE_VERSION,
maximum_wire_version: RMUX_WIRE_VERSION,
required_capabilities: required_capabilities
.into_iter()
.map(|capability| capability.as_ref().to_owned())
.collect(),
}
}
pub fn validate_against(&self, supported_capabilities: &[&str]) -> Result<(), RmuxError> {
if self.minimum_wire_version > RMUX_WIRE_VERSION
|| self.maximum_wire_version < RMUX_WIRE_VERSION
{
return Err(RmuxError::UnsupportedWireVersion {
got: RMUX_WIRE_VERSION,
minimum: self.minimum_wire_version,
maximum: self.maximum_wire_version,
});
}
if let Some(feature) = self
.required_capabilities
.iter()
.find(|feature| !supported_capabilities.contains(&feature.as_str()))
{
return Err(RmuxError::UnsupportedCapability {
feature: feature.clone(),
supported: supported_capabilities
.iter()
.copied()
.map(str::to_owned)
.collect(),
});
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HandshakeResponse {
pub wire_version: u32,
pub capabilities: Vec<String>,
}
impl HandshakeResponse {
#[must_use]
pub fn current() -> Self {
Self {
wire_version: RMUX_WIRE_VERSION,
capabilities: SUPPORTED_CAPABILITIES
.iter()
.copied()
.map(str::to_owned)
.collect(),
}
}
}