|
|
@@ -1,9 +1,10 @@
|
|
|
use tauri::{AppHandle, Manager, path::BaseDirectory};
|
|
|
use tauri_plugin_shell::{
|
|
|
ShellExt,
|
|
|
- process::{Command, CommandChild, CommandEvent},
|
|
|
+ process::{Command, CommandChild, CommandEvent, TerminatedPayload},
|
|
|
};
|
|
|
use tauri_plugin_store::StoreExt;
|
|
|
+use tokio::sync::oneshot;
|
|
|
|
|
|
use crate::{
|
|
|
LogState,
|
|
|
@@ -273,12 +274,45 @@ pub fn create_command(app: &tauri::AppHandle, args: &str, extra_env: &[(&str, St
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub fn serve(app: &AppHandle, hostname: &str, port: u32, password: &str) -> CommandChild {
|
|
|
+pub fn serve(
|
|
|
+ app: &AppHandle,
|
|
|
+ hostname: &str,
|
|
|
+ port: u32,
|
|
|
+ password: &str,
|
|
|
+) -> (CommandChild, oneshot::Receiver<TerminatedPayload>) {
|
|
|
let log_state = app.state::<LogState>();
|
|
|
let log_state_clone = log_state.inner().clone();
|
|
|
|
|
|
+ let (exit_tx, exit_rx) = oneshot::channel::<TerminatedPayload>();
|
|
|
+
|
|
|
println!("spawning sidecar on port {port}");
|
|
|
|
|
|
+ if let Ok(mut logs) = log_state_clone.0.lock() {
|
|
|
+ let args =
|
|
|
+ format!("--print-logs --log-level WARN serve --hostname {hostname} --port {port}");
|
|
|
+
|
|
|
+ #[cfg(target_os = "windows")]
|
|
|
+ {
|
|
|
+ logs.push_back(format!("[SPAWN] sidecar=opencode-cli args=\"{args}\"\n"));
|
|
|
+ }
|
|
|
+
|
|
|
+ #[cfg(not(target_os = "windows"))]
|
|
|
+ {
|
|
|
+ let sidecar = get_sidecar_path(app);
|
|
|
+ let shell = get_user_shell();
|
|
|
+ let cmd = if shell.ends_with("/nu") {
|
|
|
+ format!("^\"{}\" {}", sidecar.display(), args)
|
|
|
+ } else {
|
|
|
+ format!("\"{}\" {}", sidecar.display(), args)
|
|
|
+ };
|
|
|
+ logs.push_back(format!("[SPAWN] shell=\"{shell}\" argv=\"-il -c {cmd}\"\n"));
|
|
|
+ }
|
|
|
+
|
|
|
+ while logs.len() > MAX_LOG_ENTRIES {
|
|
|
+ logs.pop_front();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
let envs = [
|
|
|
("OPENCODE_SERVER_USERNAME", "opencode".to_string()),
|
|
|
("OPENCODE_SERVER_PASSWORD", password.to_string()),
|
|
|
@@ -286,13 +320,14 @@ pub fn serve(app: &AppHandle, hostname: &str, port: u32, password: &str) -> Comm
|
|
|
|
|
|
let (mut rx, child) = create_command(
|
|
|
app,
|
|
|
- format!("serve --hostname {hostname} --port {port}").as_str(),
|
|
|
+ format!("--print-logs --log-level WARN serve --hostname {hostname} --port {port}").as_str(),
|
|
|
&envs,
|
|
|
)
|
|
|
.spawn()
|
|
|
.expect("Failed to spawn opencode");
|
|
|
|
|
|
tokio::spawn(async move {
|
|
|
+ let mut exit_tx = Some(exit_tx);
|
|
|
while let Some(event) = rx.recv().await {
|
|
|
match event {
|
|
|
CommandEvent::Stdout(line_bytes) => {
|
|
|
@@ -321,10 +356,35 @@ pub fn serve(app: &AppHandle, hostname: &str, port: u32, password: &str) -> Comm
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ CommandEvent::Error(err) => {
|
|
|
+ eprintln!("{err}");
|
|
|
+
|
|
|
+ if let Ok(mut logs) = log_state_clone.0.lock() {
|
|
|
+ logs.push_back(format!("[ERROR] {err}\n"));
|
|
|
+ while logs.len() > MAX_LOG_ENTRIES {
|
|
|
+ logs.pop_front();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ CommandEvent::Terminated(payload) => {
|
|
|
+ if let Ok(mut logs) = log_state_clone.0.lock() {
|
|
|
+ logs.push_back(format!(
|
|
|
+ "[EXIT] code={:?} signal={:?}\n",
|
|
|
+ payload.code, payload.signal
|
|
|
+ ));
|
|
|
+ while logs.len() > MAX_LOG_ENTRIES {
|
|
|
+ logs.pop_front();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if let Some(tx) = exit_tx.take() {
|
|
|
+ let _ = tx.send(payload);
|
|
|
+ }
|
|
|
+ }
|
|
|
_ => {}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- child
|
|
|
+ (child, exit_rx)
|
|
|
}
|