perf: optimize torrent store with HashMap for O(1) updates
All checks were successful
Build MIPS Binary / build (push) Successful in 4m57s
All checks were successful
Build MIPS Binary / build (push) Successful in 4m57s
This commit is contained in:
@@ -6,52 +6,47 @@ use crate::api;
|
|||||||
pub fn Sidebar() -> impl IntoView {
|
pub fn Sidebar() -> impl IntoView {
|
||||||
let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
|
let store = use_context::<crate::store::TorrentStore>().expect("store not provided");
|
||||||
|
|
||||||
let total_count = move || store.torrents.get().len();
|
let total_count = move || store.torrents.with(|map| map.len());
|
||||||
let downloading_count = move || {
|
let downloading_count = move || {
|
||||||
store
|
store.torrents.with(|map| {
|
||||||
.torrents
|
map.values()
|
||||||
.get()
|
|
||||||
.iter()
|
|
||||||
.filter(|t| t.status == shared::TorrentStatus::Downloading)
|
.filter(|t| t.status == shared::TorrentStatus::Downloading)
|
||||||
.count()
|
.count()
|
||||||
|
})
|
||||||
};
|
};
|
||||||
let seeding_count = move || {
|
let seeding_count = move || {
|
||||||
store
|
store.torrents.with(|map| {
|
||||||
.torrents
|
map.values()
|
||||||
.get()
|
|
||||||
.iter()
|
|
||||||
.filter(|t| t.status == shared::TorrentStatus::Seeding)
|
.filter(|t| t.status == shared::TorrentStatus::Seeding)
|
||||||
.count()
|
.count()
|
||||||
|
})
|
||||||
};
|
};
|
||||||
let completed_count = move || {
|
let completed_count = move || {
|
||||||
store
|
store.torrents.with(|map| {
|
||||||
.torrents
|
map.values()
|
||||||
.get()
|
|
||||||
.iter()
|
|
||||||
.filter(|t| {
|
.filter(|t| {
|
||||||
t.status == shared::TorrentStatus::Seeding
|
t.status == shared::TorrentStatus::Seeding
|
||||||
|| (t.status == shared::TorrentStatus::Paused && t.percent_complete >= 100.0)
|
|| (t.status == shared::TorrentStatus::Paused && t.percent_complete >= 100.0)
|
||||||
})
|
})
|
||||||
.count()
|
.count()
|
||||||
|
})
|
||||||
};
|
};
|
||||||
let paused_count = move || {
|
let paused_count = move || {
|
||||||
store
|
store.torrents.with(|map| {
|
||||||
.torrents
|
map.values()
|
||||||
.get()
|
|
||||||
.iter()
|
|
||||||
.filter(|t| t.status == shared::TorrentStatus::Paused)
|
.filter(|t| t.status == shared::TorrentStatus::Paused)
|
||||||
.count()
|
.count()
|
||||||
|
})
|
||||||
};
|
};
|
||||||
let inactive_count = move || {
|
let inactive_count = move || {
|
||||||
store
|
store.torrents.with(|map| {
|
||||||
.torrents
|
map.values()
|
||||||
.get()
|
|
||||||
.iter()
|
|
||||||
.filter(|t| {
|
.filter(|t| {
|
||||||
t.status == shared::TorrentStatus::Paused
|
t.status == shared::TorrentStatus::Paused
|
||||||
|| t.status == shared::TorrentStatus::Error
|
|| t.status == shared::TorrentStatus::Error
|
||||||
})
|
})
|
||||||
.count()
|
.count()
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let close_drawer = move || {
|
let close_drawer = move || {
|
||||||
|
|||||||
@@ -82,9 +82,10 @@ pub fn TorrentTable() -> impl IntoView {
|
|||||||
let sort_dir = create_rw_signal(SortDirection::Descending);
|
let sort_dir = create_rw_signal(SortDirection::Descending);
|
||||||
|
|
||||||
let filtered_torrents = move || {
|
let filtered_torrents = move || {
|
||||||
let mut torrents = store
|
// Convert HashMap values to Vec for filtering and sorting
|
||||||
.torrents
|
let torrents: Vec<shared::Torrent> = store.torrents.with(|map| map.values().cloned().collect());
|
||||||
.get()
|
|
||||||
|
let mut torrents = torrents
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|t| {
|
.filter(|t| {
|
||||||
let filter = store.filter.get();
|
let filter = store.filter.get();
|
||||||
|
|||||||
@@ -113,9 +113,11 @@ impl FilterStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct TorrentStore {
|
pub struct TorrentStore {
|
||||||
pub torrents: RwSignal<Vec<Torrent>>,
|
pub torrents: RwSignal<HashMap<String, Torrent>>,
|
||||||
pub filter: RwSignal<FilterStatus>,
|
pub filter: RwSignal<FilterStatus>,
|
||||||
pub search_query: RwSignal<String>,
|
pub search_query: RwSignal<String>,
|
||||||
pub global_stats: RwSignal<GlobalStats>,
|
pub global_stats: RwSignal<GlobalStats>,
|
||||||
@@ -124,7 +126,7 @@ pub struct TorrentStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide_torrent_store() {
|
pub fn provide_torrent_store() {
|
||||||
let torrents = create_rw_signal(Vec::<Torrent>::new());
|
let torrents = create_rw_signal(HashMap::new());
|
||||||
let filter = create_rw_signal(FilterStatus::All);
|
let filter = create_rw_signal(FilterStatus::All);
|
||||||
let search_query = create_rw_signal(String::new());
|
let search_query = create_rw_signal(String::new());
|
||||||
let global_stats = create_rw_signal(GlobalStats::default());
|
let global_stats = create_rw_signal(GlobalStats::default());
|
||||||
@@ -193,12 +195,15 @@ pub fn provide_torrent_store() {
|
|||||||
if let Ok(event) = serde_json::from_str::<AppEvent>(&data_str) {
|
if let Ok(event) = serde_json::from_str::<AppEvent>(&data_str) {
|
||||||
match event {
|
match event {
|
||||||
AppEvent::FullList { torrents: list, .. } => {
|
AppEvent::FullList { torrents: list, .. } => {
|
||||||
torrents.set(list);
|
let map: HashMap<String, Torrent> = list
|
||||||
|
.into_iter()
|
||||||
|
.map(|t| (t.hash.clone(), t))
|
||||||
|
.collect();
|
||||||
|
torrents.set(map);
|
||||||
}
|
}
|
||||||
AppEvent::Update(update) => {
|
AppEvent::Update(update) => {
|
||||||
torrents.update(|list| {
|
torrents.update(|map| {
|
||||||
if let Some(t) = list.iter_mut().find(|t| t.hash == update.hash)
|
if let Some(t) = map.get_mut(&update.hash) {
|
||||||
{
|
|
||||||
if let Some(name) = update.name {
|
if let Some(name) = update.name {
|
||||||
t.name = name;
|
t.name = name;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user