@anysphere/file-service 0.0.0-e3fdf62d → 0.0.0-e9ef07ca

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/src/lib.rs CHANGED
@@ -1,37 +1,107 @@
1
+ #![windows_subsystem = "windows"]
1
2
  #![deny(clippy::all)]
3
+ #![deny(unsafe_op_in_unsafe_fn)]
2
4
  pub mod file_utils;
3
- pub mod git_utils;
4
5
  pub mod merkle_tree;
5
6
 
6
- use std::vec;
7
+ use std::{collections::HashSet, vec};
7
8
 
9
+ use anyhow::Context;
8
10
  use merkle_tree::{LocalConstruction, MerkleTree};
11
+ use tracing::{info, Level, subscriber};
12
+ use tracing_appender::rolling::{RollingFileAppender, Rotation};
13
+ use tracing_subscriber::fmt;
14
+ use tracing_subscriber::prelude::*;
15
+ use tracing_appender::non_blocking::WorkerGuard;
9
16
 
10
17
  #[macro_use]
11
18
  extern crate napi_derive;
12
19
 
20
+ pub enum GuardType {
21
+ // Guard(tracing_axiom::Guard),
22
+ WorkerGuard(tracing_appender::non_blocking::WorkerGuard),
23
+ }
24
+
13
25
  #[napi]
14
26
  pub struct MerkleClient {
15
27
  tree: MerkleTree,
16
- root_directory: String,
28
+ absolute_root_directory: String,
29
+ _guard: Option<GuardType>,
30
+ }
31
+
32
+ pub fn init_logger() -> Option<GuardType> {
33
+ #[cfg(feature = "debugfile")]
34
+ let _guard = {
35
+ let file_appender =
36
+ RollingFileAppender::new(Rotation::NEVER, "./", "rust_log.txt");
37
+ let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
38
+ let subscriber = fmt::Subscriber::builder()
39
+ .with_max_level(Level::TRACE)
40
+ .with_writer(non_blocking)
41
+ .with_ansi(false)
42
+ .with_line_number(true)
43
+ .finish();
44
+
45
+ let _ = tracing::subscriber::set_global_default(subscriber);
46
+
47
+ Some(GuardType::WorkerGuard(_guard))
48
+ };
49
+
50
+ #[cfg(not(feature = "debugfile"))]
51
+ let _guard = {
52
+ // let (axiom_layer, _guard) = tracing_axiom::builder().with_token("xaat-a51088e6-7889-41c0-b440-cfd4601acdd7").with_dataset("local-indexing").layer().ok()?;
53
+ // // let fmt_layer = fmt::layer().with_level(true).with_ansi(false).with_line_number(true);
54
+
55
+ // let _ = tracing_subscriber::registry().with(axiom_layer).try_init().ok()?;
56
+ // // let _ = tracing::subscriber::set_global_default(subscriber);
57
+
58
+ // info!("Tracing initialized! in rust");
59
+
60
+ None
61
+ };
62
+
63
+ _guard
17
64
  }
18
65
 
19
66
  #[napi]
