Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 89 additions & 3 deletions apps/tauri/src-tauri/src/ipc_common.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,109 @@
//! Shared IPC types and command processing logic.
//!
//! This module contains the common data structures and command handling logic
//! used by both the Unix domain socket IPC ([`crate::ipc`]) and TCP socket IPC
//! ([`crate::tcp_ipc`]) transports. By centralizing command dispatch here, both
//! transports behave identically regardless of the underlying connection type.
//!
//! # Wire Protocol
//!
//! Both transports use the same newline-delimited JSON protocol:
//!
//! 1. The client sends one JSON-encoded [`IpcCommand`] per line.
//! 2. The server deserializes the command, dispatches it via [`process_command`],
//! and writes back a JSON-encoded [`IpcResponse`] followed by a newline.
//!
//! # Supported Commands
//!
//! | Command | Description | Requires `path` |
//! |----------|------------------------------------------|-----------------|
//! | `open` | Open a file in the app and focus window | Yes |
//! | `ping` | Health check — always returns success | No |
//! | `show` | Bring the app window to the foreground | No |
//!
//! # Platform Compatibility
//!
//! This module itself is platform-independent. The Unix socket transport
//! (`ipc.rs`) is conditionally compiled on Unix systems only, while the TCP
//! transport (`tcp_ipc.rs`) is available on all platforms.

use serde::{Deserialize, Serialize};
use tauri::{Emitter, Manager};

/// IPC command structure shared between Unix socket and TCP implementations
/// An IPC command received from an external process.
///
/// Commands are deserialized from JSON objects sent over the IPC socket.
/// Each command has a name and an optional file path argument.
///
/// # Examples
///
/// ```json
/// {"command": "open", "path": "/Users/me/notes.md"}
/// {"command": "ping"}
/// {"command": "show"}
/// ```
#[derive(Deserialize)]
pub struct IpcCommand {
/// The command name to execute (e.g. `"open"`, `"ping"`, `"show"`).
pub command: String,
/// An optional file path argument. Required for the `"open"` command;
/// ignored by other commands. Defaults to `None` when omitted from JSON.
#[serde(default)]
pub path: Option<String>,
}

/// IPC response structure shared between Unix socket and TCP implementations
/// The response returned after processing an [`IpcCommand`].
///
/// Serialized as a JSON object and sent back to the client over the IPC socket.
/// When the command succeeds, `success` is `true` and `error` is omitted from
/// the output. On failure, `success` is `false` and `error` contains a
/// human-readable description of what went wrong.
///
/// # Examples
///
/// ```json
/// {"success": true}
/// {"success": false, "error": "Missing 'path' field"}
/// ```
#[derive(Serialize)]
pub struct IpcResponse {
/// Whether the command completed successfully.
pub success: bool,
/// A human-readable error message, present only when `success` is `false`.
/// Omitted from the serialized JSON when `None`.
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}

/// Process IPC commands (shared logic for both Unix socket and TCP IPC)
/// Dispatches an [`IpcCommand`] and returns an [`IpcResponse`].
///
/// This is the shared command handler used by both the Unix socket and TCP IPC
/// transports. It matches on the command name and performs the corresponding
/// action using the Tauri application handle.
///
/// # Supported Commands
///
/// - **`open`** — Opens a file in the application. Requires [`IpcCommand::path`]
/// to be set. The path is canonicalized via [`std::fs::canonicalize`], the main
/// window is brought to focus, and an `"open-file"` event is emitted to the
/// frontend. Returns an error if the path is missing, invalid, or the event
/// fails to emit.
/// - **`ping`** — A simple health check. Always returns `success: true` with no
/// side effects.
/// - **`show`** — Brings the main application window to the foreground by
/// unminimizing, showing, and focusing it. Always returns `success: true`.
///
/// Any unrecognized command name returns `success: false` with an error message.
///
/// # Parameters
///
/// - `cmd` — The deserialized [`IpcCommand`] to process.
/// - `app` — A reference to the Tauri [`AppHandle`](tauri::AppHandle), used to
/// access windows and emit events.
///
/// # Returns
///
/// An [`IpcResponse`] indicating whether the command succeeded or failed.
pub fn process_command(cmd: IpcCommand, app: &tauri::AppHandle) -> IpcResponse {
match cmd.command.as_str() {
"open" => {
Expand Down