refactor(stats): streamline session management in RemoteStatsSampler (#545)

- Removed the dependency on RemoteStatsSampler in the close_session function.
- Introduced session locking mechanism to prevent race conditions when fetching remote stats.
- Updated the stats fetching logic to utilize a probe plan for better efficiency.
- Enhanced the RemoteStatsSampler to manage session states and ensure proper cleanup of session data.
This commit is contained in:
Kang committed 2026-09-06 10:31:13 +08:00
1 parent c556b16aa6
commit f4e8b499f6
4 files changed
+732 -184

No files matched your search

-4
View File
@@ -1,5 +1,4 @@
use crate::config;
use crate::core::monitoring::stats::RemoteStatsSampler;
use crate::core::ssh::{
self, HostKeyVerifyManager, PendingAuthManager, PendingSshAgentAuthManager,
PendingSshAuthManager, SshAgentAuthAction, SshAuthResponse,
@@ -1081,7 +1080,6 @@ pub async fn detach_session_renderer(
pub async fn close_session(
app: tauri::AppHandle,
state: tauri::State<'_, Arc<SessionManager>>,
stats_sampler: tauri::State<'_, Arc<RemoteStatsSampler>>,
session_id: String,
) -> AppResult<()> {
let session_id_clone = session_id.clone();
@@ -1102,8 +1100,6 @@ pub async fn close_session(
other => other,
};
stats_sampler.clear_session(&session_id).await;
// Concurrently tidy up any downloaded/watcher temporary files stored in the OS temp directory
tauri::async_runtime::spawn(async move {
if let Ok(temp_dir) = app.path().temp_dir() {
+17 -3
View File
@@ -1,6 +1,6 @@
use crate::core::SessionManager;
use crate::core::monitoring::stats::{
RemoteStats, RemoteStatsSampler, SYSINFO_SCRIPT, parse_stats_output,
RemoteStats, RemoteStatsSampler, build_stats_script, parse_stats_output,
};
use crate::core::remote_exec::{ensure_success, exec_ssh_session_command};
use crate::error::{AppError, AppResult};
@@ -13,6 +13,15 @@ pub async fn get_remote_stats(
sampler: tauri::State<'_, Arc<RemoteStatsSampler>>,
session_id: String,
) -> AppResult<RemoteStats> {
// Auto-icon detection and the monitor can request the same new session concurrently.
// Serializing per session avoids duplicate static/disk probes without blocking other hosts.
let lease = sampler.lock_session(&session_id).await;
if !lease.is_current() {
return Err(AppError::SessionNotFound(format!(
"Session '{session_id}' was closed while waiting for remote stats"
)));
}
let remote_stats_enabled = {
let sessions = state.sessions.lock().await;
let session = sessions.get(&session_id).ok_or_else(|| {
@@ -26,17 +35,22 @@ pub async fn get_remote_stats(
));
}
let probe_plan = sampler.probe_plan(&session_id).await;
let script = build_stats_script(probe_plan);
let output = exec_ssh_session_command(
state.inner(),
&session_id,
SYSINFO_SCRIPT.as_bytes(),
script.as_bytes(),
Duration::from_secs(15),
)
.await?;
let output = ensure_success(output, "Failed to fetch stats")?;
let parsed = parse_stats_output(&output.stdout)?;
Ok(sampler.complete_snapshot(&session_id, parsed).await)
Ok(sampler
.complete_snapshot_with_lease(&session_id, &lease, parsed)
.await)
}
#[tauri::command]
File diff suppressed because it is too large. Load diff
+4
View File
@@ -4,6 +4,7 @@ use super::client::{
use crate::config::SftpCwdFollowMode;
use crate::core::capture::OutputCaptureProcessor;
use crate::core::input::remap_del_to_bs;
use crate::core::monitoring::stats::RemoteStatsSampler;
use crate::core::ssh::osc::{self, OscStripper, ShellKind};
use crate::core::terminal_session::local::split_startup_passthrough;
use crate::core::terminal_session::{TerminalOutputDecoder, encode_terminal_input};
@@ -1611,6 +1612,9 @@ pub(super) async fn ssh_io_loop(
}
manager.remove_session(&session_id).await;
if let Some(stats_sampler) = app.try_state::<Arc<RemoteStatsSampler>>() {
stats_sampler.clear_session(&session_id).await;
}
if let Some(ref conn_id) = connection_id {
if let Some(tunnel_mgr) = app.try_state::<Arc<super::TunnelManager>>() {