aria2_core/filesystem/
disk_adaptor.rs1use 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 #[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}