diff options
| author | Adam <[email protected]> | 2025-12-22 20:01:16 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-12-22 20:01:25 -0600 |
| commit | 81c3c638953fb7730a6965b3614d57e3c4919dde (patch) | |
| tree | bea87a6b98078d52dd037da16500b29a28587edc /packages/tauri/src-tauri/src | |
| parent | b76bd4141dd78db94ab485743b4dc21d918cd85e (diff) | |
| download | opencode-81c3c638953fb7730a6965b3614d57e3c4919dde.tar.gz opencode-81c3c638953fb7730a6965b3614d57e3c4919dde.zip | |
chore: rename packages/tauri -> packages/desktop
Diffstat (limited to 'packages/tauri/src-tauri/src')
| -rw-r--r-- | packages/tauri/src-tauri/src/lib.rs | 308 | ||||
| -rw-r--r-- | packages/tauri/src-tauri/src/main.rs | 63 | ||||
| -rw-r--r-- | packages/tauri/src-tauri/src/window_customizer.rs | 34 |
3 files changed, 0 insertions, 405 deletions
diff --git a/packages/tauri/src-tauri/src/lib.rs b/packages/tauri/src-tauri/src/lib.rs deleted file mode 100644 index 3c08841ab..000000000 --- a/packages/tauri/src-tauri/src/lib.rs +++ /dev/null @@ -1,308 +0,0 @@ -mod window_customizer; - -use std::{ - collections::VecDeque, - net::{SocketAddr, TcpListener}, - sync::{Arc, Mutex}, - time::{Duration, Instant}, -}; -use tauri::{AppHandle, LogicalSize, Manager, RunEvent, WebviewUrl, WebviewWindow, path::BaseDirectory}; -use tauri_plugin_clipboard_manager::ClipboardExt; -use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogResult}; -use tauri_plugin_shell::process::{CommandChild, CommandEvent}; -use tauri_plugin_shell::ShellExt; -use tokio::net::TcpSocket; - -use crate::window_customizer::PinchZoomDisablePlugin; - -#[derive(Clone)] -struct ServerState(Arc<Mutex<Option<CommandChild>>>); - -#[derive(Clone)] -struct LogState(Arc<Mutex<VecDeque<String>>>); - -const MAX_LOG_ENTRIES: usize = 200; - -#[tauri::command] -fn kill_sidecar(app: AppHandle) { - let Some(server_state) = app.try_state::<ServerState>() else { - println!("Server not running"); - return; - }; - - let Some(server_state) = server_state - .0 - .lock() - .expect("Failed to acquire mutex lock") - .take() - else { - println!("Server state missing"); - return; - }; - - let _ = server_state.kill(); - - println!("Killed server"); -} - -#[tauri::command] -async fn copy_logs_to_clipboard(app: AppHandle) -> Result<(), String> { - let log_state = app.try_state::<LogState>().ok_or("Log state not found")?; - - let logs = log_state - .0 - .lock() - .map_err(|_| "Failed to acquire log lock")?; - - let log_text = logs.iter().cloned().collect::<Vec<_>>().join(""); - - app.clipboard() - .write_text(log_text) - .map_err(|e| format!("Failed to copy to clipboard: {}", e))?; - - Ok(()) -} - -#[tauri::command] -async fn get_logs(app: AppHandle) -> Result<String, String> { - let log_state = app.try_state::<LogState>().ok_or("Log state not found")?; - - let logs = log_state - .0 - .lock() - .map_err(|_| "Failed to acquire log lock")?; - - Ok(logs.iter().cloned().collect::<Vec<_>>().join("")) -} - -fn get_sidecar_port() -> u32 { - option_env!("OPENCODE_PORT") - .map(|s| s.to_string()) - .or_else(|| std::env::var("OPENCODE_PORT").ok()) - .and_then(|port_str| port_str.parse().ok()) - .unwrap_or_else(|| { - TcpListener::bind("127.0.0.1:0") - .expect("Failed to bind to find free port") - .local_addr() - .expect("Failed to get local address") - .port() - }) as u32 -} - -fn get_user_shell() -> String { - std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string()) -} - -fn spawn_sidecar(app: &AppHandle, port: u32) -> CommandChild { - let log_state = app.state::<LogState>(); - let log_state_clone = log_state.inner().clone(); - - let state_dir = app - .path() - .resolve("", BaseDirectory::AppLocalData) - .expect("Failed to resolve app local data dir"); - - #[cfg(target_os = "windows")] - let (mut rx, child) = app - .shell() - .sidecar("opencode-cli") - .unwrap() - .env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true") - .env("OPENCODE_CLIENT", "desktop") - .env("XDG_STATE_HOME", &state_dir) - .args(["serve", &format!("--port={port}")]) - .spawn() - .expect("Failed to spawn opencode"); - - #[cfg(not(target_os = "windows"))] - let (mut rx, child) = { - let sidecar_path = tauri::utils::platform::current_exe() - .expect("Failed to get current exe") - .parent() - .expect("Failed to get parent dir") - .join("opencode-cli"); - let shell = get_user_shell(); - app.shell() - .command(&shell) - .env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true") - .env("OPENCODE_CLIENT", "desktop") - .env("XDG_STATE_HOME", &state_dir) - .args([ - "-il", - "-c", - &format!("{} serve --port={}", sidecar_path.display(), port), - ]) - .spawn() - .expect("Failed to spawn opencode") - }; - - tauri::async_runtime::spawn(async move { - while let Some(event) = rx.recv().await { - match event { - CommandEvent::Stdout(line_bytes) => { - let line = String::from_utf8_lossy(&line_bytes); - print!("{line}"); - - // Store log in shared state - if let Ok(mut logs) = log_state_clone.0.lock() { - logs.push_back(format!("[STDOUT] {}", line)); - // Keep only the last MAX_LOG_ENTRIES - while logs.len() > MAX_LOG_ENTRIES { - logs.pop_front(); - } - } - } - CommandEvent::Stderr(line_bytes) => { - let line = String::from_utf8_lossy(&line_bytes); - eprint!("{line}"); - - // Store log in shared state - if let Ok(mut logs) = log_state_clone.0.lock() { - logs.push_back(format!("[STDERR] {}", line)); - // Keep only the last MAX_LOG_ENTRIES - while logs.len() > MAX_LOG_ENTRIES { - logs.pop_front(); - } - } - } - _ => {} - } - } - }); - - child -} - -async fn is_server_running(port: u32) -> bool { - TcpSocket::new_v4() - .unwrap() - .connect(SocketAddr::new( - "127.0.0.1".parse().expect("Failed to parse IP"), - port as u16, - )) - .await - .is_ok() -} - -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - let updater_enabled = option_env!("TAURI_SIGNING_PRIVATE_KEY").is_some(); - - let mut builder = tauri::Builder::default() - .plugin(tauri_plugin_os::init()) - .plugin(tauri_plugin_window_state::Builder::new().build()) - .plugin(tauri_plugin_store::Builder::new().build()) - .plugin(tauri_plugin_dialog::init()) - .plugin(tauri_plugin_shell::init()) - .plugin(tauri_plugin_process::init()) - .plugin(tauri_plugin_opener::init()) - .plugin(tauri_plugin_clipboard_manager::init()) - .plugin(tauri_plugin_http::init()) - .plugin(PinchZoomDisablePlugin) - .invoke_handler(tauri::generate_handler![ - kill_sidecar, - copy_logs_to_clipboard, - get_logs - ]) - .setup(move |app| { - let app = app.handle().clone(); - - // Initialize log state - app.manage(LogState(Arc::new(Mutex::new(VecDeque::new())))); - - tauri::async_runtime::spawn(async move { - let port = get_sidecar_port(); - - let should_spawn_sidecar = !is_server_running(port).await; - - let child = if should_spawn_sidecar { - let child = spawn_sidecar(&app, port); - - let timestamp = Instant::now(); - loop { - if timestamp.elapsed() > Duration::from_secs(7) { - let res = app.dialog() - .message("Failed to spawn OpenCode Server. Copy logs using the button below and send them to the team for assistance.") - .title("Startup Failed") - .buttons(MessageDialogButtons::OkCancelCustom("Copy Logs And Exit".to_string(), "Exit".to_string())) - .blocking_show_with_result(); - - if matches!(&res, MessageDialogResult::Custom(name) if name == "Copy Logs And Exit") { - match copy_logs_to_clipboard(app.clone()).await { - Ok(()) => println!("Logs copied to clipboard successfully"), - Err(e) => println!("Failed to copy logs to clipboard: {}", e), - } - } - - app.exit(1); - - return; - } - - tokio::time::sleep(Duration::from_millis(10)).await; - - if is_server_running(port).await { - // give the server a little bit more time to warm up - tokio::time::sleep(Duration::from_millis(10)).await; - - break; - } - } - - println!("Server ready after {:?}", timestamp.elapsed()); - - Some(child) - } else { - None - }; - - let primary_monitor = app.primary_monitor().ok().flatten(); - let size = primary_monitor - .map(|m| m.size().to_logical(m.scale_factor())) - .unwrap_or(LogicalSize::new(1920, 1080)); - - let mut window_builder = - WebviewWindow::builder(&app, "main", WebviewUrl::App("/".into())) - .title("OpenCode") - .inner_size(size.width as f64, size.height as f64) - .decorations(true) - .zoom_hotkeys_enabled(true) - .disable_drag_drop_handler() - .initialization_script(format!( - r#" - window.__OPENCODE__ ??= {{}}; - window.__OPENCODE__.updaterEnabled = {updater_enabled}; - window.__OPENCODE__.port = {port}; - "# - )); - - #[cfg(target_os = "macos")] - { - window_builder = window_builder - .title_bar_style(tauri::TitleBarStyle::Overlay) - .hidden_title(true); - } - - window_builder.build().expect("Failed to create window"); - - app.manage(ServerState(Arc::new(Mutex::new(child)))); - }); - - Ok(()) - }); - - if updater_enabled { - builder = builder.plugin(tauri_plugin_updater::Builder::new().build()); - } - - builder - .build(tauri::generate_context!()) - .expect("error while running tauri application") - .run(|app, event| { - if let RunEvent::Exit = event { - println!("Received Exit"); - - kill_sidecar(app.clone()); - } - }); -} diff --git a/packages/tauri/src-tauri/src/main.rs b/packages/tauri/src-tauri/src/main.rs deleted file mode 100644 index b215f8c55..000000000 --- a/packages/tauri/src-tauri/src/main.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -// borrowed from https://github.com/skyline69/balatro-mod-manager -#[cfg(target_os = "linux")] -fn configure_display_backend() -> Option<String> { - use std::env; - - let set_env_if_absent = |key: &str, value: &str| { - if env::var_os(key).is_none() { - // Safety: called during startup before any threads are spawned, so mutating the - // process environment is safe. - unsafe { env::set_var(key, value) }; - } - }; - - let on_wayland = env::var_os("WAYLAND_DISPLAY").is_some() - || matches!( - env::var("XDG_SESSION_TYPE"), - Ok(v) if v.eq_ignore_ascii_case("wayland") - ); - if !on_wayland { - return None; - } - - // Allow users to explicitly keep Wayland if they know their setup is stable. - let allow_wayland = matches!( - env::var("OC_ALLOW_WAYLAND"), - Ok(v) if matches!(v.to_ascii_lowercase().as_str(), "1" | "true" | "yes") - ); - if allow_wayland { - return Some("Wayland session detected; respecting OC_ALLOW_WAYLAND=1".into()); - } - - // Prefer XWayland when available to avoid Wayland protocol errors seen during startup. - if env::var_os("DISPLAY").is_some() { - set_env_if_absent("WINIT_UNIX_BACKEND", "x11"); - set_env_if_absent("GDK_BACKEND", "x11"); - set_env_if_absent("WEBKIT_DISABLE_DMABUF_RENDERER", "1"); - return Some( - "Wayland session detected; forcing X11 backend to avoid compositor protocol errors. \ - Set OC_ALLOW_WAYLAND=1 to keep native Wayland." - .into(), - ); - } - - set_env_if_absent("WEBKIT_DISABLE_DMABUF_RENDERER", "1"); - Some( - "Wayland session detected without X11; leaving Wayland enabled (set WINIT_UNIX_BACKEND/GDK_BACKEND manually if needed)." - .into(), - ) -} - -fn main() { - #[cfg(target_os = "linux")] - { - if let Some(backend_note) = configure_display_backend() { - eprintln!("{backend_note:?}"); - } - } - - opencode_lib::run() -} diff --git a/packages/tauri/src-tauri/src/window_customizer.rs b/packages/tauri/src-tauri/src/window_customizer.rs deleted file mode 100644 index cd42fd029..000000000 --- a/packages/tauri/src-tauri/src/window_customizer.rs +++ /dev/null @@ -1,34 +0,0 @@ -use tauri::{plugin::Plugin, Manager, Runtime, Window}; - -pub struct PinchZoomDisablePlugin; - -impl Default for PinchZoomDisablePlugin { - fn default() -> Self { - Self - } -} - -impl<R: Runtime> Plugin<R> for PinchZoomDisablePlugin { - fn name(&self) -> &'static str { - "Does not matter here" - } - - fn window_created(&mut self, window: Window<R>) { - let Some(webview_window) = window.get_webview_window(window.label()) else { - return; - }; - - let _ = webview_window.with_webview(|_webview| { - #[cfg(target_os = "linux")] - unsafe { - use gtk::glib::ObjectExt; - use gtk::GestureZoom; - use webkit2gtk::glib::gobject_ffi; - - if let Some(data) = _webview.inner().data::<GestureZoom>("wk-view-zoom-gesture") { - gobject_ffi::g_signal_handlers_destroy(data.as_ptr().cast()); - } - } - }); - } -} |
