hyperware_process_lib/vfs/
directory.rs

1use super::{parse_response, vfs_request, DirEntry, FileType, VfsAction, VfsError, VfsResponse};
2
3#[cfg(feature = "hyperapp")]
4pub mod directory_async;
5
6/// VFS (Virtual File System) helper struct for a directory.
7/// Opening or creating a directory will give you a `Result<Directory>`.
8/// You can call it's impl functions to interact with it.
9pub struct Directory {
10    pub path: String,
11    pub timeout: u64,
12}
13
14impl Directory {
15    /// Iterates through children of `Directory`, returning a vector of DirEntries.
16    /// DirEntries contain the path and file type of each child.
17    pub fn read(&self) -> Result<Vec<DirEntry>, VfsError> {
18        let message = vfs_request(&self.path, VfsAction::ReadDir)
19            .send_and_await_response(self.timeout)
20            .unwrap()
21            .map_err(|e| VfsError::SendError(e.kind))?;
22
23        match parse_response(message.body())? {
24            VfsResponse::ReadDir(entries) => Ok(entries),
25            VfsResponse::Err(e) => Err(e),
26            _ => Err(VfsError::ParseError {
27                error: "unexpected response".to_string(),
28                path: self.path.clone(),
29            }),
30        }
31    }
32}
33
34/// Opens or creates a `Directory` at path.
35/// If trying to create an existing `Directory`, will just give you the path.
36pub fn open_dir(path: &str, create: bool, timeout: Option<u64>) -> Result<Directory, VfsError> {
37    let timeout = timeout.unwrap_or(5);
38    if !create {
39        let message = vfs_request(path, VfsAction::Metadata)
40            .send_and_await_response(timeout)
41            .unwrap()
42            .map_err(|e| VfsError::SendError(e.kind))?;
43        match parse_response(message.body())? {
44            VfsResponse::Metadata(m) => {
45                if m.file_type != FileType::Directory {
46                    return Err(VfsError::IOError(
47                        "entry at path is not a directory".to_string(),
48                    ));
49                }
50            }
51            VfsResponse::Err(e) => return Err(e),
52            _ => {
53                return Err(VfsError::ParseError {
54                    error: "unexpected response".to_string(),
55                    path: path.to_string(),
56                })
57            }
58        }
59
60        return Ok(Directory {
61            path: path.to_string(),
62            timeout,
63        });
64    }
65
66    let message = vfs_request(path, VfsAction::CreateDirAll)
67        .send_and_await_response(timeout)
68        .unwrap()
69        .map_err(|e| VfsError::SendError(e.kind))?;
70
71    match parse_response(message.body())? {
72        VfsResponse::Ok => Ok(Directory {
73            path: path.to_string(),
74            timeout,
75        }),
76        VfsResponse::Err(e) => Err(e),
77        _ => Err(VfsError::ParseError {
78            error: "unexpected response".to_string(),
79            path: path.to_string(),
80        }),
81    }
82}
83
84/// Removes a dir at path, errors if path not found or path is not a `Directory`.
85#[cfg(not(feature = "hyperapp"))]
86pub fn remove_dir(path: &str, timeout: Option<u64>) -> Result<(), VfsError> {
87    let timeout = timeout.unwrap_or(5);
88
89    let message = vfs_request(path, VfsAction::RemoveDir)
90        .send_and_await_response(timeout)
91        .unwrap()
92        .map_err(|e| VfsError::SendError(e.kind))?;
93
94    match parse_response(message.body())? {
95        VfsResponse::Ok => Ok(()),
96        VfsResponse::Err(e) => Err(e),
97        _ => Err(VfsError::ParseError {
98            error: "unexpected response".to_string(),
99            path: path.to_string(),
100        }),
101    }
102}
103
104/// Removes a dir at path, errors if path not found or path is not a `Directory`.
105#[cfg(feature = "hyperapp")]
106pub async fn remove_dir(path: &str, timeout: Option<u64>) -> Result<(), VfsError> {
107    directory_async::remove_dir_async(path, timeout).await
108}