Skip to main content

aria2_core/filesystem/
disk_adaptor.rs

1use crate::error::Result;
2use async_trait::async_trait;
3use std::any::Any;
4use std::path::Path;
5
6#[async_trait]
7pub trait DiskAdaptor: Send + Sync {
8    async fn open(&mut self, path: &Path) -> Result<()>;
9    async fn write(&mut self, offset: u64, data: &[u8]) -> Result<()>;
10    async fn read(&mut self, offset: u64, length: u64) -> Result<Vec<u8>>;
11    async fn close(&mut self) -> Result<()>;
12    async fn truncate(&mut self, length: u64) -> Result<()>;
13    async fn flush(&mut self) -> Result<()>;
14    async fn size(&self) -> Result<u64>;
15    fn as_any(&self) -> &dyn Any;
16
17    #[cfg(unix)]
18    fn unix_raw_fd(&self) -> Option<std::os::unix::io::RawFd>;
19
20    /// Returns the raw OS file handle on Windows, or `None` if no file is open.
21    /// The handle is borrowed (not owned); callers must not close it.
22    #[cfg(windows)]
23    fn windows_raw_handle(&self) -> Option<std::os::windows::io::RawHandle>;
24}
25
26pub struct DirectDiskAdaptor {
27    file: Option<tokio::fs::File>,
28    path: std::path::PathBuf,
29}
30
31impl DirectDiskAdaptor {
32    pub fn new() -> Self {
33        DirectDiskAdaptor {
34            file: None,
35            path: std::path::PathBuf::new(),
36        }
37    }
38}
39
40impl Default for DirectDiskAdaptor {
41    fn default() -> Self {
42        Self::new()
43    }
44}
45
46#[async_trait]
47impl DiskAdaptor for DirectDiskAdaptor {
48    async fn open(&mut self, path: &Path) -> Result<()> {
49        self.path = path.to_path_buf();
50        let mut open_opts = tokio::fs::OpenOptions::new();
51
52        if path.exists() {
53            open_opts.write(true).read(true);
54        } else {
55            open_opts.write(true).create(true).read(true);
56        }
57
58        self.file = Some(
59            open_opts
60                .open(path)
61                .await
62                .map_err(|e| crate::error::Aria2Error::Io(e.to_string()))?,
63        );
64
65        Ok(())
66    }
67
68    async fn write(&mut self, offset: u64, data: &[u8]) -> Result<()> {
69        if let Some(ref mut file) = self.file {
70            use tokio::io::{AsyncSeekExt, AsyncWriteExt};
71            file.seek(std::io::SeekFrom::Start(offset))
72                .await
73                .map_err(|e| crate::error::Aria2Error::Io(e.to_string()))?;
74            file.write_all(data)
75                .await
76                .map_err(|e| crate::error::Aria2Error::Io(e.to_string()))?;
77        }
78        Ok(())
79    }
80
81    async fn read(&mut self, offset: u64, length: u64) -> Result<Vec<u8>> {
82        if let Some(ref mut file) = self.file {
83            use tokio::io::{AsyncReadExt, AsyncSeekExt};
84            file.seek(std::io::SeekFrom::Start(offset))
85                .await
86                .map_err(|e| crate::error::Aria2Error::Io(e.to_string()))?;
87
88            let mut buffer = vec![0u8; length as usize];
89            let bytes_read = file.read_exact(&mut buffer).await;
90
91            match bytes_read {
92                Ok(_) => Ok(buffer),
93                Err(e) => {
94                    if e.kind() == std::io::ErrorKind::UnexpectedEof {
95                        Ok(buffer)
96                    } else {
97                        Err(crate::error::Aria2Error::Io(e.to_string()))
98                    }
99                }
100            }
101        } else {
102            Err(crate::error::Aria2Error::DownloadFailed(
103                "文件未打开".to_string(),
104            ))
105        }
106    }
107
108    async fn close(&mut self) -> Result<()> {
109        self.file = None;
110        Ok(())
111    }
112
113    async fn truncate(&mut self, length: u64) -> Result<()> {
114        if let Some(ref mut file) = self.file {
115            file.set_len(length)
116                .await
117                .map_err(|e| crate::error::Aria2Error::Io(e.to_string()))?;
118        }
119        Ok(())
120    }
121
122    async fn flush(&mut self) -> Result<()> {
123        if let Some(ref mut file) = self.file {
124            use tokio::io::AsyncWriteExt;
125            file.flush()
126                .await
127                .map_err(|e| crate::error::Aria2Error::Io(e.to_string()))?;
128        }
129        Ok(())
130    }
131
132    async fn size(&self) -> Result<u64> {
133        if let Some(ref file) = self.file {
134            let metadata = file
135                .metadata()
136                .await
137                .map_err(|e| crate::error::Aria2Error::Io(e.to_string()))?;
138            Ok(metadata.len())
139        } else {
140            Err(crate::error::Aria2Error::DownloadFailed(
141                "文件未打开".to_string(),
142            ))
143        }
144    }
145
146    fn as_any(&self) -> &dyn Any {
147        self
148    }
149
150    #[cfg(unix)]
151    fn unix_raw_fd(&self) -> Option<std::os::unix::io::RawFd> {
152        use std::os::fd::AsRawFd;
153        self.file.as_ref().map(|f| f.as_raw_fd())
154    }
155
156    #[cfg(windows)]
157    fn windows_raw_handle(&self) -> Option<std::os::windows::io::RawHandle> {
158        use std::os::windows::io::AsRawHandle;
159        self.file.as_ref().map(|f| f.as_raw_handle())
160    }
161}