40 lines
1.3 KiB
Rust
40 lines
1.3 KiB
Rust
use std::ffi::{CString, c_char};
|
|
|
|
unsafe extern "C" {
|
|
fn ds4_media_open(url: *const c_char, title: *const c_char, video: bool) -> bool;
|
|
}
|
|
|
|
pub(crate) fn open(url: &str, title: &str, video: bool) -> Result<(), String> {
|
|
let url = playable_url(url)?;
|
|
let url = CString::new(url.as_str()).map_err(|error| error.to_string())?;
|
|
let title = CString::new(title).map_err(|error| error.to_string())?;
|
|
// SAFETY: Both C strings live for the duration of the call; Objective-C copies them.
|
|
if unsafe { ds4_media_open(url.as_ptr(), title.as_ptr(), video) } {
|
|
Ok(())
|
|
} else {
|
|
Err("AVKit could not create the media player".into())
|
|
}
|
|
}
|
|
|
|
fn playable_url(value: &str) -> Result<url::Url, String> {
|
|
let url = url::Url::parse(value).map_err(|error| format!("invalid media URL: {error}"))?;
|
|
if matches!(url.scheme(), "http" | "https") {
|
|
Ok(url)
|
|
} else {
|
|
Err("media URLs must use HTTP(S)".into())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn media_player_only_accepts_remote_http_urls() {
|
|
assert!(playable_url("https://example.com/video.mp4").is_ok());
|
|
assert!(playable_url("http://example.com/audio.mp3").is_ok());
|
|
assert!(playable_url("file:///tmp/private.mov").is_err());
|
|
assert!(playable_url("javascript:alert(1)").is_err());
|
|
}
|
|
}
|