cranpose_services/
media_source.rs1use std::{
2 fs::File,
3 io::{self, Read, Seek, SeekFrom},
4 path::Path,
5 sync::Arc,
6};
7
8#[cfg(not(target_arch = "wasm32"))]
9use crate::media::PLATFORM_MEDIA_SOURCE;
10
11pub struct MediaSourceHandle {
13 stream: File,
14 len: Option<u64>,
15 _access: Option<Arc<dyn Send + Sync>>,
16}
17
18impl MediaSourceHandle {
19 pub fn new(stream: File, len: Option<u64>) -> Self {
21 Self {
22 stream,
23 len,
24 _access: None,
25 }
26 }
27
28 pub fn with_access(self, access: impl Send + Sync + 'static) -> Self {
30 Self {
31 _access: Some(Arc::new(access)),
32 ..self
33 }
34 }
35
36 pub fn byte_len(&self) -> Option<u64> {
38 self.len
39 }
40}
41
42impl std::fmt::Debug for MediaSourceHandle {
43 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 formatter
45 .debug_struct("MediaSourceHandle")
46 .field("len", &self.len)
47 .finish_non_exhaustive()
48 }
49}
50
51impl Read for MediaSourceHandle {
52 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
53 self.stream.read(output)
54 }
55}
56
57impl Seek for MediaSourceHandle {
58 fn seek(&mut self, position: SeekFrom) -> io::Result<u64> {
59 self.stream.seek(position)
60 }
61}
62
63pub trait MediaSourceOpener: Send + Sync {
75 fn open(&self, uri: &str) -> io::Result<MediaSourceHandle>;
77
78 fn reference(&self, path: &Path) -> io::Result<String> {
80 Ok(crate::media::uri_for_path(path))
81 }
82
83 fn child_reference(&self, folder: &str, relative: &Path) -> io::Result<String> {
86 let root = crate::media::path_from_uri(folder)
87 .ok_or_else(|| io::Error::new(io::ErrorKind::Unsupported, "folder media references"))?;
88 Ok(crate::media::uri_for_path(&root.join(relative)))
89 }
90}
91
92pub type MediaSourceOpenerRef = Arc<dyn MediaSourceOpener>;
94
95#[cfg(not(target_arch = "wasm32"))]
96pub(crate) fn media_reference(path: &Path) -> io::Result<String> {
97 match PLATFORM_MEDIA_SOURCE.get() {
98 Some(opener) => opener.reference(path),
99 None => Ok(crate::media::uri_for_path(path)),
100 }
101}
102
103#[cfg(not(target_arch = "wasm32"))]
104pub(crate) fn media_child_reference(folder: &str, relative: &Path) -> io::Result<String> {
105 if relative
106 .components()
107 .any(|part| !matches!(part, std::path::Component::Normal(_)))
108 {
109 return Err(io::Error::other(
110 "media path is outside the selected folder",
111 ));
112 }
113 match PLATFORM_MEDIA_SOURCE.get() {
114 Some(opener) => opener.child_reference(folder, relative),
115 None => {
116 let root = crate::media::path_from_uri(folder)
117 .ok_or_else(|| io::Error::other("invalid folder media reference"))?;
118 Ok(crate::media::uri_for_path(&root.join(relative)))
119 }
120 }
121}