anni_provider_drive_token_storage/fs/
local.rs

1use crate::{FileEntry, FileSystemProvider, ProviderError, Range, ResourceReader};
2use async_trait::async_trait;
3use std::io::SeekFrom;
4use std::path::PathBuf;
5use std::pin::Pin;
6use tokio::fs::read_dir;
7use tokio::io::{AsyncReadExt, AsyncSeekExt};
8use tokio_stream::{self as stream, Stream};
9
10pub struct LocalFileSystemProvider;
11
12#[async_trait]
13impl FileSystemProvider for LocalFileSystemProvider {
14    async fn children(
15        &self,
16        path: &PathBuf,
17    ) -> crate::Result<Pin<Box<dyn Stream<Item = FileEntry> + Send>>> {
18        Ok(Box::pin(stream::iter(std::fs::read_dir(path)?.filter_map(
19            |entry| {
20                let entry = entry.ok()?;
21                let path = entry.path();
22                let name = path.file_name()?.to_string_lossy().to_string();
23                if path.is_dir() {
24                    Some(FileEntry { name, path })
25                } else {
26                    None
27                }
28            },
29        ))))
30    }
31
32    async fn get_file_entry_by_prefix(
33        &self,
34        parent: &PathBuf,
35        prefix: &str,
36    ) -> crate::Result<FileEntry> {
37        let mut dir = read_dir(parent).await?;
38        loop {
39            match dir.next_entry().await? {
40                Some(entry) if entry.file_name().to_string_lossy().starts_with(prefix) => {
41                    return Ok(FileEntry {
42                        name: entry.file_name().to_string_lossy().to_string(),
43                        path: entry.path(),
44                    });
45                }
46                None => return Err(ProviderError::FileNotFound),
47                _ => {}
48            }
49        }
50    }
51
52    async fn get_file(&self, path: &PathBuf, range: Range) -> crate::Result<ResourceReader> {
53        let mut file = tokio::fs::File::open(path).await?;
54        let metadata = file.metadata().await?;
55        let file_size = metadata.len();
56
57        file.seek(SeekFrom::Start(range.start)).await?;
58        let file = file.take(range.length_limit(file_size));
59        Ok(Box::pin(file))
60    }
61
62    async fn get_audio_info(&self, path: &PathBuf) -> crate::Result<(String, usize)> {
63        let extension = path
64            .extension()
65            .map(|e| e.to_string_lossy().to_string())
66            .unwrap_or_default();
67        let size = tokio::fs::metadata(path).await.map(|m| m.len())?;
68        Ok((extension, size as usize))
69    }
70
71    async fn reload(&mut self) -> crate::Result<()> {
72        Ok(())
73    }
74}