Skip to content

Commit 4822881

Browse files
committed
transport: Add convenience methods for common operations
Add Sender::notify() and Sender::notify_with_fds() to reduce the boilerplate of constructing notification messages manually. Previously this required 4-5 lines of nested object construction. Add Receiver::receive_opt() which returns Ok(None) on connection close instead of Err(ConnectionClosed). This enables cleaner receiver loops: while let Some(msg) = receiver.receive_opt().await? { ... } Also make UnixSocketTransport::new() return Self instead of Result<Self> since it cannot fail. Assisted-by: OpenCode (Opus 4.5) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 6d4aa06 commit 4822881

1 file changed

Lines changed: 59 additions & 3 deletions

File tree

src/transport.rs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::error::{Error, Result};
2-
use crate::message::{get_fd_count, JsonRpcMessage, MessageWithFds};
2+
use crate::message::{get_fd_count, JsonRpcMessage, JsonRpcNotification, MessageWithFds};
33
use rustix::fd::AsFd;
4+
use serde::Serialize;
45
use rustix::net::{
56
RecvAncillaryBuffer, RecvAncillaryMessage, RecvFlags, SendAncillaryBuffer,
67
SendAncillaryMessage, SendFlags,
@@ -33,8 +34,8 @@ pub struct UnixSocketTransport {
3334
}
3435

3536
impl UnixSocketTransport {
36-
pub fn new(stream: TokioUnixStream) -> Result<Self> {
37-
Ok(Self { stream })
37+
pub fn new(stream: TokioUnixStream) -> Self {
38+
Self { stream }
3839
}
3940

4041
pub fn split(self) -> (Sender, Receiver) {
@@ -82,6 +83,36 @@ impl Sender {
8283
self.max_fds_per_sendmsg = max_fds;
8384
}
8485

86+
/// Send a notification without file descriptors.
87+
///
88+
/// This is a convenience method that serializes the params and constructs
89+
/// the notification message automatically.
90+
pub async fn notify<P: Serialize>(&mut self, method: &str, params: P) -> Result<()> {
91+
self.notify_with_fds(method, params, Vec::new()).await
92+
}
93+
94+
/// Send a notification with file descriptors.
95+
///
96+
/// This is a convenience method that serializes the params and constructs
97+
/// the notification message automatically.
98+
pub async fn notify_with_fds<P: Serialize>(
99+
&mut self,
100+
method: &str,
101+
params: P,
102+
fds: Vec<OwnedFd>,
103+
) -> Result<()> {
104+
let params_value = serde_json::to_value(params)?;
105+
let params_opt = if params_value.is_null() {
106+
None
107+
} else {
108+
Some(params_value)
109+
};
110+
let notification = JsonRpcNotification::new(method.to_string(), params_opt);
111+
let message = JsonRpcMessage::Notification(notification);
112+
let message_with_fds = MessageWithFds::new(message, fds);
113+
self.send(message_with_fds).await
114+
}
115+
85116
pub async fn send(&mut self, message_with_fds: MessageWithFds) -> Result<()> {
86117
let serialized = if self.pretty {
87118
message_with_fds.serialize_pretty()?
@@ -223,6 +254,10 @@ pub struct Receiver {
223254
}
224255

225256
impl Receiver {
257+
/// Receive a message, returning an error on connection close.
258+
///
259+
/// See also [`receive_opt`](Self::receive_opt) which returns `Ok(None)`
260+
/// on connection close instead of an error.
226261
pub async fn receive(&mut self) -> Result<MessageWithFds> {
227262
loop {
228263
if let Some(message) = self.try_parse_message()? {
@@ -233,6 +268,27 @@ impl Receiver {
233268
}
234269
}
235270

271+
/// Receive a message, returning `Ok(None)` on connection close.
272+
///
273+
/// This is a convenience method that converts `Error::ConnectionClosed`
274+
/// to `Ok(None)`, which is useful for receiver loops:
275+
///
276+
/// ```ignore
277+
/// while let Some(msg) = receiver.receive_opt().await? {
278+
/// // handle message
279+
/// }
280+
/// ```
281+
///
282+
/// See also [`receive`](Self::receive) which returns an error on
283+
/// connection close.
284+
pub async fn receive_opt(&mut self) -> Result<Option<MessageWithFds>> {
285+
match self.receive().await {
286+
Ok(msg) => Ok(Some(msg)),
287+
Err(Error::ConnectionClosed) => Ok(None),
288+
Err(e) => Err(e),
289+
}
290+
}
291+
236292
fn try_parse_message(&mut self) -> Result<Option<MessageWithFds>> {
237293
if self.buffer.is_empty() {
238294
return Ok(None);

0 commit comments

Comments
 (0)