refactor(backend): optimize diff logic and integrate DiffResult
This commit is contained in:
@@ -1,35 +1,31 @@
|
|||||||
use shared::{AppEvent, Torrent, TorrentUpdate};
|
use shared::{AppEvent, Torrent, TorrentUpdate};
|
||||||
|
|
||||||
pub fn diff_torrents(old: &[Torrent], new: &[Torrent]) -> Vec<AppEvent> {
|
#[derive(Debug)]
|
||||||
// 1. Structural Change Check
|
pub enum DiffResult {
|
||||||
// If length differs or any hash at specific index differs (simplistic view), send FullList.
|
NoChange,
|
||||||
// Ideally we should track "Added/Removed", but for simplicity and robustness as per prompt "FullList for big changes",
|
FullUpdate,
|
||||||
// we fallback to FullList on structural changes.
|
Partial(Vec<AppEvent>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn diff_torrents(old: &[Torrent], new: &[Torrent]) -> DiffResult {
|
||||||
|
// 1. Structural Check (Length or Order changed)
|
||||||
if old.len() != new.len() {
|
if old.len() != new.len() {
|
||||||
// Timestamp is needed for FullList? The definition is FullList(Vec, u64).
|
return DiffResult::FullUpdate;
|
||||||
// We'll let the caller handle the timestamp or pass it in?
|
|
||||||
// AppEvent in shared::lib.rs is FullList(Vec<Torrent>, u64).
|
|
||||||
// We'll return just the list decision here, or constructs events.
|
|
||||||
// Let's assume caller adds the u64 (disk space/timestamp).
|
|
||||||
// Actually, let's keep it simple: Return Option<Vec<AppEvent>>.
|
|
||||||
// But simply returning "NeedFullList" signal is easier if we can't accept u64 here.
|
|
||||||
// Let's change signature to return an enum or boolean flag if FullList needed.
|
|
||||||
return vec![]; // Special signal: Empty vec means "No diffs" or "Caller handles FullList"?
|
|
||||||
// This function is tricky if we don't have the u64.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for hash mismatch (order changed)
|
|
||||||
for (i, t) in new.iter().enumerate() {
|
for (i, t) in new.iter().enumerate() {
|
||||||
if old[i].hash != t.hash {
|
if old[i].hash != t.hash {
|
||||||
return vec![]; // Signal Full List needed
|
return DiffResult::FullUpdate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Field Updates
|
||||||
let mut events = Vec::new();
|
let mut events = Vec::new();
|
||||||
|
|
||||||
for (i, new_t) in new.iter().enumerate() {
|
for (i, new_t) in new.iter().enumerate() {
|
||||||
let old_t = &old[i];
|
let old_t = &old[i];
|
||||||
|
|
||||||
|
// Initialize with all None
|
||||||
let mut update = TorrentUpdate {
|
let mut update = TorrentUpdate {
|
||||||
hash: new_t.hash.clone(),
|
hash: new_t.hash.clone(),
|
||||||
name: None,
|
name: None,
|
||||||
@@ -45,6 +41,7 @@ pub fn diff_torrents(old: &[Torrent], new: &[Torrent]) -> Vec<AppEvent> {
|
|||||||
|
|
||||||
let mut has_changes = false;
|
let mut has_changes = false;
|
||||||
|
|
||||||
|
// Compare fields
|
||||||
if old_t.name != new_t.name {
|
if old_t.name != new_t.name {
|
||||||
update.name = Some(new_t.name.clone());
|
update.name = Some(new_t.name.clone());
|
||||||
has_changes = true;
|
has_changes = true;
|
||||||
@@ -61,7 +58,6 @@ pub fn diff_torrents(old: &[Torrent], new: &[Torrent]) -> Vec<AppEvent> {
|
|||||||
update.up_rate = Some(new_t.up_rate);
|
update.up_rate = Some(new_t.up_rate);
|
||||||
has_changes = true;
|
has_changes = true;
|
||||||
}
|
}
|
||||||
// Floating point comparison with epsilon
|
|
||||||
if (old_t.percent_complete - new_t.percent_complete).abs() > 0.01 {
|
if (old_t.percent_complete - new_t.percent_complete).abs() > 0.01 {
|
||||||
update.percent_complete = Some(new_t.percent_complete);
|
update.percent_complete = Some(new_t.percent_complete);
|
||||||
has_changes = true;
|
has_changes = true;
|
||||||
@@ -88,9 +84,10 @@ pub fn diff_torrents(old: &[Torrent], new: &[Torrent]) -> Vec<AppEvent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !events.is_empty() {
|
if events.is_empty() {
|
||||||
tracing::debug!("Generated {} updates", events.len());
|
DiffResult::NoChange
|
||||||
|
} else {
|
||||||
|
tracing::debug!("Generated {} partial updates", events.len());
|
||||||
|
DiffResult::Partial(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
events
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,30 +91,17 @@ async fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.as_secs();
|
.as_secs();
|
||||||
|
|
||||||
let mut structural_change = false;
|
match diff::diff_torrents(&previous_torrents, &new_torrents) {
|
||||||
if previous_torrents.len() != new_torrents.len() {
|
diff::DiffResult::FullUpdate => {
|
||||||
structural_change = true;
|
let _ =
|
||||||
} else {
|
event_bus_tx.send(AppEvent::FullList(new_torrents.clone(), now));
|
||||||
// Check for order/hash change
|
|
||||||
for (i, t) in new_torrents.iter().enumerate() {
|
|
||||||
if previous_torrents[i].hash != t.hash {
|
|
||||||
structural_change = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
diff::DiffResult::Partial(updates) => {
|
||||||
|
|
||||||
if structural_change {
|
|
||||||
// Structural change -> Send FullList
|
|
||||||
let _ = event_bus_tx.send(AppEvent::FullList(new_torrents.clone(), now));
|
|
||||||
} else {
|
|
||||||
// Same structure -> Calculate partial updates
|
|
||||||
let updates = diff::diff_torrents(&previous_torrents, &new_torrents);
|
|
||||||
if !updates.is_empty() {
|
|
||||||
for update in updates {
|
for update in updates {
|
||||||
let _ = event_bus_tx.send(update);
|
let _ = event_bus_tx.send(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
diff::DiffResult::NoChange => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
previous_torrents = new_torrents;
|
previous_torrents = new_torrents;
|
||||||
|
|||||||
Reference in New Issue
Block a user