Ver Fonte

fud: add `Resource::get_chunks_of_selection()` and `Resource::get_bytes_of_selection()`

epiphany há 7 meses atrás
pai
commit
9b59ce44c8
3 ficheiros alterados com 67 adições e 24 exclusões
  1. 1 1
      bin/fud/fud/src/download.rs
  2. 21 12
      bin/fud/fud/src/lib.rs
  3. 45 11
      bin/fud/fud/src/resource.rs

+ 1 - 1
bin/fud/fud/src/download.rs

@@ -289,7 +289,7 @@ async fn handle_chunk_reply(
 
 
     resource.total_bytes_downloaded += reply.chunk.len() as u64;
     resource.total_bytes_downloaded += reply.chunk.len() as u64;
     resource.target_bytes_downloaded +=
     resource.target_bytes_downloaded +=
-        resource.get_selected_bytes(ctx.chunked, &reply.chunk) as u64;
+        resource.get_selected_bytes(ctx.chunked, chunk_hash, reply.chunk.len()) as u64;
     resource.speeds.push(reply.chunk.len() as f64 / start_time.elapsed().as_secs_f64());
     resource.speeds.push(reply.chunk.len() as f64 / start_time.elapsed().as_secs_f64());
     if resource.speeds.len() > 12 {
     if resource.speeds.len() > 12 {
         resource.speeds = resource.speeds.split_off(resource.speeds.len() - 12); // Only keep the last few speeds
         resource.speeds = resource.speeds.split_off(resource.speeds.len() - 12); // Only keep the last few speeds

+ 21 - 12
bin/fud/fud/src/lib.rs

@@ -448,7 +448,7 @@ impl Fud {
                                      total_bytes_downloaded: u64,
                                      total_bytes_downloaded: u64,
                                      target_bytes_downloaded: u64| {
                                      target_bytes_downloaded: u64| {
             let files = match chunked {
             let files = match chunked {
-                Some(chunked) => resource.get_selected_files(chunked),
+                Some(chunked) => resource.get_selected_files(chunked, &resource.file_selection),
                 None => vec![],
                 None => vec![],
             };
             };
             let chunk_hashes = match chunked {
             let chunk_hashes = match chunked {
@@ -530,7 +530,8 @@ impl Fud {
                     continue;
                     continue;
                 }
                 }
             };
             };
-            let verify_res = self.verify_chunks(resource, &mut chunked).await;
+            let verify_res =
+                self.verify_chunks(resource, &mut chunked, &resource.file_selection).await;
             if let Err(e) = verify_res {
             if let Err(e) = verify_res {
                 error!(target: "fud::verify_resources()", "Error while verifying chunks of {}: {e}", hash_to_string(&resource.hash));
                 error!(target: "fud::verify_resources()", "Error while verifying chunks of {}: {e}", hash_to_string(&resource.hash));
                 update_resource(&mut resource, ResourceStatus::Incomplete, None, 0, 0).await;
                 update_resource(&mut resource, ResourceStatus::Incomplete, None, 0, 0).await;
@@ -712,7 +713,7 @@ impl Fud {
                 return Ok(())
                 return Ok(())
             }
             }
         };
         };
-        let files_vec: Vec<PathBuf> = resource.get_selected_files(&chunked);
+        let files_vec: Vec<PathBuf> = resource.get_selected_files(&chunked, files);
         drop(resources_read);
         drop(resources_read);
 
 
         // Create all files (and all necessary directories)
         // Create all files (and all necessary directories)
@@ -734,7 +735,7 @@ impl Fud {
         notify_event!(self, MetadataDownloadCompleted, resource);
         notify_event!(self, MetadataDownloadCompleted, resource);
 
 
         // Set of all chunks we need locally (including the ones we already have)
         // Set of all chunks we need locally (including the ones we already have)
-        let chunk_hashes = resource.get_selected_chunks(&chunked);
+        let chunk_hashes = resource.get_chunks_of_selection(&chunked, files);
 
 
         // Write all scraps to make sure the data on the filesystem is correct
         // Write all scraps to make sure the data on the filesystem is correct
         if let Err(e) = self.write_scraps(&mut chunked, &chunk_hashes).await {
         if let Err(e) = self.write_scraps(&mut chunked, &chunk_hashes).await {
@@ -743,7 +744,7 @@ impl Fud {
         }
         }
 
 
         // Mark locally available chunks as such
         // Mark locally available chunks as such
-        let verify_res = self.verify_chunks(&resource, &mut chunked).await;
+        let verify_res = self.verify_chunks(&resource, &mut chunked, files).await;
         if let Err(e) = verify_res {
         if let Err(e) = verify_res {
             dht_sub.unsubscribe().await;
             dht_sub.unsubscribe().await;
             error!(target: "fud::fetch_resource()", "Error while verifying chunks: {e}");
             error!(target: "fud::fetch_resource()", "Error while verifying chunks: {e}");
@@ -856,7 +857,7 @@ impl Fud {
         notify_event!(self, ResourceUpdated, resource);
         notify_event!(self, ResourceUpdated, resource);
 
 
         // Verify all chunks
         // Verify all chunks
-        self.verify_chunks(&resource, &mut chunked).await?;
+        self.verify_chunks(&resource, &mut chunked, &resource.last_file_selection).await?;
 
 
         let is_complete =
         let is_complete =
             chunked.iter().filter(|c| chunk_hashes.contains(&c.hash)).all(|c| c.available);
             chunked.iter().filter(|c| chunk_hashes.contains(&c.hash)).all(|c| c.available);
@@ -938,14 +939,13 @@ impl Fud {
 
 
     /// Iterate over chunks and find which chunks are available locally,
     /// Iterate over chunks and find which chunks are available locally,
     /// either in the filesystem (using geode::verify_chunks()) or in scraps.
     /// either in the filesystem (using geode::verify_chunks()) or in scraps.
-    /// `chunk_hashes` is the list of chunk hashes we want to take into account, `None` means to
-    /// take all chunks into account.
-    /// Return the scraps in a HashMap, and the size in bytes of locally available data
-    /// (downloaded and downloaded+targeted).
+    /// Return the size in bytes of locally available data (downloaded and
+    /// downloaded+targeted).
     pub async fn verify_chunks(
     pub async fn verify_chunks(
         &self,
         &self,
         resource: &Resource,
         resource: &Resource,
         chunked: &mut ChunkedStorage,
         chunked: &mut ChunkedStorage,
+        file_selection: &FileSelection,
     ) -> Result<(u64, u64)> {
     ) -> Result<(u64, u64)> {
         let chunks = chunked.get_chunks().clone();
         let chunks = chunked.get_chunks().clone();
         let mut bytes: HashMap<blake3::Hash, (usize, usize)> = HashMap::new();
         let mut bytes: HashMap<blake3::Hash, (usize, usize)> = HashMap::new();
@@ -1025,8 +1025,16 @@ impl Fud {
 
 
             // Update the sums of locally available data
             // Update the sums of locally available data
             bytes.insert(
             bytes.insert(
-                *chunk_hash,
-                (scrap.chunk.len(), resource.get_selected_bytes(chunked, &scrap.chunk)),
+                chunk.hash,
+                (
+                    scrap.chunk.len(),
+                    resource.get_bytes_of_selection(
+                        chunked,
+                        file_selection,
+                        &chunk.hash,
+                        scrap.chunk.len(),
+                    ),
+                ),
             );
             );
         }
         }
 
 
@@ -1136,6 +1144,7 @@ impl Fud {
                 path: path.to_path_buf(),
                 path: path.to_path_buf(),
                 status: ResourceStatus::Seeding,
                 status: ResourceStatus::Seeding,
                 file_selection: FileSelection::All,
                 file_selection: FileSelection::All,
+                last_file_selection: FileSelection::All,
                 total_chunks_count: chunk_hashes.len() as u64,
                 total_chunks_count: chunk_hashes.len() as u64,
                 target_chunks_count: chunk_hashes.len() as u64,
                 target_chunks_count: chunk_hashes.len() as u64,
                 total_chunks_downloaded: chunk_hashes.len() as u64,
                 total_chunks_downloaded: chunk_hashes.len() as u64,

+ 45 - 11
bin/fud/fud/src/resource.rs

@@ -100,6 +100,8 @@ pub struct Resource {
     pub status: ResourceStatus,
     pub status: ResourceStatus,
     /// The files the user wants to download
     /// The files the user wants to download
     pub file_selection: FileSelection,
     pub file_selection: FileSelection,
+    /// The last files the user wanted to download
+    pub last_file_selection: FileSelection,
 
 
     /// Total number of chunks
     /// Total number of chunks
     pub total_chunks_count: u64,
     pub total_chunks_count: u64,
@@ -138,7 +140,8 @@ impl Resource {
             rtype,
             rtype,
             path: path.to_path_buf(),
             path: path.to_path_buf(),
             status,
             status,
-            file_selection,
+            file_selection: file_selection.clone(),
+            last_file_selection: file_selection,
             total_chunks_count: 0,
             total_chunks_count: 0,
             target_chunks_count: 0,
             target_chunks_count: 0,
             total_chunks_downloaded: 0,
             total_chunks_downloaded: 0,
@@ -164,8 +167,12 @@ impl Resource {
     }
     }
 
 
     /// Returns the list of selected files (absolute paths).
     /// Returns the list of selected files (absolute paths).
-    pub fn get_selected_files(&self, chunked: &ChunkedStorage) -> Vec<PathBuf> {
-        match &self.file_selection {
+    pub fn get_selected_files(
+        &self,
+        chunked: &ChunkedStorage,
+        file_selection: &FileSelection,
+    ) -> Vec<PathBuf> {
+        match &file_selection {
             FileSelection::Set(files) => files
             FileSelection::Set(files) => files
                 .iter()
                 .iter()
                 .map(|file| self.path.join(file))
                 .map(|file| self.path.join(file))
@@ -175,9 +182,19 @@ impl Resource {
         }
         }
     }
     }
 
 
-    /// Returns the (sub)set of chunk hashes in a ChunkedStorage for a file selection.
+    /// Returns the (sub)set of chunk hashes in a ChunkedStorage for the
+    /// resource's file selection.
     pub fn get_selected_chunks(&self, chunked: &ChunkedStorage) -> HashSet<blake3::Hash> {
     pub fn get_selected_chunks(&self, chunked: &ChunkedStorage) -> HashSet<blake3::Hash> {
-        match &self.file_selection {
+        self.get_chunks_of_selection(chunked, &self.file_selection)
+    }
+
+    /// Returns the (sub)set of chunk hashes in a ChunkedStorage for a file selection.
+    pub fn get_chunks_of_selection(
+        &self,
+        chunked: &ChunkedStorage,
+        file_selection: &FileSelection,
+    ) -> HashSet<blake3::Hash> {
+        match &file_selection {
             FileSelection::Set(files) => {
             FileSelection::Set(files) => {
                 let mut chunks = HashSet::new();
                 let mut chunks = HashSet::new();
                 for file in files {
                 for file in files {
@@ -189,16 +206,32 @@ impl Resource {
         }
         }
     }
     }
 
 
-    /// Returns the number of bytes we want from a chunk (depends on the file selection).
-    pub fn get_selected_bytes(&self, chunked: &ChunkedStorage, chunk: &[u8]) -> usize {
+    /// Returns the number of bytes we want from a chunk (depends on the
+    /// resource's file selection).
+    pub fn get_selected_bytes(
+        &self,
+        chunked: &ChunkedStorage,
+        chunk_hash: &blake3::Hash,
+        chunk_size: usize,
+    ) -> usize {
+        self.get_bytes_of_selection(chunked, &self.file_selection, chunk_hash, chunk_size)
+    }
+
+    /// Returns the number of bytes we selected from a chunk.
+    pub fn get_bytes_of_selection(
+        &self,
+        chunked: &ChunkedStorage,
+        file_selection: &FileSelection,
+        chunk_hash: &blake3::Hash,
+        chunk_size: usize,
+    ) -> usize {
         // If `FileSelection` is not a set, we want all bytes from a chunk
         // If `FileSelection` is not a set, we want all bytes from a chunk
-        let file_set = if let FileSelection::Set(files) = &self.file_selection {
+        let file_set = if let FileSelection::Set(files) = &file_selection {
             files
             files
         } else {
         } else {
-            return chunk.len();
+            return chunk_size;
         };
         };
 
 
-        let chunk_hash = blake3::hash(chunk);
         let chunk_index = match chunked.iter().position(|c| c.hash == *chunk_hash) {
         let chunk_index = match chunked.iter().position(|c| c.hash == *chunk_hash) {
             Some(index) => index,
             Some(index) => index,
             None => {
             None => {
@@ -207,7 +240,7 @@ impl Resource {
         };
         };
 
 
         let files = chunked.get_files();
         let files = chunked.get_files();
-        let chunk_length = chunk.len();
+        let chunk_length = chunk_size;
         let position = (chunk_index as u64) * (MAX_CHUNK_SIZE as u64);
         let position = (chunk_index as u64) * (MAX_CHUNK_SIZE as u64);
         let mut total_selected_bytes = 0;
         let mut total_selected_bytes = 0;
 
 
@@ -326,6 +359,7 @@ impl From<JsonValue> for Resource {
             path,
             path,
             status,
             status,
             file_selection: FileSelection::All, // TODO
             file_selection: FileSelection::All, // TODO
+            last_file_selection: FileSelection::All, // TODO
             total_chunks_count,
             total_chunks_count,
             target_chunks_count,
             target_chunks_count,
             total_chunks_downloaded,
             total_chunks_downloaded,