Uh oh!
There was an error while loading. Please reload this page.
feat(ipc): add Unix domain socket for inter-process communication - #10
Conversation
- Create ipc.rs module with async socket server - Implement commands: open, ping, show - Socket path: ~/.arandu/arandu.sock with 0600 permissions - Update CLI script to use socket with fallback to open - Add tokio features: net, io-util - Graceful degradation if socket setup fails
wilcorrea
commented
Feb 23, 2026
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughAdds Unix-domain socket IPC at Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI Process
participant Socket as Unix Socket\n(~/.arandu/arandu.sock)
participant Server as IPC Server Task
participant App as Tauri App
participant Window as Main Window
CLI->>Socket: connect()
CLI->>Server: send JSON {"command":"open","path":"/abs/path"}\n
Server->>Server: parse JSON, canonicalize path
Server->>App: emit "open-file" event (abs path)
App->>Window: show / unminimize / focus
App-->>Server: event handled
Server->>Socket: send JSON {"success":true}\n
CLI->>CLI: exit(0)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/tauri/src-tauri/src/cli_installer.rs`:
- Around line 8-17: The IPC block around SOCKET currently assumes nc always
succeeds, skips sending when no args are passed, and embeds raw paths into JSON;
change it so you first detect socket existence, then if $# -eq 0 send a single
'{"command":"open"}' over the socket, otherwise iterate over for f in "$@" and
build ABS as now but escape backslashes and double quotes in "$ABS" (e.g.
replace \ with \\ and " with \") before embedding into the JSON payload, write
the payload to nc and check nc's exit status for each send; if any nc call fails
(non-zero) or the socket is unreachable, stop using the socket and fall back to
the non-IPC code path (i.e. remove the unconditional exit 0 and only exit when
all IPC sends succeeded). Ensure you update references in this block: SOCKET,
the for f in "$@" loop, ABS, the JSON echo/pipe to nc and the exit 0 behavior.
In `@apps/tauri/src-tauri/src/ipc.rs`:
- Around line 24-53: The current setup() sets SocketState before attempting
UnixListener::bind, which can cause cleanup to remove another instance's socket
if bind fails; change the flow so you call socket_path() and
cleanup_stale_socket(&sock_path) as before, then attempt
UnixListener::bind(&sock_path) first, and only after bind returns Ok(listener)
acquire the state mutex (state.0.lock()) and set *guard =
Some(sock_path.clone()) before spawning the async task that calls
socket_listener_loop; on Err(e) do not set SocketState and handle/log/propagate
the error instead.
In `@apps/tauri/src-tauri/src/lib.rs`:
- Line 376: The code unconditionally registers
ipc::SocketState(Mutex::new(None)) with .manage(...) but ipc::SocketState is
only available on Unix builds; wrap the manage call in a cfg guard so it only
compiles on Unix (e.g., use #[cfg(unix)] or cfg_if! around the .manage(...)
invocation) or provide a non-Unix stub type and conditional module export;
target the .manage call that references ipc::SocketState and the ipc module to
make the registration conditional.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/tauri/src-tauri/Cargo.tomlapps/tauri/src-tauri/src/cli_installer.rsapps/tauri/src-tauri/src/ipc.rsapps/tauri/src-tauri/src/lib.rs
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…cfg guard - CLI script: handle empty args (send "show"), escape paths for JSON, check nc exit status and fall back on failure - ipc.rs: set SocketState only after successful UnixListener::bind - lib.rs: wrap ipc::SocketState manage call with #[cfg(unix)]
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/tauri/src-tauri/src/ipc.rs`:
- Around line 63-71: The ~/.arandu directory creation in socket_path does not
enforce restrictive permissions; after creating the directory with
std::fs::create_dir_all(&arandu_dir) update the code to explicitly set
permissions to 0o700 (owner rwx only) to prevent cross‑user access. Use
std::fs::set_permissions(&arandu_dir, std::fs::Permissions::from_mode(0o700))
(with std::os::unix::fs::PermissionsExt imported) and propagate/map any error
into the same Result error path so failures to apply the 0700 permissions are
handled and logged similarly to the existing create_dir_all error. Ensure this
change is applied in the socket_path function surrounding the arandu_dir
variable.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/tauri/src-tauri/src/cli_installer.rsapps/tauri/src-tauri/src/ipc.rsapps/tauri/src-tauri/src/lib.rs
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/tauri/src-tauri/src/ipc.rs (1)
94-110: Add a small backoff on accept errors to avoid tight loops.If the listener starts erroring (e.g., after shutdown), the loop can spin and log rapidly; a short delay prevents that. If Tokio’s
timefeature isn’t enabled yet, you’ll need to add it.♻️ Proposed backoff on accept errors
-use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};+use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};+use tokio::time::sleep;+use std::time::Duration;Err(e) => { eprintln!("Accept error: {}", e); + sleep(Duration::from_millis(200)).await; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/tauri/src-tauri/src/ipc.rs` around lines 94 - 110, The accept error handling in socket_listener_loop currently immediately continues on Err(e), which can cause a tight loop; modify the Err branch in socket_listener_loop to await a short sleep (e.g., tokio::time::sleep(Duration::from_millis(100)).await) after logging the error to provide a small backoff, and ensure the tokio "time" feature is enabled in Cargo.toml if not already; keep using the same listener.accept().await flow and spawn behavior for Ok((stream, _addr)).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@apps/tauri/src-tauri/src/ipc.rs`:
- Around line 94-110: The accept error handling in socket_listener_loop
currently immediately continues on Err(e), which can cause a tight loop; modify
the Err branch in socket_listener_loop to await a short sleep (e.g.,
tokio::time::sleep(Duration::from_millis(100)).await) after logging the error to
provide a small backoff, and ensure the tokio "time" feature is enabled in
Cargo.toml if not already; keep using the same listener.accept().await flow and
spawn behavior for Ok((stream, _addr)).
Summary
~/.arandu/arandu.sockfor fast IPC communicationopen(opens markdown files),ping(health check),show(brings window to focus)open --argswhen app isn't runningTest plan
~/.arandu/arandu.sockecho '{"command":"ping"}' | nc -U ~/.arandu/arandu.sockecho '{"command":"open","path":"/path/to/file.md"}' | nc -U ~/.arandu/arandu.sockecho '{"command":"show"}' | nc -U ~/.arandu/arandu.sockarandu path/to/file.md(should use socket if app is running)arandu file.md(should start app using traditional method)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores