chore: refactor to support multi search
This commit is contained in:
@@ -8,7 +8,7 @@ use crate::message::peer::{
|
|||||||
use crate::message::server::MessageFactory;
|
use crate::message::server::MessageFactory;
|
||||||
use crate::message::{Handlers, Message, MessageReader, MessageType};
|
use crate::message::{Handlers, Message, MessageReader, MessageType};
|
||||||
use crate::peer::Peer;
|
use crate::peer::Peer;
|
||||||
use crate::types::{Download, FileSearchResult, Transfer};
|
use crate::types::{Download, SearchResult, Transfer};
|
||||||
use crate::{debug, error, trace, warn};
|
use crate::{debug, error, trace, warn};
|
||||||
|
|
||||||
use std::io::{self, Error, Write};
|
use std::io::{self, Error, Write};
|
||||||
@@ -20,7 +20,7 @@ use std::time::{Duration, Instant};
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PeerMessage {
|
pub enum PeerMessage {
|
||||||
SendMessage(Message),
|
SendMessage(Message),
|
||||||
FileSearchResult(FileSearchResult),
|
FileSearchResult(SearchResult),
|
||||||
TransferRequest(Transfer),
|
TransferRequest(Transfer),
|
||||||
UploadFailed(String, String),
|
UploadFailed(String, String),
|
||||||
TransferResponse {
|
TransferResponse {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::{
|
|||||||
actor::{peer_registry::PeerRegistry, ActorSystem},
|
actor::{peer_registry::PeerRegistry, ActorSystem},
|
||||||
error::{Result, SoulseekRs},
|
error::{Result, SoulseekRs},
|
||||||
peer::{listen::Listen, ConnectionType, DownloadPeer, NewPeer, Peer},
|
peer::{listen::Listen, ConnectionType, DownloadPeer, NewPeer, Peer},
|
||||||
types::{Download, FileSearchResult},
|
types::{Download, Search, SearchResult},
|
||||||
utils::{md5, thread_pool::ThreadPool},
|
utils::{md5, thread_pool::ThreadPool},
|
||||||
Transfer,
|
Transfer,
|
||||||
};
|
};
|
||||||
@@ -70,7 +70,7 @@ impl Default for ClientSettings {
|
|||||||
pub enum ClientOperation {
|
pub enum ClientOperation {
|
||||||
NewPeer(NewPeer),
|
NewPeer(NewPeer),
|
||||||
ConnectToPeer(Peer),
|
ConnectToPeer(Peer),
|
||||||
SearchResult(FileSearchResult),
|
SearchResult(SearchResult),
|
||||||
PeerDisconnected(String, Option<SoulseekRs>),
|
PeerDisconnected(String, Option<SoulseekRs>),
|
||||||
PierceFireWall(Peer),
|
PierceFireWall(Peer),
|
||||||
DownloadFromPeer(u32, Peer, bool),
|
DownloadFromPeer(u32, Peer, bool),
|
||||||
@@ -89,7 +89,7 @@ pub struct ClientContext {
|
|||||||
pub peer_registry: Option<PeerRegistry>,
|
pub peer_registry: Option<PeerRegistry>,
|
||||||
sender: Option<Sender<ClientOperation>>,
|
sender: Option<Sender<ClientOperation>>,
|
||||||
server_sender: Option<Sender<ServerMessage>>,
|
server_sender: Option<Sender<ServerMessage>>,
|
||||||
search_results: Vec<FileSearchResult>,
|
searches: HashMap<String, Search>,
|
||||||
pub download_tokens: HashMap<u32, Download>,
|
pub download_tokens: HashMap<u32, Download>,
|
||||||
actor_system: Arc<ActorSystem>,
|
actor_system: Arc<ActorSystem>,
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ impl ClientContext {
|
|||||||
peer_registry: None,
|
peer_registry: None,
|
||||||
sender: None,
|
sender: None,
|
||||||
server_sender: None,
|
server_sender: None,
|
||||||
search_results: Vec::new(),
|
searches: HashMap::new(),
|
||||||
download_tokens: HashMap::new(),
|
download_tokens: HashMap::new(),
|
||||||
actor_system,
|
actor_system,
|
||||||
}
|
}
|
||||||
@@ -234,7 +234,7 @@ impl Client {
|
|||||||
&self,
|
&self,
|
||||||
query: &str,
|
query: &str,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
) -> Result<Vec<FileSearchResult>> {
|
) -> Result<Vec<SearchResult>> {
|
||||||
self.search_with_cancel(query, timeout, None)
|
self.search_with_cancel(query, timeout, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,15 +243,22 @@ impl Client {
|
|||||||
query: &str,
|
query: &str,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
cancel_flag: Option<Arc<AtomicBool>>,
|
cancel_flag: Option<Arc<AtomicBool>>,
|
||||||
) -> Result<Vec<FileSearchResult>> {
|
) -> Result<Vec<SearchResult>> {
|
||||||
info!("Searching for {}", query);
|
info!("Searching for {}", query);
|
||||||
|
|
||||||
// Clear previous search results
|
|
||||||
self.context.write().unwrap().search_results.clear();
|
|
||||||
|
|
||||||
if let Some(handle) = &self.server_handle {
|
if let Some(handle) = &self.server_handle {
|
||||||
let hash = md5::md5(query);
|
let hash = md5::md5(query);
|
||||||
let token = u32::from_str_radix(&hash[0..5], 16)?;
|
let token = u32::from_str_radix(&hash[0..5], 16)?;
|
||||||
|
|
||||||
|
// Initialize new search with query string as key
|
||||||
|
self.context.write().unwrap().searches.insert(
|
||||||
|
query.to_string(),
|
||||||
|
Search {
|
||||||
|
token,
|
||||||
|
results: Vec::new(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let _ = handle.send(ServerMessage::FileSearch {
|
let _ = handle.send(ServerMessage::FileSearch {
|
||||||
token,
|
token,
|
||||||
query: query.to_string(),
|
query: query.to_string(),
|
||||||
@@ -277,15 +284,32 @@ impl Client {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(self.context.read().unwrap().search_results.clone())
|
|
||||||
|
Ok(self.get_search_results(query))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_search_results_count(&self) -> usize {
|
pub fn get_search_results_count(&self, search_key: &str) -> usize {
|
||||||
self.context.read().unwrap().search_results.len()
|
self.context
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.searches
|
||||||
|
.get(search_key)
|
||||||
|
.map(|s| s.results.len())
|
||||||
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_search_results(&self) -> Vec<FileSearchResult> {
|
pub fn get_search_results(&self, search_key: &str) -> Vec<SearchResult> {
|
||||||
self.context.read().unwrap().search_results.clone()
|
self.context
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.searches
|
||||||
|
.get(search_key)
|
||||||
|
.map(|s| s.results.clone())
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_all_searches(&self) -> HashMap<String, Search> {
|
||||||
|
self.context.read().unwrap().searches.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn download(
|
pub fn download(
|
||||||
@@ -385,13 +409,18 @@ impl Client {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ClientOperation::SearchResult(file_search) => {
|
ClientOperation::SearchResult(search_result) => {
|
||||||
trace!("[client] SearchResult {:?}", file_search);
|
trace!("[client] SearchResult {:?}", search_result);
|
||||||
client_context
|
let mut context = client_context.write().unwrap();
|
||||||
.write()
|
let result_token = search_result.token;
|
||||||
.unwrap()
|
|
||||||
.search_results
|
// Find the search with matching token
|
||||||
.push(file_search.clone());
|
for search in context.searches.values_mut() {
|
||||||
|
if search.token == result_token {
|
||||||
|
search.results.push(search_result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ClientOperation::PeerDisconnected(username, error) => {
|
ClientOperation::PeerDisconnected(username, error) => {
|
||||||
let context = client_context.read().unwrap();
|
let context = client_context.read().unwrap();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ pub mod utils;
|
|||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::actor::server_actor::PeerAddress;
|
pub use crate::actor::server_actor::PeerAddress;
|
||||||
pub use crate::types::{
|
pub use crate::types::{
|
||||||
DownloadResult, DownloadStatus, File, FileSearchResult, Transfer,
|
DownloadResult, DownloadStatus, File, Search, SearchResult, Transfer,
|
||||||
};
|
};
|
||||||
pub use crate::{debug, error, info, trace, warn};
|
pub use crate::{debug, error, info, trace, warn};
|
||||||
}
|
}
|
||||||
@@ -23,5 +23,5 @@ pub use actor::server_actor::PeerAddress;
|
|||||||
pub use client::{Client, ClientSettings};
|
pub use client::{Client, ClientSettings};
|
||||||
pub use error::{Result, SoulseekRs};
|
pub use error::{Result, SoulseekRs};
|
||||||
pub use types::{
|
pub use types::{
|
||||||
DownloadResult, DownloadStatus, File, FileSearchResult, Transfer,
|
DownloadResult, DownloadStatus, File, Search, SearchResult, Transfer,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::message::{Message, MessageHandler};
|
use crate::message::{Message, MessageHandler};
|
||||||
use crate::peer::PeerMessage;
|
use crate::peer::PeerMessage;
|
||||||
use crate::types::FileSearchResult;
|
use crate::types::SearchResult;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
pub struct FileSearchResponse;
|
pub struct FileSearchResponse;
|
||||||
@@ -9,7 +9,7 @@ impl MessageHandler<PeerMessage> for FileSearchResponse {
|
|||||||
9
|
9
|
||||||
}
|
}
|
||||||
fn handle(&self, message: &mut Message, sender: Sender<PeerMessage>) {
|
fn handle(&self, message: &mut Message, sender: Sender<PeerMessage>) {
|
||||||
let file_search = match FileSearchResult::new_from_message(message) {
|
let file_search = match SearchResult::new_from_message(message) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(_) => return, // Skip malformed search results
|
Err(_) => return, // Skip malformed search results
|
||||||
};
|
};
|
||||||
@@ -43,7 +43,7 @@ fn test_new_from_message() {
|
|||||||
let mut message = Message::new_with_data(data);
|
let mut message = Message::new_with_data(data);
|
||||||
message.set_pointer(8);
|
message.set_pointer(8);
|
||||||
|
|
||||||
let file_search = FileSearchResult::new_from_message(&mut message).unwrap();
|
let file_search = SearchResult::new_from_message(&mut message).unwrap();
|
||||||
assert_eq!(file_search.token, 882125677);
|
assert_eq!(file_search.token, 882125677);
|
||||||
assert_eq!(file_search.files.len(), 2);
|
assert_eq!(file_search.files.len(), 2);
|
||||||
let file = &file_search.files[0];
|
let file = &file_search.files[0];
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ impl UploadFailed {
|
|||||||
}
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct FileSearchResult {
|
pub struct SearchResult {
|
||||||
pub token: u32,
|
pub token: u32,
|
||||||
pub files: Vec<File>,
|
pub files: Vec<File>,
|
||||||
pub slots: u8,
|
pub slots: u8,
|
||||||
@@ -30,7 +30,13 @@ pub struct FileSearchResult {
|
|||||||
pub username: String,
|
pub username: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileSearchResult {
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Search {
|
||||||
|
pub token: u32,
|
||||||
|
pub results: Vec<SearchResult>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SearchResult {
|
||||||
pub fn new_from_message(message: &mut Message) -> Result<Self> {
|
pub fn new_from_message(message: &mut Message) -> Result<Self> {
|
||||||
let pointer = message.get_pointer();
|
let pointer = message.get_pointer();
|
||||||
let size = message.get_size();
|
let size = message.get_size();
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ fn search_and_download(config: SearchConfig) -> Result<()> {
|
|||||||
cancel_flag.store(true, std::sync::atomic::Ordering::Relaxed);
|
cancel_flag.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
// Get final results
|
// Get final results
|
||||||
let results = client.get_search_results();
|
let results = client.get_search_results(&config.query);
|
||||||
|
|
||||||
if selected_indices.is_empty() {
|
if selected_indices.is_empty() {
|
||||||
ratatui::restore();
|
ratatui::restore();
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ impl FileSelector {
|
|||||||
// Poll for new search results if active
|
// Poll for new search results if active
|
||||||
if self.search_active {
|
if self.search_active {
|
||||||
if let Some(ref client) = self.client {
|
if let Some(ref client) = self.client {
|
||||||
let current_count = client.get_search_results_count();
|
let current_count =
|
||||||
|
client.get_search_results_count(&self.soulseek_query);
|
||||||
if current_count != self.last_result_count {
|
if current_count != self.last_result_count {
|
||||||
self.update_results_from_client();
|
self.update_results_from_client();
|
||||||
self.last_result_count = current_count;
|
self.last_result_count = current_count;
|
||||||
@@ -124,7 +125,8 @@ impl FileSelector {
|
|||||||
|
|
||||||
fn update_results_from_client(&mut self) {
|
fn update_results_from_client(&mut self) {
|
||||||
if let Some(ref client) = self.client {
|
if let Some(ref client) = self.client {
|
||||||
let search_results = client.get_search_results();
|
let search_results =
|
||||||
|
client.get_search_results(&self.soulseek_query);
|
||||||
|
|
||||||
// Convert search results to FileDisplayData
|
// Convert search results to FileDisplayData
|
||||||
let mut new_items = Vec::new();
|
let mut new_items = Vec::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user