-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch_handler.rs
More file actions
101 lines (86 loc) · 3.18 KB
/
Copy pathsearch_handler.rs
File metadata and controls
101 lines (86 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use crate::app_state::{AppState, SocketData};
use crate::search::{FileSearchResult, global_search};
use serde::{Deserialize, Serialize};
use serde_json::{self, json};
use socketioxide::extract::{Data, SocketRef, State};
use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken;
use tracing::info;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SearchRequest {
pub pattern: String,
pub case_sensitive: Option<bool>,
}
pub async fn handle_search(
socket: SocketRef,
Data(search_request): Data<SearchRequest>,
state: State<AppState>,
) {
info!("Received handle_search {}", search_request.pattern);
let sid = socket.id.as_str();
let mut sockets_data = state.socket2data.lock().await;
// Get the socket data
let data = sockets_data
.entry(sid.to_string())
.or_insert_with(|| SocketData::default());
// Cancel the previous search if any
if let Some(cancel) = &data.search_cancel {
cancel.cancel();
}
// Create the cancellation token
let cancel = CancellationToken::new();
// Save the cancel in the socket data
data.search_cancel = Some(cancel.clone());
data.search_pattern = Some(search_request.pattern.clone());
// Prepare search, get the current directory and create channel to collect results
let current_dir = std::env::current_dir().unwrap();
let (result_tx, mut result_rx) = mpsc::channel::<FileSearchResult>(1000);
let socket_clone = socket.clone();
let start = std::time::Instant::now();
// Start the search in the background
tokio::spawn(async move {
let case_sensitive = search_request.case_sensitive.unwrap_or(false);
let search_result =
global_search(¤t_dir, &search_request.pattern, case_sensitive, cancel, result_tx).await;
if let Err(err) = search_result {
let _ = socket_clone.emit(
"search:error",
&json!({
"error": "Search failed", "message": err.to_string()
}),
);
}
});
// Collect results and send them to the socket
tokio::spawn(async move {
let mut matches = 0;
// In cancel case, the loop will be ended automatically
while let Some(file_result) = result_rx.recv().await {
let _ = socket.emit("search:result", &file_result);
matches += file_result.matches.len();
}
let _ = socket.emit(
"search:end",
&json!({
"elapsed": start.elapsed().as_millis(),
"matches": matches
}),
);
});
}
pub async fn handle_search_cancel(socket: SocketRef, state: State<AppState>) {
info!("Received handle_search_cancel");
let sid = socket.id.as_str();
let mut sockets_data = state.socket2data.lock().await;
// Get the socket data
if let Some(data) = sockets_data.get_mut(sid) {
// Cancel the current search if any
if let Some(cancel) = &data.search_cancel {
cancel.cancel();
info!("Search cancelled for socket {}", sid);
}
// Clear the cancel token
data.search_cancel = None;
data.search_pattern = None;
}
}