use bytes::Bytes;
use serde_json::Value;
use crate::error::{EnigmaRtcError, RtcResult};
use crate::types::SignalingMessage;
pub fn encode_signaling(message: &SignalingMessage) -> String {
match serde_json::to_string(message) {
Ok(json) => json,
Err(_) => "{\"type\":\"hangup\",\"reason\":\"serialization_error\"}".to_string(),
}
}
pub fn decode_signaling(payload: &str) -> RtcResult<SignalingMessage> {
let buffer = Bytes::copy_from_slice(payload.as_bytes());
let value: Value = serde_json::from_slice(buffer.as_ref())
.map_err(|e| EnigmaRtcError::JsonError(e.to_string()))?;
let message_type = value
.get("type")
.and_then(Value::as_str)
.ok_or_else(|| EnigmaRtcError::JsonError("missing type".into()))?;
match message_type {
"offer" => parse_offer(&value),
"answer" => parse_answer(&value),
"ice_candidate" => parse_candidate(&value),
"hangup" => parse_hangup(&value),
_ => Err(EnigmaRtcError::JsonError("unknown message type".into())),
}
}
fn parse_offer(value: &Value) -> RtcResult<SignalingMessage> {
let sdp = extract_string(value, "sdp")?;
if sdp.trim().is_empty() {
return Err(EnigmaRtcError::InvalidSdp);
}
Ok(SignalingMessage::Offer { sdp })
}
fn parse_answer(value: &Value) -> RtcResult<SignalingMessage> {
let sdp = extract_string(value, "sdp")?;
if sdp.trim().is_empty() {
return Err(EnigmaRtcError::InvalidSdp);
}
Ok(SignalingMessage::Answer { sdp })
}
fn parse_candidate(value: &Value) -> RtcResult<SignalingMessage> {
let candidate = extract_string(value, "candidate")?;
if candidate.trim().is_empty() {
return Err(EnigmaRtcError::InvalidCandidate);
}
let sdp_mid = value
.get("sdp_mid")
.and_then(Value::as_str)
.map(|s| s.to_string());
let sdp_mline_index = match value.get("sdp_mline_index") {
Some(v) => Some(
v.as_u64()
.ok_or_else(|| EnigmaRtcError::JsonError("invalid sdp_mline_index".into()))?
as u16,
),
None => None,
};
Ok(SignalingMessage::IceCandidate {
candidate,
sdp_mid,
sdp_mline_index,
})
}
fn parse_hangup(value: &Value) -> RtcResult<SignalingMessage> {
let reason = value
.get("reason")
.and_then(Value::as_str)
.map(|s| s.to_string());
Ok(SignalingMessage::Hangup { reason })
}
fn extract_string(value: &Value, key: &str) -> RtcResult<String> {
value
.get(key)
.and_then(Value::as_str)
.map(|s| s.to_string())
.ok_or_else(|| EnigmaRtcError::JsonError(format!("missing {key}")))
}