mirror of https://github.com/ospab/ostp.git
fix(split-tunnel): hot-reload exclusions into running proxy tunnel without reconnect
This commit is contained in:
parent
83ba39e59a
commit
4543fa82f8
|
|
@ -95,6 +95,7 @@ enum HelperMsg {
|
||||||
|
|
||||||
struct InProcessState {
|
struct InProcessState {
|
||||||
shutdown_tx: Option<tokio::sync::watch::Sender<bool>>,
|
shutdown_tx: Option<tokio::sync::watch::Sender<bool>>,
|
||||||
|
config_tx: Option<tokio::sync::watch::Sender<ostp_client::config::ClientConfig>>,
|
||||||
metrics: Arc<ostp_client::bridge::BridgeMetrics>,
|
metrics: Arc<ostp_client::bridge::BridgeMetrics>,
|
||||||
handle: tokio::task::JoinHandle<Result<(), String>>,
|
handle: tokio::task::JoinHandle<Result<(), String>>,
|
||||||
error_msg: Arc<tokio::sync::Mutex<Option<String>>>,
|
error_msg: Arc<tokio::sync::Mutex<Option<String>>>,
|
||||||
|
|
@ -443,10 +444,13 @@ async fn reload_tunnel(state: tauri::State<'_, AppState>) -> Result<bool, String
|
||||||
);
|
);
|
||||||
let _ = h.cmd_tx.send(cmd).await;
|
let _ = h.cmd_tx.send(cmd).await;
|
||||||
}
|
}
|
||||||
Some(TunnelHandle::InProcess(_s)) => {
|
Some(TunnelHandle::InProcess(s)) => {
|
||||||
// Restarting in-process tunnel is not supported without re-calling start_tunnel,
|
// Hot-reload exclusions by pushing new config into the watch channel.
|
||||||
// but we can just abort and we should really call start_tunnel again.
|
// If config_tx is None (old tunnel without this feature), return false.
|
||||||
// For now, return false.
|
if let Some(ref tx) = s.config_tx {
|
||||||
|
let _ = tx.send(core_cfg);
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
|
@ -557,12 +561,14 @@ async fn start_proxy_in_process(
|
||||||
});
|
});
|
||||||
|
|
||||||
let (shutdown_tx, shutdown_rx) = watch::channel(false);
|
let (shutdown_tx, shutdown_rx) = watch::channel(false);
|
||||||
|
// Config hot-reload channel: allows updating exclusions while tunnel is running.
|
||||||
|
let (config_tx, config_rx) = watch::channel(mapped.clone());
|
||||||
let metrics_clone = metrics.clone();
|
let metrics_clone = metrics.clone();
|
||||||
let error_msg = Arc::new(tokio::sync::Mutex::new(None));
|
let error_msg = Arc::new(tokio::sync::Mutex::new(None));
|
||||||
let error_msg_clone = error_msg.clone();
|
let error_msg_clone = error_msg.clone();
|
||||||
|
|
||||||
let handle = tokio::spawn(async move {
|
let handle = tokio::spawn(async move {
|
||||||
match ostp_client::runner::run_client_core(mapped, metrics_clone, shutdown_rx, None).await {
|
match ostp_client::runner::run_client_core(mapped, metrics_clone, shutdown_rx, Some(config_rx)).await {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let mut err_guard = error_msg_clone.lock().await;
|
let mut err_guard = error_msg_clone.lock().await;
|
||||||
|
|
@ -575,6 +581,7 @@ async fn start_proxy_in_process(
|
||||||
|
|
||||||
guard.tunnel = Some(TunnelHandle::InProcess(InProcessState {
|
guard.tunnel = Some(TunnelHandle::InProcess(InProcessState {
|
||||||
shutdown_tx: Some(shutdown_tx),
|
shutdown_tx: Some(shutdown_tx),
|
||||||
|
config_tx: Some(config_tx),
|
||||||
metrics,
|
metrics,
|
||||||
handle,
|
handle,
|
||||||
error_msg,
|
error_msg,
|
||||||
|
|
|
||||||
|
|
@ -431,6 +431,9 @@ async function handleSave(silent = false) {
|
||||||
const ok = await invoke('save_config', { jsonContent: JSON.stringify(rawConfig, null, 2) });
|
const ok = await invoke('save_config', { jsonContent: JSON.stringify(rawConfig, null, 2) });
|
||||||
if (!ok && !silent) {
|
if (!ok && !silent) {
|
||||||
showToast(t('toast_error'), 'error');
|
showToast(t('toast_error'), 'error');
|
||||||
|
} else if (ok && appState === 'connected') {
|
||||||
|
// Hot-reload exclusions into the running tunnel (no reconnect needed)
|
||||||
|
try { await invoke('reload_tunnel'); } catch { /* ignore */ }
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!silent) showToast(String(err), 'error');
|
if (!silent) showToast(String(err), 'error');
|
||||||
|
|
@ -598,14 +601,7 @@ window.addEventListener('DOMContentLoaded', async () => {
|
||||||
// Auto-save wiring for standard form elements (excluding tag-inputs which wire themselves)
|
// Auto-save wiring for standard form elements (excluding tag-inputs which wire themselves)
|
||||||
const formInputs = document.querySelectorAll('#settings-screen input:not(#in-import-url):not(.tag-input-field), #settings-screen select');
|
const formInputs = document.querySelectorAll('#settings-screen input:not(#in-import-url):not(.tag-input-field), #settings-screen select');
|
||||||
formInputs.forEach(el => {
|
formInputs.forEach(el => {
|
||||||
el.addEventListener('input', () => {
|
el.addEventListener('input', scheduleAutoSave);
|
||||||
scheduleAutoSave();
|
|
||||||
if (appState === 'connected') {
|
|
||||||
if (window.__TAURI__ && window.__TAURI__.invoke) {
|
|
||||||
window.__TAURI__.invoke('reload_tunnel');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
el.addEventListener('change', scheduleAutoSave);
|
el.addEventListener('change', scheduleAutoSave);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue