Skip to content

Commit 1c2416b

Browse files
committed
desktop: don't spawn sidecar if default is localhost server
1 parent d86c108 commit 1c2416b

4 files changed

Lines changed: 38 additions & 20 deletions

File tree

packages/desktop/src-tauri/src/lib.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ use crate::windows::{LoadingWindow, MainWindow};
4040
#[derive(Clone, serde::Serialize, specta::Type, Debug)]
4141
struct ServerReadyData {
4242
url: String,
43+
username: Option<String>,
4344
password: Option<String>,
45+
is_sidecar: bool
4446
}
4547

4648
#[derive(Clone, Copy, serde::Serialize, specta::Type, Debug)]
@@ -605,6 +607,7 @@ async fn initialize(app: AppHandle) {
605607
child,
606608
health_check,
607609
url,
610+
username,
608611
password,
609612
} => {
610613
let app = app.clone();
@@ -631,7 +634,7 @@ async fn initialize(app: AppHandle) {
631634

632635
app.state::<ServerState>().set_child(Some(child));
633636

634-
Ok(ServerReadyData { url, password })
637+
Ok(ServerReadyData { url, username,password, is_sidecar: true })
635638
}
636639
.map(move |res| {
637640
let _ = server_ready_tx.send(res);
@@ -641,7 +644,9 @@ async fn initialize(app: AppHandle) {
641644
ServerConnection::Existing { url } => {
642645
let _ = server_ready_tx.send(Ok(ServerReadyData {
643646
url: url.to_string(),
647+
username: None,
644648
password: None,
649+
is_sidecar: false,
645650
}));
646651
None
647652
}
@@ -719,6 +724,7 @@ enum ServerConnection {
719724
},
720725
CLI {
721726
url: String,
727+
username: Option<String>,
722728
password: Option<String>,
723729
child: CommandChild,
724730
health_check: server::HealthCheck,
@@ -730,11 +736,15 @@ async fn setup_server_connection(app: AppHandle) -> ServerConnection {
730736

731737
tracing::info!(?custom_url, "Attempting server connection");
732738

733-
if let Some(url) = custom_url
734-
&& server::check_health_or_ask_retry(&app, &url).await
739+
if let Some(url) = &custom_url
740+
&& server::check_health_or_ask_retry(&app, url).await
735741
{
736742
tracing::info!(%url, "Connected to custom server");
737-
return ServerConnection::Existing { url: url.clone() };
743+
// If the default server is already local, no need to also spawn a sidecar
744+
if server::is_localhost_url(url) {
745+
return ServerConnection::Existing { url: url.clone() };
746+
}
747+
// Remote default server: fall through and also spawn a local sidecar
738748
}
739749

740750
let local_port = get_sidecar_port();
@@ -755,6 +765,7 @@ async fn setup_server_connection(app: AppHandle) -> ServerConnection {
755765

756766
ServerConnection::CLI {
757767
url: local_url,
768+
username: Some("opencode".to_string()),
758769
password: Some(password),
759770
child,
760771
health_check,

packages/desktop/src-tauri/src/server.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ pub async fn check_health(url: &str, password: Option<&str>) -> bool {
150150
return false;
151151
};
152152

153-
let mut builder = reqwest::Client::builder().timeout(Duration::from_secs(3));
153+
let mut builder = reqwest::Client::builder().timeout(Duration::from_secs(7));
154154

155155
if url_is_localhost(&url) {
156156
// 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 {
178178
.unwrap_or(false)
179179
}
180180

181+
pub fn is_localhost_url(url: &str) -> bool {
182+
reqwest::Url::parse(url).is_ok_and(|u| url_is_localhost(&u))
183+
}
184+
181185
fn url_is_localhost(url: &reqwest::Url) -> bool {
182186
url.host_str().is_some_and(|host| {
183187
host.eq_ignore_ascii_case("localhost")

packages/desktop/src/bindings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ export type LoadingWindowComplete = null;
3535

3636
export type ServerReadyData = {
3737
url: string,
38+
username: string | null,
3839
password: string | null,
40+
is_sidecar: boolean,
3941
};
4042

4143
export type SqliteMigrationProgress = { type: "InProgress"; value: number } | { type: "Done" };

packages/desktop/src/index.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ import { relaunch } from "@tauri-apps/plugin-process"
2323
import { open as shellOpen } from "@tauri-apps/plugin-shell"
2424
import { Store } from "@tauri-apps/plugin-store"
2525
import { check, type Update } from "@tauri-apps/plugin-updater"
26-
import { type Accessor, createResource, type JSX, onCleanup, onMount, Show } from "solid-js"
26+
import { createResource, type JSX, onCleanup, onMount, Show } from "solid-js"
2727
import { render } from "solid-js/web"
2828
import pkg from "../package.json"
2929
import { initI18n, t } from "./i18n"
3030
import { UPDATER_ENABLED } from "./updater"
3131
import { webviewZoom } from "./webview-zoom"
3232
import "./styles.css"
3333
import { Channel } from "@tauri-apps/api/core"
34-
import { commands, type InitStep } from "./bindings"
34+
import { commands, ServerReadyData, type InitStep } from "./bindings"
3535
import { createMenu } from "./menu"
3636

3737
const root = document.getElementById("root")
@@ -452,16 +452,19 @@ render(() => {
452452
<AppBaseProviders>
453453
<ServerGate>
454454
{(data) => {
455-
const server: ServerConnection.Sidecar = {
456-
displayName: "Local Server",
457-
type: "sidecar",
458-
variant: "base",
459-
http: {
460-
url: data().url,
461-
username: "opencode",
462-
password: data().password ?? undefined,
463-
},
455+
const http = {
456+
url: data.url,
457+
username: data.username ?? undefined,
458+
password: data.password ?? undefined,
464459
}
460+
const server: ServerConnection.Any = data.is_sidecar
461+
? {
462+
displayName: "Local Server",
463+
type: "sidecar",
464+
variant: "base",
465+
http,
466+
}
467+
: { type: "http", http }
465468

466469
function Inner() {
467470
const cmd = useCommand()
@@ -485,10 +488,8 @@ render(() => {
485488
)
486489
}, root!)
487490

488-
type ServerReadyData = { url: string; password: string | null }
489-
490491
// Gate component that waits for the server to be ready
491-
function ServerGate(props: { children: (data: Accessor<ServerReadyData>) => JSX.Element }) {
492+
function ServerGate(props: { children: (data: ServerReadyData) => JSX.Element }) {
492493
const [serverData] = createResource(() => commands.awaitInitialization(new Channel<InitStep>() as any))
493494

494495
return (
@@ -516,7 +517,7 @@ function ServerGate(props: { children: (data: Accessor<ServerReadyData>) => JSX.
516517
</div>
517518
}
518519
>
519-
{(data) => props.children(data)}
520+
{(data) => props.children(data())}
520521
</Show>
521522
</Show>
522523
)

0 commit comments

Comments
 (0)