20
67
  impl MerkleClient {
21
68
  #[napi(constructor)]
22
- pub fn new(root_directory: String) -> MerkleClient {
69
+ pub fn new(absolute_root_directory: String) -> MerkleClient {
70
+ let _guard = init_logger();
71
+
72
+ // let canonical_root_directory = std::path::Path::new(&absolute_root_directory);
73
+ // use dunce::canonicalize;
74
+ // let canonical_root_directory = match dunce::canonicalize(&canonical_root_directory) {
75
+ // Ok(path) => path.to_str().unwrap_or(&absolute_root_directory).to_string().to_lowercase(),
76
+ // Err(e) => {
77
+ // info!("Error in canonicalizing path: path: {:?}, error {:?}", canonical_root_directory, e);
78
+ // absolute_root_directory
79
+ // }
80
+ // };
81
+
23
82
  MerkleClient {
24
83
  tree: MerkleTree::empty_tree(),
25
- root_directory,
84
+ absolute_root_directory,
85
+ _guard,
26
86
  }
27
87
  }
28
88
 
29
89
  #[napi]
30
- pub async unsafe fn init(&mut self) -> Result<(), napi::Error> {
90
+ pub async unsafe fn init(
91
+ &mut self,
92
+ git_ignored_files: Vec<String>,
93
+ is_git_repo: bool,
94
+ ) -> Result<(), napi::Error> {
31
95
  // 1. compute the merkle tree
32
96
  // 2. update the backend
33
97
  // 3. sync with the remote
34
- self.compute_merkle_tree().await?;
98
+ info!("Merkle tree compute started!");
99
+ info!("Root directory: {:?}", self.absolute_root_directory);
100
+ unsafe {
101
+ self
102
+ .compute_merkle_tree(git_ignored_files, is_git_repo)
103
+ .await?;
104
+ }
35
105
 
36
106
  Ok(())
37
107
  }
@@ -40,12 +110,27 @@ impl MerkleClient {
40
110
  unimplemented!("Interrupt is not implemented yet");
41
111
  }
42
112
 
43
- // #[napi]
113
+ #[napi]
44
114
  pub async unsafe fn compute_merkle_tree(
45
115
  &mut self,
116
+ git_ignored_files: Vec<String>,
117
+ is_git_repo: bool,
46
118
  ) -> Result<(), napi::Error> {
47
- let t =
48
- MerkleTree::construct_merkle_tree(self.root_directory.clone()).await;
119
+ // make the git ignored files into a hash set
120
+ let mut git_ignored_set = HashSet::from_iter(git_ignored_files.into_iter());
121
+
122
+ // if the hashset itself contains the root directory, then we should remove it.
123
+ // this is because the root directory is not a file, and we don't want to ignore it.
124
+ if git_ignored_set.contains(&self.absolute_root_directory) {
125
+ git_ignored_set.remove(&self.absolute_root_directory);
126
+ }
127
+
128
+ let t = MerkleTree::construct_merkle_tree(
129
+ self.absolute_root_directory.clone(),
130
+ git_ignored_set,
131
+ is_git_repo,
132
+ )
133
+ .await;
49
134
 
50
135
  match t {
51
136
  Ok(tree) => {
@@ -72,15 +157,42 @@ impl MerkleClient {
72
157
  #[napi]
73
158
  pub async fn get_subtree_hash(
74
159
  &self,
75
- path: String,
160
+ relative_path: String,
76
161
  ) -> Result<String, napi::Error> {
77
- let hash = self.tree.get_subtree_hash(path).await;
162
+ let relative_path_without_leading_slash = match relative_path
163
+ .strip_prefix('.')
164
+ {
165
+ Some(path) => path.strip_prefix(std::path::MAIN_SEPARATOR).unwrap_or(""),
166
+ None => relative_path.as_str(),
167
+ };
168
+
169
+ let absolute_path = if !relative_path_without_leading_slash.is_empty() {
170
+ std::path::Path::new(&self.absolute_root_directory)
171
+ .join(relative_path_without_leading_slash)
172
+ } else {
173
+ std::path::Path::new(&self.absolute_root_directory).to_path_buf()
174
+ };
175
+
176
+ let absolute_path_string = match absolute_path.to_str() {
177
+ Some(path) => path.to_string(),
178
+ None => {
179
+ return Err(napi::Error::new(
180
+ napi::Status::Unknown,
181
+ format!("some string error"),
182
+ ))
183
+ }
184
+ };
185
+
186
+ let hash = self
187
+ .tree
188
+ .get_subtree_hash(absolute_path_string.as_str())
189
+ .await;
78
190
 
79
191
  match hash {
80
192
  Ok(hash) => Ok(hash),
81
193
  Err(e) => Err(napi::Error::new(
82
194
  napi::Status::Unknown,
83
- format!("Error in get_subtree_hash: {:?}", e),
195
+ format!("Error in get_subtree_hash. \nRelative path: {:?}, \nAbsolute path: {:?}, \nRoot directory: {:?}\nError: {:?}", &relative_path, absolute_path, self.absolute_root_directory, e)
84
196
  )),
85
197
  }
86
198
  }
@@ -98,6 +210,28 @@ impl MerkleClient {
98
210
  }
99
211
  }
100
212
 
213
+ pub async fn get_num_embeddable_files_in_subtree(
214
+ &self,
215
+ relative_path: String,
216
+ ) -> Result<i32, napi::Error> {
217
+ let absolute_path = std::path::Path::new(&self.absolute_root_directory)
218
+ .join(relative_path)
219
+ .canonicalize()?;
220
+
221
+ let num = self
222
+ .tree
223
+ .get_num_embeddable_files_in_subtree(absolute_path)
224
+ .await;
225
+
226
+ match num {
227
+ Ok(num) => Ok(num),
228
+ Err(e) => Err(napi::Error::new(
229
+ napi::Status::Unknown,
230
+ format!("Error in get_num_embeddable_files_in_subtree: {:?}", e),
231
+ )),
232
+ }
233
+ }
234
+
101
235
  #[napi]
102
236
  pub async fn get_all_files(&self) -> Result<Vec<String>, napi::Error> {
103
237
  let files = self.tree.get_all_files().await;
@@ -111,6 +245,28 @@ impl MerkleClient {
111
245
  }
112
246
  }
113
247
 
248
+ #[napi]
249
+ pub async fn get_all_dir_files_to_embed(
250
+ &self,
251
+ absolute_file_path: String,
252
+ ) -> Result<Vec<String>, napi::Error> {
253
+ // let absolute_path = absolute_file_path.to_lowercase();
254
+ // let absolute_path_str = absolute_path.as_str();
255
+
256
+ let files = self
257
+ .tree
258
+ .get_all_dir_files_to_embed(absolute_file_path.as_str())
259
+ .await;
260
+
261
+ match files {
262
+ Ok(files) => Ok(files),
263
+ Err(e) => Err(napi::Error::new(
264
+ napi::Status::Unknown,
265
+ format!("Error in get_all_dir_files_to_embed: {:?}", e),
266
+ )),
267
+ }
268
+ }
269
+
114
270
  #[napi]
115
271
  pub async unsafe fn get_next_file_to_embed(
116
272
  &mut self,
@@ -125,7 +281,6 @@ impl MerkleClient {
125
281
 
126
282
  let ret = vec![file];
127
283
  let ret = ret.into_iter().chain(path.into_iter()).collect::<Vec<_>>();
128
-
129
284
  Ok(ret)
130
285
  }
131
286
  Err(e) => Err(napi::Error::new(
@@ -135,6 +290,25 @@ impl MerkleClient {
135
290
  }
136
291
  }
137
292
 
293
+ // FIXME(sualeh): get_spline
294
+ #[napi]
295
+ pub async fn get_spline(
296
+ &self,
297
+ absolute_file_path: String,
298
+ ) -> Result<Vec<String>, napi::Error> {
299
+ // let absolute_path = absolute_file_path.to_lowercase();
300
+ // let absolute_path_str = absolute_path.as_str();
301
+ let spline = self.tree.get_spline(absolute_file_path.as_str()).await;
302
+
303
+ match spline {
304
+ Ok(spline) => Ok(spline),
305
+ Err(e) => Err(napi::Error::new(
306
+ napi::Status::Unknown,
307
+ format!("Error in get_spline: {:?}", e),
308
+ )),
309
+ }
310
+ }
311
+
138
312
  #[napi]
139
313
  pub async fn get_hashes_for_files(
140
314
  &self,
@@ -151,8 +325,8 @@ impl MerkleClient {
151
325
  }
152
326
  }
153
327
 
154
- // #[napi]
328
+ #[napi]
155
329
  pub fn update_root_directory(&mut self, root_directory: String) {
156
- self.root_directory = root_directory;
330
+ self.absolute_root_directory = root_directory;
157
331
  }
158
332
  }
@@ -3,17 +3,23 @@ use crate::merkle_tree::{
3
3
  };
4
4
 
5
5
  use super::{LocalConstruction, MerkleTree};
6
- use std::path::PathBuf;
7
- use std::{collections::HashMap, path::Path, sync::Arc};
6
+ use std::collections::{BTreeMap, HashSet};
7
+ use std::path::{Path, PathBuf};
8
8
  use tonic::async_trait;
9
9
 
10
10
  #[async_trait]
11
11
  impl LocalConstruction for MerkleTree {
12
+ #[tracing::instrument]
12
13
  async fn new(
13
14
  root_directory: Option<String>,
14
15
  ) -> Result<MerkleTree, anyhow::Error> {
16
+ let git_ignored_files = HashSet::<String>::new();
15
17
  if let Some(root_directory) = root_directory {
16
- let n = MerkleTree::construct_merkle_tree(root_directory).await;
18
+ let n = MerkleTree::construct_merkle_tree(
19
+ root_directory,
20
+ git_ignored_files,
21
+ false
22
+ ).await;
17
23
  return n;
18
24
  }
19
25
 
@@ -27,28 +33,50 @@ impl LocalConstruction for MerkleTree {
27
33
  /// 2. compute hash for each file
28
34
  /// 3. construct merkle tree
29
35
  /// 4. return merkle tree
36
+ #[tracing::instrument(skip(git_ignored_files_and_dirs))]
30
37
  async fn construct_merkle_tree(
31
- root_directory: String,
38
+ absolute_path_to_root_directory: String,
39
+ git_ignored_files_and_dirs: HashSet<String>,
40
+ is_git_repo: bool
32
41
  ) -> Result<MerkleTree, anyhow::Error> {
33
- let path = PathBuf::from(root_directory.clone());
42
+ let path = PathBuf::from(absolute_path_to_root_directory.clone());
34
43
  if !path.exists() {
35
44
  // FIXME: we should report this via a good logger.
36
45
  panic!("Root directory does not exist!");
37
46
  }
38
47
 
39
- let root_node = MerkleNode::new(path, None).await;
48
+ // 1. get all the gitignored files
49
+ // let git_ignored_files_and_dirs =
50
+ // match git_utils::list_ignored_files_and_directories(
51
+ // absolute_path_to_root_directory.as_str(),
52
+ // true,
53
+ // ) {
54
+ // Ok(git_ignored) => git_ignored,
55
+ // Err(_e) => HashSet::new(),
56
+ // };
57
+
58
+ let root_node = MerkleNode::new(
59
+ path,
60
+ None,
61
+ &git_ignored_files_and_dirs,
62
+ absolute_path_to_root_directory.as_str(),
63
+ is_git_repo
64
+ ).await;
65
+
40
66
  let mut mt = MerkleTree {
41
67
  root: root_node,
42
- files: HashMap::new(),
43
- root_path: root_directory,
68
+ files: BTreeMap::new(),
69
+ root_path: absolute_path_to_root_directory,
44
70
  cursor: None,
71
+ git_ignored_files_and_dirs,
72
+ is_git_repo
45
73
  };
46
74
 
47
75
  // we now iterate over all the nodes and add them to the hashmap
48
76
  // TODO(later): i can make this parallel.
49
77
  fn add_nodes_to_hashmap<'a>(
50
78
  node: &'a MerkleNodePtr,
51
- files: &'a mut HashMap<String, File>,
79
+ files: &'a mut BTreeMap<String, File>,
52
80
  ) -> PinnedFuture<'a, ()> {
53
81
  Box::pin(async move {
54
82
  let node_reader = node.read().await;
@@ -62,6 +90,13 @@ impl LocalConstruction for MerkleTree {
62
90
  }
63
91
  NodeType::File(file_name) => {
64
92
  let f = File { node: node.clone() };
93
+
94
+ // i dont reallly like this :(((
95
+ // let canonical_file_name = match dunce::canonicalize(file_name) {
96
+ // Ok(path) => path.to_str().unwrap_or(file_name).to_string(),
97
+ // Err(_) => file_name.clone(),
98
+ // };
99
+
65
100
  files.insert(file_name.clone(), f);
66
101
  }
67
102
  NodeType::ErrorNode(_) => {
@@ -73,9 +108,12 @@ impl LocalConstruction for MerkleTree {
73
108
 
74
109
  add_nodes_to_hashmap(&mt.root, &mut mt.files).await;
75
110
 
111
+ tracing::info!("number of files in the tree: {}", mt.files.len());
112
+
76
113
  Ok(mt)
77
114
  }
78
115
 
116
+ #[tracing::instrument]
79
117
  async fn update_file(
80
118
  &mut self,
81
119
  file_path: String,
@@ -115,6 +153,7 @@ impl LocalConstruction for MerkleTree {
115
153
  Ok(())
116
154
  }
117
155
 
156
+ #[tracing::instrument]
118
157
  async fn delete_file(
119
158
  &mut self,
120
159
  file_path: String,