use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamUrl {
pub url: String,
pub protocol: StreamProtocol,
}
impl StreamUrl {
pub fn parse(url: &str) -> Self {
let protocol = StreamProtocol::detect(url);
Self {
url: url.to_string(),
protocol,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum StreamProtocol {
Http,
Https,
Hls,
Dash,
Rtmp,
Rtsp,
Udp,
Rtp,
Mms,
#[default]
Unknown,
}
impl StreamProtocol {
pub fn detect(url: &str) -> Self {
let lower = url.to_ascii_lowercase();
if lower.starts_with("rtmp://") || lower.starts_with("rtmps://") {
return Self::Rtmp;
}
if lower.starts_with("rtsp://") {
return Self::Rtsp;
}
if lower.starts_with("udp://") {
return Self::Udp;
}
if lower.starts_with("rtp://") {
return Self::Rtp;
}
if lower.starts_with("mms://") || lower.starts_with("mmsh://") {
return Self::Mms;
}
if lower.contains(".m3u8") || lower.contains("/hls/") {
return Self::Hls;
}
if lower.contains(".mpd") || lower.contains("/dash/") {
return Self::Dash;
}
if lower.starts_with("https://") {
return Self::Https;
}
if lower.starts_with("http://") {
return Self::Http;
}
Self::Unknown
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamStatus {
pub available: bool,
pub status_code: Option<u16>,
pub response_time_ms: Option<u64>,
pub content_type: Option<String>,
pub error: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detect_hls() {
assert_eq!(
StreamProtocol::detect("http://example.com/live/stream.m3u8"),
StreamProtocol::Hls,
);
}
#[test]
fn detect_rtmp() {
assert_eq!(
StreamProtocol::detect("rtmp://cdn.example.com/live/key"),
StreamProtocol::Rtmp,
);
}
#[test]
fn detect_http() {
assert_eq!(
StreamProtocol::detect("http://example.com/stream.ts"),
StreamProtocol::Http,
);
}
#[test]
fn detect_udp() {
assert_eq!(
StreamProtocol::detect("udp://239.0.0.1:5000"),
StreamProtocol::Udp,
);
}
#[test]
fn detect_dash() {
assert_eq!(
StreamProtocol::detect("https://cdn.example.com/manifest.mpd"),
StreamProtocol::Dash,
);
}
#[test]
fn detect_unknown() {
assert_eq!(
StreamProtocol::detect("ftp://example.com/file"),
StreamProtocol::Unknown,
);
}
#[test]
fn stream_url_parse() {
let s = StreamUrl::parse("https://cdn.example.com/live/stream.m3u8");
assert_eq!(s.protocol, StreamProtocol::Hls);
}
}