use std::{
fs::File,
io::{self, Read, Seek, SeekFrom},
path::Path,
sync::Arc,
};
#[cfg(not(target_arch = "wasm32"))]
use crate::media::PLATFORM_MEDIA_SOURCE;
pub struct MediaSourceHandle {
stream: File,
len: Option<u64>,
_access: Option<Arc<dyn Send + Sync>>,
}
impl MediaSourceHandle {
pub fn new(stream: File, len: Option<u64>) -> Self {
Self {
stream,
len,
_access: None,
}
}
pub fn with_access(self, access: impl Send + Sync + 'static) -> Self {
Self {
_access: Some(Arc::new(access)),
..self
}
}
pub fn byte_len(&self) -> Option<u64> {
self.len
}
}
impl std::fmt::Debug for MediaSourceHandle {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("MediaSourceHandle")
.field("len", &self.len)
.finish_non_exhaustive()
}
}
impl Read for MediaSourceHandle {
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
self.stream.read(output)
}
}
impl Seek for MediaSourceHandle {
fn seek(&mut self, position: SeekFrom) -> io::Result<u64> {
self.stream.seek(position)
}
}
pub trait MediaSourceOpener: Send + Sync {
fn open(&self, uri: &str) -> io::Result<MediaSourceHandle>;
fn reference(&self, path: &Path) -> io::Result<String> {
Ok(crate::media::uri_for_path(path))
}
fn child_reference(&self, folder: &str, relative: &Path) -> io::Result<String> {
let root = crate::media::path_from_uri(folder)
.ok_or_else(|| io::Error::new(io::ErrorKind::Unsupported, "folder media references"))?;
Ok(crate::media::uri_for_path(&root.join(relative)))
}
}
pub type MediaSourceOpenerRef = Arc<dyn MediaSourceOpener>;
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn media_reference(path: &Path) -> io::Result<String> {
match PLATFORM_MEDIA_SOURCE.get() {
Some(opener) => opener.reference(path),
None => Ok(crate::media::uri_for_path(path)),
}
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn media_child_reference(folder: &str, relative: &Path) -> io::Result<String> {
if relative
.components()
.any(|part| !matches!(part, std::path::Component::Normal(_)))
{
return Err(io::Error::other(
"media path is outside the selected folder",
));
}
match PLATFORM_MEDIA_SOURCE.get() {
Some(opener) => opener.child_reference(folder, relative),
None => {
let root = crate::media::path_from_uri(folder)
.ok_or_else(|| io::Error::other("invalid folder media reference"))?;
Ok(crate::media::uri_for_path(&root.join(relative)))
}
}
}