diff options
| author | Brendan Allan <[email protected]> | 2026-03-12 16:10:52 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-03-12 08:10:52 +0000 |
| commit | b76ead3fe80a6159fdbfcc9b82c7c6318be68e7f (patch) | |
| tree | bad16ba8185403eb9dc97b6c996bbfa78ae7918b /packages/desktop/src-tauri/src/server.rs | |
| parent | 51835ecf90e23b34957f4dde843bbba1134f17fe (diff) | |
| download | opencode-b76ead3fe80a6159fdbfcc9b82c7c6318be68e7f.tar.gz opencode-b76ead3fe80a6159fdbfcc9b82c7c6318be68e7f.zip | |
refactor(desktop): rework default server initialization and connection handling (#16965)
Diffstat (limited to 'packages/desktop/src-tauri/src/server.rs')
| -rw-r--r-- | packages/desktop/src-tauri/src/server.rs | 105 |
1 files changed, 11 insertions, 94 deletions
diff --git a/packages/desktop/src-tauri/src/server.rs b/packages/desktop/src-tauri/src/server.rs index 2c43c1cc8..070d0c71f 100644 --- a/packages/desktop/src-tauri/src/server.rs +++ b/packages/desktop/src-tauri/src/server.rs @@ -1,7 +1,6 @@ use std::time::{Duration, Instant}; use tauri::AppHandle; -use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogResult}; use tauri_plugin_store::StoreExt; use tokio::task::JoinHandle; @@ -85,22 +84,6 @@ pub fn set_wsl_config(app: AppHandle, config: WslConfig) -> Result<(), String> { Ok(()) } -pub async fn get_saved_server_url(app: &tauri::AppHandle) -> Option<String> { - if let Some(url) = get_default_server_url(app.clone()).ok().flatten() { - tracing::info!(%url, "Using desktop-specific custom URL"); - return Some(url); - } - - if let Some(cli_config) = cli::get_config(app).await - && let Some(url) = get_server_url_from_config(&cli_config) - { - tracing::info!(%url, "Using custom server URL from config"); - return Some(url); - } - - None -} - pub fn spawn_local_server( app: AppHandle, hostname: String, @@ -145,19 +128,27 @@ pub fn spawn_local_server( pub struct HealthCheck(pub JoinHandle<Result<(), String>>); -pub async fn check_health(url: &str, password: Option<&str>) -> bool { +async fn check_health(url: &str, password: Option<&str>) -> bool { let Ok(url) = reqwest::Url::parse(url) else { return false; }; let mut builder = reqwest::Client::builder().timeout(Duration::from_secs(7)); - if url_is_localhost(&url) { + if url + .host_str() + .is_some_and(|host| { + host.eq_ignore_ascii_case("localhost") + || host + .parse::<std::net::IpAddr>() + .is_ok_and(|ip| ip.is_loopback()) + }) + { // Some environments set proxy variables (HTTP_PROXY/HTTPS_PROXY/ALL_PROXY) without // excluding loopback. reqwest respects these by default, which can prevent the desktop // app from reaching its own local sidecar server. builder = builder.no_proxy(); - }; + } let Ok(client) = builder.build() else { return false; @@ -177,77 +168,3 @@ pub async fn check_health(url: &str, password: Option<&str>) -> bool { .map(|r| r.status().is_success()) .unwrap_or(false) } - -pub fn is_localhost_url(url: &str) -> bool { - reqwest::Url::parse(url).is_ok_and(|u| url_is_localhost(&u)) -} - -fn url_is_localhost(url: &reqwest::Url) -> bool { - url.host_str().is_some_and(|host| { - host.eq_ignore_ascii_case("localhost") - || host - .parse::<std::net::IpAddr>() - .is_ok_and(|ip| ip.is_loopback()) - }) -} - -/// Converts a bind address hostname to a valid URL hostname for connection. -/// - `0.0.0.0` and `::` are wildcard bind addresses, not valid connect targets -/// - IPv6 addresses need brackets in URLs (e.g., `::1` -> `[::1]`) -fn normalize_hostname_for_url(hostname: &str) -> String { - // Wildcard bind addresses -> localhost equivalents - if hostname == "0.0.0.0" { - return "127.0.0.1".to_string(); - } - if hostname == "::" { - return "[::1]".to_string(); - } - - // IPv6 addresses need brackets in URLs - if hostname.contains(':') && !hostname.starts_with('[') { - return format!("[{}]", hostname); - } - - hostname.to_string() -} - -fn get_server_url_from_config(config: &cli::Config) -> Option<String> { - let server = config.server.as_ref()?; - let port = server.port?; - tracing::debug!(port, "server.port found in OC config"); - let hostname = server - .hostname - .as_ref() - .map(|v| normalize_hostname_for_url(v)) - .unwrap_or_else(|| "127.0.0.1".to_string()); - - Some(format!("http://{}:{}", hostname, port)) -} - -pub async fn check_health_or_ask_retry(app: &AppHandle, url: &str) -> bool { - tracing::debug!(%url, "Checking health"); - loop { - if check_health(url, None).await { - return true; - } - - const RETRY: &str = "Retry"; - - let res = app.dialog() - .message(format!("Could not connect to configured server:\n{}\n\nWould you like to retry or start a local server instead?", url)) - .title("Connection Failed") - .buttons(MessageDialogButtons::OkCancelCustom(RETRY.to_string(), "Start Local".to_string())) - .blocking_show_with_result(); - - match res { - MessageDialogResult::Custom(name) if name == RETRY => { - continue; - } - _ => { - break; - } - } - } - - false -} |
