#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub struct SsdpMessage {
pub kind: SsdpKind,
pub host: Option<String>,
pub nt: Option<String>,
pub nts: Option<String>,
pub st: Option<String>,
pub usn: Option<String>,
pub location: Option<String>,
pub server: Option<String>,
pub cache_control_max_age: Option<u32>,
pub user_agent: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
serde(tag = "kind", content = "value", rename_all = "snake_case")
)]
#[non_exhaustive]
pub enum SsdpKind {
Notify,
MSearch,
Response,
}
impl SsdpKind {
pub fn as_str(self) -> &'static str {
match self {
SsdpKind::Notify => "notify",
SsdpKind::MSearch => "m_search",
SsdpKind::Response => "response",
}
}
}
impl SsdpMessage {
#[inline]
pub fn is_byebye(&self) -> bool {
matches!(self.kind, SsdpKind::Notify)
&& self
.nts
.as_deref()
.map(|s| s.eq_ignore_ascii_case("ssdp:byebye"))
.unwrap_or(false)
}
#[inline]
pub fn is_alive(&self) -> bool {
matches!(self.kind, SsdpKind::Notify)
&& self
.nts
.as_deref()
.map(|s| s.eq_ignore_ascii_case("ssdp:alive"))
.unwrap_or(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kind_slugs_locked() {
assert_eq!(SsdpKind::Notify.as_str(), "notify");
assert_eq!(SsdpKind::MSearch.as_str(), "m_search");
assert_eq!(SsdpKind::Response.as_str(), "response");
}
#[test]
fn is_byebye_only_fires_on_notify_byebye() {
let mut m = SsdpMessage {
kind: SsdpKind::Notify,
host: None,
nt: None,
nts: Some("ssdp:byebye".into()),
st: None,
usn: None,
location: None,
server: None,
cache_control_max_age: None,
user_agent: None,
};
assert!(m.is_byebye());
assert!(!m.is_alive());
m.nts = Some("ssdp:alive".into());
assert!(!m.is_byebye());
assert!(m.is_alive());
m.kind = SsdpKind::Response;
assert!(!m.is_alive());
}
#[test]
fn nts_check_is_case_insensitive() {
let m = SsdpMessage {
kind: SsdpKind::Notify,
host: None,
nt: None,
nts: Some("SSDP:ALIVE".into()),
st: None,
usn: None,
location: None,
server: None,
cache_control_max_age: None,
user_agent: None,
};
assert!(m.is_alive());
}
}