1#![warn(missing_docs)]
2
3use docker_types::DockerError;
4use std::path::{Path, PathBuf};
5use tokio::fs;
6
7pub type StorageResult<T> = std::result::Result<T, DockerError>;
9
10pub struct StorageManager {
11 base_path: PathBuf,
12}
13
14impl StorageManager {
15 pub fn new() -> StorageResult<Self> {
16 let base_path = Self::get_base_path()?;
17 Ok(Self { base_path })
18 }
19
20 pub async fn ensure_directories(&self) -> StorageResult<()> {
21 let directories = [
22 &self.base_path,
23 &self.containers_path()?,
24 &self.images_path()?,
25 &self.volumes_path()?,
26 &self.tmp_path()?,
27 ];
28
29 for dir in directories {
30 if !dir.exists() {
31 fs::create_dir_all(dir).await?;
32 }
33 }
34
35 Ok(())
36 }
37
38 pub fn containers_path(&self) -> StorageResult<PathBuf> {
39 Ok(self.base_path.join("containers"))
40 }
41
42 pub fn container_path(&self, container_id: &str) -> StorageResult<PathBuf> {
43 Ok(self.containers_path()?.join(container_id))
44 }
45
46 pub fn images_path(&self) -> StorageResult<PathBuf> {
47 Ok(self.base_path.join("images"))
48 }
49
50 pub fn image_path(&self, image_id: &str) -> StorageResult<PathBuf> {
51 Ok(self.images_path()?.join(image_id))
52 }
53
54 pub fn volumes_path(&self) -> StorageResult<PathBuf> {
55 Ok(self.base_path.join("volumes"))
56 }
57
58 pub fn volume_path(&self, volume_id: &str) -> StorageResult<PathBuf> {
59 Ok(self.volumes_path()?.join(volume_id))
60 }
61
62 pub fn tmp_path(&self) -> StorageResult<PathBuf> {
63 Ok(self.base_path.join("tmp"))
64 }
65
66 pub fn get_base_path() -> StorageResult<PathBuf> {
67 #[cfg(windows)]
68 {
69 let app_data =
70 std::env::var("APPDATA").map_err(|_| DockerError::config_missing("APPDATA"))?;
71 Ok(PathBuf::from(app_data).join("DockerCrab"))
72 }
73
74 #[cfg(target_os = "linux")]
75 {
76 let home = std::env::var("HOME").map_err(|_| DockerError::config_missing("HOME"))?;
77 Ok(PathBuf::from(home).join(".docker-crab"))
78 }
79
80 #[cfg(target_os = "macos")]
81 {
82 let home = std::env::var("HOME").map_err(|_| DockerError::config_missing("HOME"))?;
83 Ok(PathBuf::from(home)
84 .join("Library")
85 .join("Application Support")
86 .join("DockerCrab"))
87 }
88 }
89
90 pub async fn create_file(&self, path: &Path, content: &[u8]) -> StorageResult<()> {
91 fs::write(path, content).await?;
92 Ok(())
93 }
94
95 pub async fn read_file(&self, path: &Path) -> StorageResult<Vec<u8>> {
96 let content = fs::read(path).await?;
97 Ok(content)
98 }
99
100 pub async fn remove_file(&self, path: &Path) -> StorageResult<()> {
101 if path.exists() {
102 fs::remove_file(path).await?;
103 }
104 Ok(())
105 }
106
107 pub async fn remove_directory(&self, path: &Path) -> StorageResult<()> {
108 if path.exists() {
109 fs::remove_dir_all(path).await?;
110 }
111 Ok(())
112 }
113}