desktop: don't spawn sidecar if default is localhost server
This commit is contained in:
@@ -40,7 +40,9 @@ use crate::windows::{LoadingWindow, MainWindow};
|
|||||||
#[derive(Clone, serde::Serialize, specta::Type, Debug)]
|
#[derive(Clone, serde::Serialize, specta::Type, Debug)]
|
||||||
struct ServerReadyData {
|
struct ServerReadyData {
|
||||||
url: String,
|
url: String,
|
||||||
|
username: Option<String>,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
|
is_sidecar: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, serde::Serialize, specta::Type, Debug)]
|
#[derive(Clone, Copy, serde::Serialize, specta::Type, Debug)]
|
||||||
@@ -605,6 +607,7 @@ async fn initialize(app: AppHandle) {
|
|||||||
child,
|
child,
|
||||||
health_check,
|
health_check,
|
||||||
url,
|
url,
|
||||||
|
username,
|
||||||
password,
|
password,
|
||||||
} => {
|
} => {
|
||||||
let app = app.clone();
|
let app = app.clone();
|
||||||
@@ -631,7 +634,7 @@ async fn initialize(app: AppHandle) {
|
|||||||
|
|
||||||
app.state::<ServerState>().set_child(Some(child));
|
app.state::<ServerState>().set_child(Some(child));
|
||||||
|
|
||||||
Ok(ServerReadyData { url, password })
|
Ok(ServerReadyData { url, username,password, is_sidecar: true })
|
||||||
}
|
}
|
||||||
.map(move |res| {
|
.map(move |res| {
|
||||||
let _ = server_ready_tx.send(res);
|
let _ = server_ready_tx.send(res);
|
||||||
@@ -641,7 +644,9 @@ async fn initialize(app: AppHandle) {
|
|||||||
ServerConnection::Existing { url } => {
|
ServerConnection::Existing { url } => {
|
||||||
let _ = server_ready_tx.send(Ok(ServerReadyData {
|
let _ = server_ready_tx.send(Ok(ServerReadyData {
|
||||||
url: url.to_string(),
|
url: url.to_string(),
|
||||||
|
username: None,
|
||||||
password: None,
|
password: None,
|
||||||
|
is_sidecar: false,
|
||||||
}));
|
}));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -719,6 +724,7 @@ enum ServerConnection {
|
|||||||
},
|
},
|
||||||
CLI {
|
CLI {
|
||||||
url: String,
|
url: String,
|
||||||
|
username: Option<String>,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
child: CommandChild,
|
child: CommandChild,
|
||||||
health_check: server::HealthCheck,
|
health_check: server::HealthCheck,
|
||||||
@@ -730,11 +736,15 @@ async fn setup_server_connection(app: AppHandle) -> ServerConnection {
|
|||||||
|
|
||||||
tracing::info!(?custom_url, "Attempting server connection");
|
tracing::info!(?custom_url, "Attempting server connection");
|
||||||
|
|
||||||
if let Some(url) = custom_url
|
if let Some(url) = &custom_url
|
||||||
&& server::check_health_or_ask_retry(&app, &url).await
|
&& server::check_health_or_ask_retry(&app, url).await
|
||||||
{
|
{
|
||||||
tracing::info!(%url, "Connected to custom server");
|
tracing::info!(%url, "Connected to custom server");
|
||||||
return ServerConnection::Existing { url: url.clone() };
|
// If the default server is already local, no need to also spawn a sidecar
|
||||||
|
if server::is_localhost_url(url) {
|
||||||
|
return ServerConnection::Existing { url: url.clone() };
|
||||||
|
}
|
||||||
|
// Remote default server: fall through and also spawn a local sidecar
|
||||||
}
|
}
|
||||||
|
|
||||||
let local_port = get_sidecar_port();
|
let local_port = get_sidecar_port();
|
||||||
@@ -755,6 +765,7 @@ async fn setup_server_connection(app: AppHandle) -> ServerConnection {
|
|||||||
|
|
||||||
ServerConnection::CLI {
|
ServerConnection::CLI {
|
||||||
url: local_url,
|
url: local_url,
|
||||||
|
username: Some("opencode".to_string()),
|
||||||
password: Some(password),
|
password: Some(password),
|
||||||
child,
|
child,
|
||||||
health_check,
|
health_check,
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ pub async fn check_health(url: &str, password: Option<&str>) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut builder = reqwest::Client::builder().timeout(Duration::from_secs(3));
|
let mut builder = reqwest::Client::builder().timeout(Duration::from_secs(7));
|
||||||
|
|
||||||
if url_is_localhost(&url) {
|
if url_is_localhost(&url) {
|
||||||
// Some environments set proxy variables (HTTP_PROXY/HTTPS_PROXY/ALL_PROXY) without
|
// Some environments set proxy variables (HTTP_PROXY/HTTPS_PROXY/ALL_PROXY) without
|
||||||
@@ -178,6 +178,10 @@ pub async fn check_health(url: &str, password: Option<&str>) -> bool {
|
|||||||
.unwrap_or(false)
|
.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 {
|
fn url_is_localhost(url: &reqwest::Url) -> bool {
|
||||||
url.host_str().is_some_and(|host| {
|
url.host_str().is_some_and(|host| {
|
||||||
host.eq_ignore_ascii_case("localhost")
|
host.eq_ignore_ascii_case("localhost")
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ export type LoadingWindowComplete = null;
|
|||||||
|
|
||||||
export type ServerReadyData = {
|
export type ServerReadyData = {
|
||||||
url: string,
|
url: string,
|
||||||
|
username: string | null,
|
||||||
password: string | null,
|
password: string | null,
|
||||||
|
is_sidecar: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SqliteMigrationProgress = { type: "InProgress"; value: number } | { type: "Done" };
|
export type SqliteMigrationProgress = { type: "InProgress"; value: number } | { type: "Done" };
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { relaunch } from "@tauri-apps/plugin-process"
|
|||||||
import { open as shellOpen } from "@tauri-apps/plugin-shell"
|
import { open as shellOpen } from "@tauri-apps/plugin-shell"
|
||||||
import { Store } from "@tauri-apps/plugin-store"
|
import { Store } from "@tauri-apps/plugin-store"
|
||||||
import { check, type Update } from "@tauri-apps/plugin-updater"
|
import { check, type Update } from "@tauri-apps/plugin-updater"
|
||||||
import { type Accessor, createResource, type JSX, onCleanup, onMount, Show } from "solid-js"
|
import { createResource, type JSX, onCleanup, onMount, Show } from "solid-js"
|
||||||
import { render } from "solid-js/web"
|
import { render } from "solid-js/web"
|
||||||
import pkg from "../package.json"
|
import pkg from "../package.json"
|
||||||
import { initI18n, t } from "./i18n"
|
import { initI18n, t } from "./i18n"
|
||||||
@@ -31,7 +31,7 @@ import { UPDATER_ENABLED } from "./updater"
|
|||||||
import { webviewZoom } from "./webview-zoom"
|
import { webviewZoom } from "./webview-zoom"
|
||||||
import "./styles.css"
|
import "./styles.css"
|
||||||
import { Channel } from "@tauri-apps/api/core"
|
import { Channel } from "@tauri-apps/api/core"
|
||||||
import { commands, type InitStep } from "./bindings"
|
import { commands, ServerReadyData, type InitStep } from "./bindings"
|
||||||
import { createMenu } from "./menu"
|
import { createMenu } from "./menu"
|
||||||
|
|
||||||
const root = document.getElementById("root")
|
const root = document.getElementById("root")
|
||||||
@@ -452,16 +452,19 @@ render(() => {
|
|||||||
<AppBaseProviders>
|
<AppBaseProviders>
|
||||||
<ServerGate>
|
<ServerGate>
|
||||||
{(data) => {
|
{(data) => {
|
||||||
const server: ServerConnection.Sidecar = {
|
const http = {
|
||||||
displayName: "Local Server",
|
url: data.url,
|
||||||
type: "sidecar",
|
username: data.username ?? undefined,
|
||||||
variant: "base",
|
password: data.password ?? undefined,
|
||||||
http: {
|
|
||||||
url: data().url,
|
|
||||||
username: "opencode",
|
|
||||||
password: data().password ?? undefined,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
const server: ServerConnection.Any = data.is_sidecar
|
||||||
|
? {
|
||||||
|
displayName: "Local Server",
|
||||||
|
type: "sidecar",
|
||||||
|
variant: "base",
|
||||||
|
http,
|
||||||
|
}
|
||||||
|
: { type: "http", http }
|
||||||
|
|
||||||
function Inner() {
|
function Inner() {
|
||||||
const cmd = useCommand()
|
const cmd = useCommand()
|
||||||
@@ -485,10 +488,8 @@ render(() => {
|
|||||||
)
|
)
|
||||||
}, root!)
|
}, root!)
|
||||||
|
|
||||||
type ServerReadyData = { url: string; password: string | null }
|
|
||||||
|
|
||||||
// Gate component that waits for the server to be ready
|
// Gate component that waits for the server to be ready
|
||||||
function ServerGate(props: { children: (data: Accessor<ServerReadyData>) => JSX.Element }) {
|
function ServerGate(props: { children: (data: ServerReadyData) => JSX.Element }) {
|
||||||
const [serverData] = createResource(() => commands.awaitInitialization(new Channel<InitStep>() as any))
|
const [serverData] = createResource(() => commands.awaitInitialization(new Channel<InitStep>() as any))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -516,7 +517,7 @@ function ServerGate(props: { children: (data: Accessor<ServerReadyData>) => JSX.
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{(data) => props.children(data)}
|
{(data) => props.children(data())}
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user