use serde::{Deserialize, Serialize};
pub const WHEP_CAPABILITY: &str = "video.whep.relay";
pub const WHEP_OFFER_METHOD: &str = "video.whep.offer";
pub const WHEP_CLOSE_METHOD: &str = "video.whep.close";
pub const RIG_CAPABILITY: &str = "sensors.rig.write";
pub const RIG_WRITE_METHOD: &str = "sensors.rig.write";
pub const WHEP_UNAVAILABLE: &str = "whep_unavailable";
pub const UNKNOWN_CAMERA: &str = "unknown_camera";
pub const RIG_UNAVAILABLE: &str = "rig_unavailable";
pub const MAX_SDP_BYTES: usize = 64 * 1024;
pub const MAX_RIG_BYTES: usize = 256 * 1024;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct WhepOfferRequest {
pub camera_id: String,
pub sdp: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct WhepOfferReply {
pub sdp: String,
pub location: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct WhepCloseRequest {
pub location: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RigWriteRequest {
pub rig_json: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RigWriteReply {
pub status: u16,
pub body_json: String,
}
pub fn is_path_segment(s: &str) -> bool {
!s.is_empty()
&& s.bytes()
.all(|b| b.is_ascii_alphanumeric() || matches!(b, b'_' | b'-'))
}
pub fn whep_location(camera: &str, session: &str) -> String {
format!("/whep/{session}?camera={camera}")
}
pub fn parse_whep_location(location: &str) -> Option<(String, String)> {
let rest = location.strip_prefix("/whep/")?;
let (session, query) = rest.split_once("?camera=")?;
(is_path_segment(session) && is_path_segment(query))
.then(|| (query.to_string(), session.to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_location_round_trips() {
let loc = whep_location("main", "a1-b_2");
assert_eq!(loc, "/whep/a1-b_2?camera=main");
assert_eq!(
parse_whep_location(&loc),
Some(("main".into(), "a1-b_2".into()))
);
}
#[test]
fn a_foreign_location_is_refused() {
for bad in [
"/whep/s",
"/main/whep/s",
"http://127.0.0.1:8889/main/whep/s",
"/whep/../x?camera=main",
"/whep/s?camera=main&x=1",
"/whep/s?camera=",
"/whep/?camera=main",
] {
assert_eq!(parse_whep_location(bad), None, "{bad}");
}
}
}