aleo_std_storage/lib.rs
1// Copyright (C) 2019-2021 Aleo Systems Inc.
2// This file is part of the aleo-std library.
3
4// The aleo-std library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The aleo-std library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the aleo-std library. If not, see <https://www.gnu.org/licenses/>.
16
17use dirs::home_dir;
18use std::{path::PathBuf, sync::Arc};
19use tempfile::TempDir;
20
21/// The directory name for Aleo-related resources.
22const ALEO_DIRECTORY: &str = ".aleo";
23
24/// An enum to define the operating mode of the Aleo node.
25#[derive(Clone, Debug)]
26pub enum StorageMode {
27 /// The production mode is used for running a node on the Aleo mainnet.
28 Production,
29 /// The development mode is used for running a node on a local network.
30 Development(u16),
31 /// The custom mode is used for running a node on custom configurations.
32 Custom(PathBuf),
33 /// Test-only ephemeral storage which self-destructs afterwards.
34 Test(Option<Arc<TempDir>>),
35}
36
37impl StorageMode {
38 pub fn new_test(tempdir: Option<Arc<TempDir>>) -> Self {
39 if tempdir.is_some() {
40 Self::Test(tempdir)
41 } else {
42 Self::Test(Some(Arc::new(tempfile::TempDir::with_prefix("aleo_storage_").unwrap())))
43 }
44 }
45}
46
47impl PartialEq for StorageMode {
48 fn eq(&self, other: &Self) -> bool {
49 match (self, other) {
50 (StorageMode::Production, StorageMode::Production) => true,
51 (StorageMode::Development(id1), StorageMode::Development(id2)) => id1 == id2,
52 (StorageMode::Custom(path1), StorageMode::Custom(path2)) => path1 == path2,
53 (StorageMode::Test(Some(temp1)), StorageMode::Test(Some(temp2))) => temp1.path() == temp2.path(),
54 _ => false,
55 }
56 }
57}
58impl Eq for StorageMode {}
59
60impl From<u16> for StorageMode {
61 fn from(id: u16) -> Self {
62 StorageMode::Development(id)
63 }
64}
65
66impl From<PathBuf> for StorageMode {
67 fn from(path: PathBuf) -> Self {
68 StorageMode::Custom(path)
69 }
70}
71
72impl From<Arc<TempDir>> for StorageMode {
73 fn from(tempdir: Arc<TempDir>) -> Self {
74 StorageMode::Test(Some(tempdir))
75 }
76}
77
78impl StorageMode {
79 /// Returns the development ID if the mode is development.
80 pub const fn dev(&self) -> Option<u16> {
81 match self {
82 Self::Development(id) => Some(*id),
83 Self::Production | Self::Custom(_) | Self::Test(_) => None,
84 }
85 }
86}
87
88///
89/// Returns the directory for accessing resources from Aleo storage.
90/// The expected directory path to be returned is `~/.aleo/`.
91///
92pub fn aleo_dir() -> PathBuf {
93 // Locate the home directory as the starting point.
94 // If called on a non-standard OS, use the repository directory.
95 let mut path = match home_dir() {
96 Some(home) => home,
97 None => PathBuf::from(env!("CARGO_MANIFEST_DIR")),
98 };
99 // Append the Aleo directory to the path.
100 path.push(ALEO_DIRECTORY);
101 path
102}
103
104///
105/// Returns the directory for accessing the ledger files from Aleo storage.
106///
107/// In production mode, the expected directory path is `~/.aleo/storage/ledger-{network}`.
108/// In development mode, the expected directory path is `/path/to/repo/.ledger-{network}-{id}`.
109/// In custom mode, the expected directory path is `/path/to/custom`.
110///
111pub fn aleo_ledger_dir(network: u16, mode: &StorageMode) -> PathBuf {
112 // Construct the path to the ledger in storage.
113 match mode {
114 // In production mode, the ledger is stored in the `~/.aleo/` directory.
115 StorageMode::Production => {
116 let mut path = aleo_dir();
117 path.push("storage");
118 path.push(format!("ledger-{}", network));
119 path
120 }
121 // In development mode, the ledger files are stored in a hidden folder in the repository root directory.
122 StorageMode::Development(id) => {
123 let mut path = match std::env::current_dir() {
124 Ok(current_dir) => current_dir,
125 _ => PathBuf::from(env!("CARGO_MANIFEST_DIR")),
126 };
127 path.push(format!(".ledger-{}-{}", network, id));
128 path
129 }
130 // In custom mode, the ledger files are stored in the given directory path.
131 StorageMode::Custom(path) => path.to_owned(),
132 StorageMode::Test(tempdir) => {
133 if let Some(tempdir) = tempdir {
134 tempdir.path().to_owned()
135 } else {
136 // aleo_ledger_dir is only ever called with persistent storage, where TempDir must be present.
137 panic!("StorageMode::Test was created in a persistent storage context without a TempDir");
138 }
139 }
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_aleo_dir() {
149 println!("{:?} exists: {:?}", aleo_dir(), aleo_dir().exists());
150 }
151
152 #[test]
153 fn test_aleo_ledger_dir() {
154 println!(
155 "{:?} exists: {:?}",
156 aleo_ledger_dir(2, &StorageMode::Production),
157 aleo_ledger_dir(2, &StorageMode::Production).exists()
158 );
159 }
160}