feat(storage-server): add StorageServer<F: FileSystem> with BlockDevice trait, mock adapters, and tests
This commit is contained in:
100
crates/servers/storage-server/src/server.rs
Normal file
100
crates/servers/storage-server/src/server.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use server_framework::Server;
|
||||
|
||||
use crate::filesystem::{FileHandle, FileSystem};
|
||||
use crate::protocol::{StorageRequest, StorageResponse};
|
||||
|
||||
pub struct StorageServer<F: FileSystem> {
|
||||
fs: F,
|
||||
}
|
||||
|
||||
impl<F: FileSystem> StorageServer<F> {
|
||||
pub fn new(fs: F) -> Self {
|
||||
Self { fs }
|
||||
}
|
||||
|
||||
pub fn filesystem(&self) -> &F {
|
||||
&self.fs
|
||||
}
|
||||
|
||||
fn path_from_words(w0: usize, w1: usize) -> [u8; 16] {
|
||||
let mut path = [0u8; 16];
|
||||
let b0 = w0.to_le_bytes();
|
||||
let b1 = w1.to_le_bytes();
|
||||
path[..8].copy_from_slice(&b0);
|
||||
path[8..16].copy_from_slice(&b1);
|
||||
path
|
||||
}
|
||||
|
||||
fn path_len(path: &[u8]) -> usize {
|
||||
path.iter().position(|&b| b == 0).unwrap_or(path.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: FileSystem> Server for StorageServer<F> {
|
||||
type Request = StorageRequest;
|
||||
type Response = StorageResponse;
|
||||
|
||||
fn handle(&mut self, request: StorageRequest) -> StorageResponse {
|
||||
match request {
|
||||
StorageRequest::Open { path_word0, path_word1 } => {
|
||||
let path = Self::path_from_words(path_word0, path_word1);
|
||||
let len = Self::path_len(&path);
|
||||
match self.fs.open(&path[..len]) {
|
||||
Some(h) => StorageResponse::Handle(h),
|
||||
None => StorageResponse::NotFound,
|
||||
}
|
||||
}
|
||||
StorageRequest::Read { handle, max_bytes } => {
|
||||
let mut buf = [0u8; 512];
|
||||
let read_len = max_bytes.min(buf.len());
|
||||
match self.fs.read(handle, &mut buf[..read_len]) {
|
||||
Some(n) => StorageResponse::Data { bytes_read: n },
|
||||
None => StorageResponse::Error,
|
||||
}
|
||||
}
|
||||
StorageRequest::Write { handle, data_word } => {
|
||||
let data = data_word.to_le_bytes();
|
||||
match self.fs.write(handle, &data) {
|
||||
Some(n) => StorageResponse::Written { bytes_written: n },
|
||||
None => StorageResponse::Error,
|
||||
}
|
||||
}
|
||||
StorageRequest::Close { handle } => {
|
||||
self.fs.close(handle);
|
||||
StorageResponse::Ok
|
||||
}
|
||||
StorageRequest::ListDir { path_word0, path_word1 } => {
|
||||
let path = Self::path_from_words(path_word0, path_word1);
|
||||
let len = Self::path_len(&path);
|
||||
let mut entries = [crate::filesystem::DirEntry::empty(); 16];
|
||||
match self.fs.list_dir(&path[..len], &mut entries) {
|
||||
Some(count) => StorageResponse::DirEntries { count },
|
||||
None => StorageResponse::NotFound,
|
||||
}
|
||||
}
|
||||
StorageRequest::Create { path_word0, path_word1 } => {
|
||||
let path = Self::path_from_words(path_word0, path_word1);
|
||||
let len = Self::path_len(&path);
|
||||
match self.fs.create(&path[..len]) {
|
||||
Some(h) => StorageResponse::Handle(h),
|
||||
None => StorageResponse::Error,
|
||||
}
|
||||
}
|
||||
StorageRequest::Delete { path_word0, path_word1 } => {
|
||||
let path = Self::path_from_words(path_word0, path_word1);
|
||||
let len = Self::path_len(&path);
|
||||
if self.fs.delete(&path[..len]) {
|
||||
StorageResponse::Ok
|
||||
} else {
|
||||
StorageResponse::NotFound
|
||||
}
|
||||
}
|
||||
StorageRequest::FileSize { handle } => {
|
||||
match self.fs.file_size(handle) {
|
||||
Some(size) => StorageResponse::Size(size),
|
||||
None => StorageResponse::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user