@anysphere/file-service 0.0.0-eb1d04d9 → 0.0.0-ed88c2dc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +5 -1
- package/package.json +7 -7
- package/src/lib.rs +64 -4
- package/src/merkle_tree/local_construction.rs +3 -2
- package/src/merkle_tree/mod.rs +129 -72
package/index.d.ts
CHANGED
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
export class MerkleClient {
|
|
7
7
|
constructor(rootDirectory: string)
|
|
8
8
|
init(): Promise<void>
|
|
9
|
+
computeMerkleTree(): Promise<void>
|
|
9
10
|
updateFile(filePath: string): Promise<void>
|
|
10
11
|
deleteFile(filePath: string): Promise<void>
|
|
11
|
-
getSubtreeHash(
|
|
12
|
+
getSubtreeHash(relativePath: string): Promise<string>
|
|
12
13
|
getNumEmbeddableFiles(): Promise<number>
|
|
13
14
|
getAllFiles(): Promise<Array<string>>
|
|
15
|
+
getAllDirFilesToEmbed(absoluteFilePath: string): Promise<Array<string>>
|
|
14
16
|
getNextFileToEmbed(): Promise<Array<string>>
|
|
17
|
+
getSpline(absoluteFilePath: string): Promise<Array<string>>
|
|
15
18
|
getHashesForFiles(files: Array<string>): Promise<Array<string>>
|
|
19
|
+
updateRootDirectory(rootDirectory: string): void
|
|
16
20
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anysphere/file-service",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-ed88c2dc",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"napi": {
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"version": "napi version"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@anysphere/file-service-win32-x64-msvc": "0.0.0-
|
|
39
|
-
"@anysphere/file-service-darwin-x64": "0.0.0-
|
|
40
|
-
"@anysphere/file-service-linux-x64-gnu": "0.0.0-
|
|
41
|
-
"@anysphere/file-service-darwin-arm64": "0.0.0-
|
|
42
|
-
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-
|
|
43
|
-
"@anysphere/file-service-darwin-universal": "0.0.0-
|
|
38
|
+
"@anysphere/file-service-win32-x64-msvc": "0.0.0-ed88c2dc",
|
|
39
|
+
"@anysphere/file-service-darwin-x64": "0.0.0-ed88c2dc",
|
|
40
|
+
"@anysphere/file-service-linux-x64-gnu": "0.0.0-ed88c2dc",
|
|
41
|
+
"@anysphere/file-service-darwin-arm64": "0.0.0-ed88c2dc",
|
|
42
|
+
"@anysphere/file-service-win32-arm64-msvc": "0.0.0-ed88c2dc",
|
|
43
|
+
"@anysphere/file-service-darwin-universal": "0.0.0-ed88c2dc"
|
|
44
44
|
}
|
|
45
45
|
}
|
package/src/lib.rs
CHANGED
|
@@ -40,7 +40,7 @@ impl MerkleClient {
|
|
|
40
40
|
unimplemented!("Interrupt is not implemented yet");
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
#[napi]
|
|
44
44
|
pub async unsafe fn compute_merkle_tree(
|
|
45
45
|
&mut self,
|
|
46
46
|
) -> Result<(), napi::Error> {
|
|
@@ -72,9 +72,11 @@ impl MerkleClient {
|
|
|
72
72
|
#[napi]
|
|
73
73
|
pub async fn get_subtree_hash(
|
|
74
74
|
&self,
|
|
75
|
-
|
|
75
|
+
relative_path: String,
|
|
76
76
|
) -> Result<String, napi::Error> {
|
|
77
|
-
let
|
|
77
|
+
let absolute_path =
|
|
78
|
+
std::path::Path::new(&self.root_directory).join(relative_path);
|
|
79
|
+
let hash = self.tree.get_subtree_hash(absolute_path).await;
|
|
78
80
|
|
|
79
81
|
match hash {
|
|
80
82
|
Ok(hash) => Ok(hash),
|
|
@@ -98,6 +100,26 @@ impl MerkleClient {
|
|
|
98
100
|
}
|
|
99
101
|
}
|
|
100
102
|
|
|
103
|
+
pub async fn get_num_embeddable_files_in_subtree(
|
|
104
|
+
&self,
|
|
105
|
+
relative_path: String,
|
|
106
|
+
) -> Result<i32, napi::Error> {
|
|
107
|
+
let absolute_path =
|
|
108
|
+
std::path::Path::new(&self.root_directory).join(relative_path);
|
|
109
|
+
let num = self
|
|
110
|
+
.tree
|
|
111
|
+
.get_num_embeddable_files_in_subtree(absolute_path)
|
|
112
|
+
.await;
|
|
113
|
+
|
|
114
|
+
match num {
|
|
115
|
+
Ok(num) => Ok(num),
|
|
116
|
+
Err(e) => Err(napi::Error::new(
|
|
117
|
+
napi::Status::Unknown,
|
|
118
|
+
format!("Error in get_num_embeddable_files_in_subtree: {:?}", e),
|
|
119
|
+
)),
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
101
123
|
#[napi]
|
|
102
124
|
pub async fn get_all_files(&self) -> Result<Vec<String>, napi::Error> {
|
|
103
125
|
let files = self.tree.get_all_files().await;
|
|
@@ -111,6 +133,26 @@ impl MerkleClient {
|
|
|
111
133
|
}
|
|
112
134
|
}
|
|
113
135
|
|
|
136
|
+
#[napi]
|
|
137
|
+
pub async fn get_all_dir_files_to_embed(
|
|
138
|
+
&self,
|
|
139
|
+
absolute_file_path: String,
|
|
140
|
+
) -> Result<Vec<String>, napi::Error> {
|
|
141
|
+
let absolute_path_str = absolute_file_path.as_str();
|
|
142
|
+
let files = self
|
|
143
|
+
.tree
|
|
144
|
+
.get_all_dir_files_to_embed(absolute_path_str)
|
|
145
|
+
.await;
|
|
146
|
+
|
|
147
|
+
match files {
|
|
148
|
+
Ok(files) => Ok(files),
|
|
149
|
+
Err(e) => Err(napi::Error::new(
|
|
150
|
+
napi::Status::Unknown,
|
|
151
|
+
format!("Error in get_all_dir_files_to_embed: {:?}", e),
|
|
152
|
+
)),
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
114
156
|
#[napi]
|
|
115
157
|
pub async unsafe fn get_next_file_to_embed(
|
|
116
158
|
&mut self,
|
|
@@ -135,6 +177,24 @@ impl MerkleClient {
|
|
|
135
177
|
}
|
|
136
178
|
}
|
|
137
179
|
|
|
180
|
+
// FIXME(sualeh): get_spline
|
|
181
|
+
#[napi]
|
|
182
|
+
pub async fn get_spline(
|
|
183
|
+
&self,
|
|
184
|
+
absolute_file_path: String,
|
|
185
|
+
) -> Result<Vec<String>, napi::Error> {
|
|
186
|
+
let absolute_path_str = absolute_file_path.as_str();
|
|
187
|
+
let spline = self.tree.get_spline(absolute_path_str).await;
|
|
188
|
+
|
|
189
|
+
match spline {
|
|
190
|
+
Ok(spline) => Ok(spline),
|
|
191
|
+
Err(e) => Err(napi::Error::new(
|
|
192
|
+
napi::Status::Unknown,
|
|
193
|
+
format!("Error in get_spline: {:?}", e),
|
|
194
|
+
)),
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
138
198
|
#[napi]
|
|
139
199
|
pub async fn get_hashes_for_files(
|
|
140
200
|
&self,
|
|
@@ -151,7 +211,7 @@ impl MerkleClient {
|
|
|
151
211
|
}
|
|
152
212
|
}
|
|
153
213
|
|
|
154
|
-
|
|
214
|
+
#[napi]
|
|
155
215
|
pub fn update_root_directory(&mut self, root_directory: String) {
|
|
156
216
|
self.root_directory = root_directory;
|
|
157
217
|
}
|
|
@@ -3,6 +3,7 @@ use crate::merkle_tree::{
|
|
|
3
3
|
};
|
|
4
4
|
|
|
5
5
|
use super::{LocalConstruction, MerkleTree};
|
|
6
|
+
use std::collections::BTreeMap;
|
|
6
7
|
use std::path::PathBuf;
|
|
7
8
|
use std::{collections::HashMap, path::Path, sync::Arc};
|
|
8
9
|
use tonic::async_trait;
|
|
@@ -39,7 +40,7 @@ impl LocalConstruction for MerkleTree {
|
|
|
39
40
|
let root_node = MerkleNode::new(path, None).await;
|
|
40
41
|
let mut mt = MerkleTree {
|
|
41
42
|
root: root_node,
|
|
42
|
-
files:
|
|
43
|
+
files: BTreeMap::new(),
|
|
43
44
|
root_path: root_directory,
|
|
44
45
|
cursor: None,
|
|
45
46
|
};
|
|
@@ -48,7 +49,7 @@ impl LocalConstruction for MerkleTree {
|
|
|
48
49
|
// TODO(later): i can make this parallel.
|
|
49
50
|
fn add_nodes_to_hashmap<'a>(
|
|
50
51
|
node: &'a MerkleNodePtr,
|
|
51
|
-
files: &'a mut
|
|
52
|
+
files: &'a mut BTreeMap<String, File>,
|
|
52
53
|
) -> PinnedFuture<'a, ()> {
|
|
53
54
|
Box::pin(async move {
|
|
54
55
|
let node_reader = node.read().await;
|
package/src/merkle_tree/mod.rs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
use super::file_utils;
|
|
2
2
|
use sha2::Digest;
|
|
3
|
+
use std::collections::BTreeMap;
|
|
3
4
|
use std::path::PathBuf;
|
|
4
|
-
use std::{
|
|
5
|
+
use std::{fs, path::Path, sync::Arc};
|
|
5
6
|
use tokio::sync::RwLock;
|
|
6
7
|
use tonic::async_trait;
|
|
7
8
|
pub mod local_construction;
|
|
@@ -12,8 +13,8 @@ pub type MerkleNodePtr = Arc<RwLock<MerkleNode>>;
|
|
|
12
13
|
pub struct MerkleTree {
|
|
13
14
|
root_path: String,
|
|
14
15
|
root: MerkleNodePtr,
|
|
15
|
-
files:
|
|
16
|
-
cursor: Option<
|
|
16
|
+
files: BTreeMap<String, File>,
|
|
17
|
+
cursor: Option<usize>,
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
#[derive(Debug)]
|
|
@@ -87,7 +88,7 @@ impl MerkleTree {
|
|
|
87
88
|
pub fn empty_tree() -> MerkleTree {
|
|
88
89
|
MerkleTree {
|
|
89
90
|
root: Arc::new(RwLock::new(MerkleNode::empty_node(None, None))),
|
|
90
|
-
files:
|
|
91
|
+
files: BTreeMap::new(),
|
|
91
92
|
root_path: "".to_string(),
|
|
92
93
|
cursor: None,
|
|
93
94
|
}
|
|
@@ -95,10 +96,18 @@ impl MerkleTree {
|
|
|
95
96
|
|
|
96
97
|
pub async fn get_subtree_hash(
|
|
97
98
|
&self,
|
|
98
|
-
|
|
99
|
+
absolute_path: PathBuf,
|
|
99
100
|
) -> Result<String, anyhow::Error> {
|
|
100
|
-
let
|
|
101
|
-
|
|
101
|
+
let abs_string = match absolute_path.to_str() {
|
|
102
|
+
Some(s) => s.to_string(),
|
|
103
|
+
None => {
|
|
104
|
+
return Err(anyhow::anyhow!(
|
|
105
|
+
"get_subtree_hash: Failed to convert path to string"
|
|
106
|
+
))
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
let node = match self.files.get(&abs_string) {
|
|
102
111
|
Some(file) => file.node.clone(),
|
|
103
112
|
None => {
|
|
104
113
|
return Err(anyhow::anyhow!("Could not find file in tree!"));
|
|
@@ -132,6 +141,43 @@ impl MerkleTree {
|
|
|
132
141
|
Ok(count)
|
|
133
142
|
}
|
|
134
143
|
|
|
144
|
+
pub async fn get_num_embeddable_files_in_subtree(
|
|
145
|
+
&self,
|
|
146
|
+
absolute_path: PathBuf,
|
|
147
|
+
) -> Result<i32, anyhow::Error> {
|
|
148
|
+
let mut count = 0;
|
|
149
|
+
|
|
150
|
+
let absolute_path = match absolute_path.to_str() {
|
|
151
|
+
Some(s) => s.to_string(),
|
|
152
|
+
None => {
|
|
153
|
+
return Err(anyhow::anyhow!(
|
|
154
|
+
"get_num_embeddable_files_in_subtree: Failed to convert path to string"
|
|
155
|
+
))
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// TODO(sualeh): worth keeping this list sorted. its now a btree
|
|
160
|
+
|
|
161
|
+
for (_, file) in &self.files {
|
|
162
|
+
let file_reader = file.node.read().await;
|
|
163
|
+
match &file_reader.node_type {
|
|
164
|
+
NodeType::File(file_name) => {
|
|
165
|
+
if file_name.contains(&absolute_path) {
|
|
166
|
+
count += 1;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
NodeType::Branch(_) => {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
NodeType::ErrorNode(_) => {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
Ok(count)
|
|
179
|
+
}
|
|
180
|
+
|
|
135
181
|
pub async fn get_all_files(&self) -> Result<Vec<String>, anyhow::Error> {
|
|
136
182
|
let mut files = Vec::new();
|
|
137
183
|
|
|
@@ -188,83 +234,94 @@ impl MerkleTree {
|
|
|
188
234
|
pub async fn get_next_file_to_embed(
|
|
189
235
|
&mut self,
|
|
190
236
|
) -> Result<(String, Vec<String>), anyhow::Error> {
|
|
191
|
-
// the
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// if the path is not empty, we can iterate till we find the first child.
|
|
202
|
-
let mut potential_first_child = self.root.clone();
|
|
203
|
-
let mut is_branch = true;
|
|
204
|
-
let mut path = Vec::new();
|
|
205
|
-
|
|
206
|
-
while is_branch {
|
|
207
|
-
let node = {
|
|
208
|
-
let potential_first_child_reader = potential_first_child.read().await;
|
|
209
|
-
match &potential_first_child_reader.node_type {
|
|
210
|
-
NodeType::Branch(branch) => branch.clone(),
|
|
211
|
-
NodeType::File(_) => {
|
|
212
|
-
return Err(anyhow::anyhow!(
|
|
213
|
-
"get_next_file_to_embed: This should not happen! the branch happened to be file."
|
|
214
|
-
));
|
|
215
|
-
}
|
|
216
|
-
NodeType::ErrorNode(_) => {
|
|
217
|
-
return Err(anyhow::anyhow!("Cursor is an error node!"));
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
};
|
|
237
|
+
// if the cursor is none, set it to 0
|
|
238
|
+
let cursor = match self.cursor {
|
|
239
|
+
Some(cursor) => cursor,
|
|
240
|
+
None => {
|
|
241
|
+
self.cursor = Some(0);
|
|
242
|
+
0
|
|
243
|
+
}
|
|
244
|
+
};
|
|
221
245
|
|
|
222
|
-
|
|
223
|
-
|
|
246
|
+
// get the thing at the cursor. while we dont find a file, we keep incrementing the cursor.
|
|
247
|
+
let mut cursor = cursor;
|
|
248
|
+
loop {
|
|
249
|
+
// O(log n)
|
|
250
|
+
let file = match self.files.values().nth(cursor) {
|
|
251
|
+
Some(file) => file,
|
|
252
|
+
None => {
|
|
253
|
+
return Err(anyhow::anyhow!("Could not find file to embed!"));
|
|
254
|
+
}
|
|
255
|
+
};
|
|
224
256
|
|
|
225
|
-
|
|
226
|
-
|
|
257
|
+
let file_reader = file.node.read().await;
|
|
258
|
+
match &file_reader.node_type {
|
|
259
|
+
NodeType::File(f) => {
|
|
260
|
+
// update the cursor.
|
|
261
|
+
self.cursor = Some(cursor + 1);
|
|
262
|
+
let spline = self.get_spline(f).await?;
|
|
263
|
+
return Ok((f.clone(), spline));
|
|
264
|
+
}
|
|
265
|
+
NodeType::Branch(_) => {
|
|
266
|
+
cursor += 1;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
NodeType::ErrorNode(_) => {
|
|
270
|
+
cursor += 1;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
227
276
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
277
|
+
pub async fn get_all_dir_files_to_embed(
|
|
278
|
+
&self,
|
|
279
|
+
absolute_path: &str,
|
|
280
|
+
) -> Result<Vec<String>, anyhow::Error> {
|
|
281
|
+
let mut files = Vec::new();
|
|
232
282
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
is_branch = true;
|
|
283
|
+
for (file_path, f) in &self.files {
|
|
284
|
+
if !file_path.contains(absolute_path) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
238
287
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
return Err(anyhow::anyhow!("Root has no children!"));
|
|
288
|
+
match f.node.read().await.node_type {
|
|
289
|
+
NodeType::File(_) => {
|
|
290
|
+
files.push(file_path.clone());
|
|
291
|
+
}
|
|
292
|
+
NodeType::Branch(_) => {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
NodeType::ErrorNode(_) => {
|
|
296
|
+
continue;
|
|
249
297
|
}
|
|
250
298
|
}
|
|
251
299
|
}
|
|
252
300
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
// UNWRAP checked and fine. see the none case above.
|
|
257
|
-
let cursor_name = self.cursor.as_ref().unwrap();
|
|
258
|
-
let cursor_reader = cursor_name.read().await;
|
|
259
|
-
|
|
260
|
-
// invariant: you must be a file!!
|
|
301
|
+
Ok(files)
|
|
302
|
+
}
|
|
261
303
|
|
|
262
|
-
|
|
304
|
+
pub async fn get_spline(
|
|
305
|
+
&self,
|
|
306
|
+
absolute_path: &str,
|
|
307
|
+
) -> Result<Vec<String>, anyhow::Error> {
|
|
308
|
+
let mut files = Vec::new();
|
|
263
309
|
|
|
264
|
-
|
|
265
|
-
|
|
310
|
+
let current_node = match self.files.get(absolute_path) {
|
|
311
|
+
Some(node) => node.node.clone(),
|
|
312
|
+
None => return Err(anyhow::anyhow!("File not found: {}", absolute_path)),
|
|
313
|
+
};
|
|
314
|
+
let mut stack = Vec::new();
|
|
315
|
+
stack.push(current_node);
|
|
266
316
|
|
|
267
|
-
|
|
317
|
+
while let Some(node) = stack.pop() {
|
|
318
|
+
let parent = node.read().await.parent.clone();
|
|
319
|
+
if let Some(parent) = parent {
|
|
320
|
+
files.push(parent.read().await.hash.clone());
|
|
321
|
+
stack.push(parent);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
Ok(files)
|
|
268
325
|
}
|
|
269
326
|
|
|
270
327
|
/// creates a new node and attaches it to the current tree.
|