commy_sdk_rust/
file_accessor.rs1use crate::error::Result;
4use memmap2::Mmap;
5use std::path::PathBuf;
6
7#[async_trait::async_trait]
9pub trait FileAccessor: Send + Sync {
10 async fn read_bytes(&self, offset: u64, size: u64) -> Result<Vec<u8>>;
12
13 async fn write_bytes(&self, offset: u64, data: &[u8]) -> Result<()>;
15
16 async fn file_size(&self) -> Result<u64>;
18
19 fn is_local(&self) -> bool;
21
22 async fn resize(&self, new_size: u64) -> Result<()>;
24}
25
26pub struct LocalFileAccessor {
28 file_path: PathBuf,
29 mmap: Mmap,
30}
31
32impl LocalFileAccessor {
33 pub async fn new(file_path: PathBuf) -> Result<Self> {
35 let file = std::fs::OpenOptions::new()
36 .read(true)
37 .write(true)
38 .create(true)
39 .open(&file_path)?;
40
41 let mmap = unsafe { memmap2::MmapMut::map_mut(&file)? };
42 let mmap = mmap.make_read_only()?;
43 Ok(Self {
46 file_path,
47 mmap,
48 })
49 }
50
51 pub fn path(&self) -> &PathBuf {
53 &self.file_path
54 }
55
56 pub fn as_slice(&self) -> &[u8] {
58 &self.mmap[..]
59 }
60}
61
62#[async_trait::async_trait]
63impl FileAccessor for LocalFileAccessor {
64 async fn read_bytes(&self, offset: u64, size: u64) -> Result<Vec<u8>> {
65 let start = offset as usize;
66 let end = (offset + size) as usize;
67
68 if end > self.mmap.len() {
69 return Err(crate::error::CommyError::InvalidOffset(
70 format!("Read extends beyond file bounds"),
71 ));
72 }
73
74 Ok(self.mmap[start..end].to_vec())
75 }
76
77 async fn write_bytes(&self, _offset: u64, _data: &[u8]) -> Result<()> {
78 Err(crate::error::CommyError::InvalidState(
80 "Cannot write directly to local accessor; use file watcher".to_string(),
81 ))
82 }
83
84 async fn file_size(&self) -> Result<u64> {
85 Ok(self.mmap.len() as u64)
86 }
87
88 fn is_local(&self) -> bool {
89 true
90 }
91
92 async fn resize(&self, _new_size: u64) -> Result<()> {
93 Err(crate::error::CommyError::InvalidState(
94 "Cannot resize local mapped file".to_string(),
95 ))
96 }
97}
98
99pub struct RemoteFileAccessor {
101 buffer: std::sync::Arc<tokio::sync::RwLock<Vec<u8>>>,
103}
104
105impl RemoteFileAccessor {
106 pub fn new() -> Self {
108 Self {
109 buffer: std::sync::Arc::new(tokio::sync::RwLock::new(Vec::new())),
110 }
111 }
112
113 pub async fn update_buffer(&self, data: Vec<u8>) -> Result<()> {
115 let mut buf = self.buffer.write().await;
116 *buf = data;
117 Ok(())
118 }
119
120 pub async fn get_buffer(&self) -> Vec<u8> {
122 self.buffer.read().await.clone()
123 }
124}
125
126#[async_trait::async_trait]
127impl FileAccessor for RemoteFileAccessor {
128 async fn read_bytes(&self, offset: u64, size: u64) -> Result<Vec<u8>> {
129 let buf = self.buffer.read().await;
130 let start = offset as usize;
131 let end = (offset + size) as usize;
132
133 if end > buf.len() {
134 return Err(crate::error::CommyError::InvalidOffset(
135 format!("Read extends beyond buffer bounds"),
136 ));
137 }
138
139 Ok(buf[start..end].to_vec())
140 }
141
142 async fn write_bytes(&self, offset: u64, data: &[u8]) -> Result<()> {
143 let mut buf = self.buffer.write().await;
144 let start = offset as usize;
145 let end = start + data.len();
146
147 if end > buf.len() {
148 buf.resize(end, 0);
149 }
150
151 buf[start..end].copy_from_slice(data);
152 Ok(())
153 }
154
155 async fn file_size(&self) -> Result<u64> {
156 Ok(self.buffer.read().await.len() as u64)
157 }
158
159 fn is_local(&self) -> bool {
160 false
161 }
162
163 async fn resize(&self, new_size: u64) -> Result<()> {
164 let mut buf = self.buffer.write().await;
165 buf.resize(new_size as usize, 0);
166 Ok(())
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[tokio::test]
175 async fn test_remote_file_accessor() {
176 let accessor = RemoteFileAccessor::new();
177
178 accessor
180 .update_buffer(vec![1, 2, 3, 4, 5, 6, 7, 8])
181 .await
182 .unwrap();
183
184 let data = accessor.read_bytes(0, 4).await.unwrap();
186 assert_eq!(data, vec![1, 2, 3, 4]);
187
188 assert!(!accessor.is_local());
190 }
191
192 #[tokio::test]
193 async fn test_remote_write_bytes() {
194 let accessor = RemoteFileAccessor::new();
195 accessor.update_buffer(vec![0; 8]).await.unwrap();
196
197 accessor
198 .write_bytes(2, &[99, 88, 77])
199 .await
200 .unwrap();
201
202 let data = accessor.read_bytes(0, 8).await.unwrap();
203 assert_eq!(data, vec![0, 0, 99, 88, 77, 0, 0, 0]);
204 }
205}