use super::{headermap::HeaderMap, status::Status}; use anyhow::{anyhow, bail, Context}; use std::{fmt::Display, str::FromStr}; #[derive(Debug, Clone)] pub struct Response { pub status: Status, pub headers: HeaderMap, } impl FromStr for Response { type Err = anyhow::Error; fn from_str(s: &str) -> Result { let mut lines = s.lines(); let statusline = lines.next().ok_or(anyhow!("status line missing"))?; let (sipver, rest) = statusline .split_once(" ") .ok_or(anyhow!("status line malformed"))?; let (code, _status_str) = rest .split_once(" ") .ok_or(anyhow!("status line malformed"))?; let code = u16::from_str(code).context("status code")?; let Some(ver) = sipver.strip_prefix("SIP/") else { bail!("sip version malformed"); }; if ver != "2.0" { bail!("sip version {ver:?} is not supported"); } let headers = HeaderMap::parse(&mut lines)?; let status = Status::from_code(code); Ok(Self { status, headers }) } } impl Display for Response { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Self { status, headers } = self; write!(f, "SIP/2.0 {} {status:?}\r\n", status.to_code())?; write!(f, "{headers}\r\n")?; Ok(()) } }