Skip to content

Commit 37ef310

Browse files
committed
Minimize deps even more
1 parent 2b55b7b commit 37ef310

File tree

5 files changed

+144
-63
lines changed

5 files changed

+144
-63
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+31-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "quic-rpc"
3-
version = "0.18.3"
3+
version = "0.5.0"
44
edition = "2021"
55
authors = ["Rüdiger Klaehn <[email protected]>", "n0 team"]
66
keywords = ["api", "protocol", "network", "rpc"]
@@ -13,26 +13,45 @@ description = "A streaming rpc system based on quic"
1313
rust-version = "1.76"
1414

1515
[dependencies]
16-
anyhow = "1"
17-
derive_more = { version = "2", features = ["debug", "display", "from"] }
18-
n0-future = "0.1.2"
19-
tracing = "0.1.41"
20-
serde = { version = "1.0.219", features = ["derive"] }
21-
tokio = { version = "1.44.1", features = ["full"] }
22-
postcard = { version = "1.1.1", features = ["alloc", "use-std"], optional = true }
16+
# we require serde even in non-rpc mode
17+
serde = { version = "1", default-features = false }
18+
# just for the oneshot and mpsc queues
19+
tokio = { version = "1", features = ["sync"], default-features = false }
20+
21+
# used in the endpoint handler code when using rpc
22+
tracing = { version = "0.1.41", optional = true }
23+
# used to ser/de messages when using rpc
24+
postcard = { version = "1", features = ["alloc", "use-std"], optional = true }
25+
# currently only transport when using rpc
2326
quinn = { version = "0.13.0", package = "iroh-quinn", optional = true }
24-
tracing-subscriber = { version = "0.3.19", features = ["fmt"] }
27+
# used as a buffer for serialization when using rpc
28+
smallvec = { version = "1.14.0", features = ["write"], optional = true }
29+
# used in the test utils to generate quinn endpoints
2530
rustls = { version = "0.23.5", default-features = false, features = ["std"], optional = true }
31+
# used in the test utils to generate quinn endpoints
2632
rcgen = { version = "0.13.2", optional = true }
27-
smallvec = { version = "1.14.0", features = ["write"] }
33+
# used in the test utils to generate quinn endpoints
34+
anyhow = { version = "1", optional = true }
2835

2936
[dev-dependencies]
37+
tracing-subscriber = { version = "0.3.19", features = ["fmt"] }
38+
# used in the derive example. This must not be a main crate dep or else it will be circular!
3039
quic-rpc-derive = { path = "quic-rpc-derive" }
40+
# just convenient for the enum definitions
41+
derive_more = { version = "2", features = ["debug", "display", "from"] }
42+
# we need full for example main etc.
43+
tokio = { version = "1", features = ["full"] }
44+
# for AbortOnDropHandle
45+
n0-future = "0.1.2"
3146

3247
[features]
33-
rpc = ["dep:quinn", "dep:postcard"]
48+
# enable the remote transport
49+
rpc = ["dep:quinn", "dep:postcard", "dep:smallvec", "dep:tracing"]
50+
# add test utilities
51+
test = ["dep:rustls", "dep:rcgen", "dep:anyhow"]
52+
# switch on to avoid needing Send on the boxed futures
53+
wasm-browser = []
3454
default = ["rpc", "test"]
35-
test = ["rustls", "rcgen"]
3655

3756
[workspace]
3857
members = ["quic-rpc-derive"]

examples/derive.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ impl StorageApi {
133133
Ok(())
134134
})
135135
});
136-
Ok(listen(endpoint, fun))
136+
let x = AbortOnDropHandle::new(tokio::spawn(listen(endpoint, fun)));
137+
Ok(x)
137138
}
138139
ServiceSender::Remote(_, _, _) => {
139140
Err(anyhow::anyhow!("cannot listen on a remote service"))

examples/storage.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ impl StorageApi {
146146
Ok(())
147147
})
148148
});
149-
Ok(listen(endpoint, fun))
149+
Ok(AbortOnDropHandle::new(tokio::spawn(listen(endpoint, fun))))
150150
}
151151
ServiceSender::Remote(_, _, _) => {
152152
Err(anyhow::anyhow!("cannot listen on a remote service"))

src/lib.rs

+109-48
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{fmt::Debug, marker::PhantomData, net::SocketAddr, ops::Deref};
1+
use std::{fmt::Debug, io, marker::PhantomData, ops::Deref};
22

33
use channel::none::NoReceiver;
44
use serde::{de::DeserializeOwned, Serialize};
@@ -33,6 +33,20 @@ pub trait Channels<S: Service> {
3333
type Rx: Receiver;
3434
}
3535

36+
mod wasm_browser {
37+
#![allow(dead_code)]
38+
pub type BoxedFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + 'a>>;
39+
}
40+
mod multithreaded {
41+
#![allow(dead_code)]
42+
pub type BoxedFuture<'a, T> =
43+
std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>;
44+
}
45+
#[cfg(not(feature = "wasm-browser"))]
46+
pub use multithreaded::*;
47+
#[cfg(feature = "wasm-browser")]
48+
pub use wasm_browser::*;
49+
3650
/// Channels that abstract over local or remote sending
3751
pub mod channel {
3852
/// Oneshot channel, similar to tokio's oneshot channel
@@ -48,7 +62,7 @@ pub mod channel {
4862
Tokio(tokio::sync::oneshot::Sender<T>),
4963
Boxed(
5064
Box<
51-
dyn FnOnce(T) -> n0_future::future::Boxed<io::Result<()>>
65+
dyn FnOnce(T) -> crate::BoxedFuture<'static, io::Result<()>>
5266
+ Send
5367
+ Sync
5468
+ 'static,
@@ -71,12 +85,27 @@ pub mod channel {
7185
}
7286
}
7387

74-
#[derive(Debug, derive_more::From, derive_more::Display)]
88+
#[derive(Debug)]
7589
pub enum SendError {
7690
ReceiverClosed,
7791
Io(std::io::Error),
7892
}
7993

94+
impl From<std::io::Error> for SendError {
95+
fn from(e: std::io::Error) -> Self {
96+
Self::Io(e)
97+
}
98+
}
99+
100+
impl std::fmt::Display for SendError {
101+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102+
match self {
103+
SendError::ReceiverClosed => write!(f, "receiver closed"),
104+
SendError::Io(e) => write!(f, "io error: {}", e),
105+
}
106+
}
107+
}
108+
80109
impl std::error::Error for SendError {
81110
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
82111
match self {
@@ -99,7 +128,7 @@ pub mod channel {
99128

100129
pub enum Receiver<T> {
101130
Tokio(tokio::sync::oneshot::Receiver<T>),
102-
Boxed(n0_future::future::Boxed<std::io::Result<T>>),
131+
Boxed(crate::BoxedFuture<'static, std::io::Result<T>>),
103132
}
104133

105134
impl<T> Future for Receiver<T> {
@@ -159,12 +188,27 @@ pub mod channel {
159188
(tx.into(), rx.into())
160189
}
161190

162-
#[derive(Debug, derive_more::From, derive_more::Display)]
191+
#[derive(Debug)]
163192
pub enum SendError {
164193
ReceiverClosed,
165194
Io(std::io::Error),
166195
}
167196

197+
impl From<std::io::Error> for SendError {
198+
fn from(e: std::io::Error) -> Self {
199+
Self::Io(e)
200+
}
201+
}
202+
203+
impl std::fmt::Display for SendError {
204+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205+
match self {
206+
SendError::ReceiverClosed => write!(f, "receiver closed"),
207+
SendError::Io(e) => write!(f, "io error: {}", e),
208+
}
209+
}
210+
}
211+
168212
impl std::error::Error for SendError {
169213
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
170214
match self {
@@ -329,7 +373,7 @@ impl<I: Channels<S>, S: Service> Deref for WithChannels<I, S> {
329373
pub enum ServiceSender<M, R, S> {
330374
Local(LocalMpscChannel<M, S>, PhantomData<R>),
331375
#[cfg(feature = "rpc")]
332-
Remote(quinn::Endpoint, SocketAddr, PhantomData<(R, S)>),
376+
Remote(quinn::Endpoint, std::net::SocketAddr, PhantomData<(R, S)>),
333377
}
334378

335379
impl<M, R, S> From<LocalMpscChannel<M, S>> for ServiceSender<M, R, S> {
@@ -339,12 +383,15 @@ impl<M, R, S> From<LocalMpscChannel<M, S>> for ServiceSender<M, R, S> {
339383
}
340384

341385
impl<M: Send + Sync + 'static, R, S: Service> ServiceSender<M, R, S> {
342-
pub async fn request(&self) -> anyhow::Result<ServiceRequest<M, R, S>> {
386+
pub async fn request(&self) -> io::Result<ServiceRequest<M, R, S>> {
343387
match self {
344388
Self::Local(tx, _) => Ok(ServiceRequest::from(tx.clone())),
345389
#[cfg(feature = "rpc")]
346390
Self::Remote(endpoint, addr, _) => {
347-
let connection = endpoint.connect(*addr, "localhost")?.await?;
391+
let connection = endpoint
392+
.connect(*addr, "localhost")
393+
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
394+
.await?;
348395
let (send, recv) = connection.open_bi().await?;
349396
Ok(ServiceRequest::Remote(rpc::RemoteRequest::new(send, recv)))
350397
}
@@ -371,7 +418,6 @@ impl<M, S> Clone for LocalMpscChannel<M, S> {
371418
pub mod rpc {
372419
use std::{fmt::Debug, future::Future, io, marker::PhantomData, pin::Pin, sync::Arc};
373420

374-
use n0_future::task::AbortOnDropHandle;
375421
use serde::{de::DeserializeOwned, Serialize};
376422
use smallvec::SmallVec;
377423
use tokio::task::JoinSet;
@@ -399,9 +445,15 @@ pub mod rpc {
399445
}
400446
}
401447

402-
#[derive(Debug, derive_more::From)]
448+
#[derive(Debug)]
403449
pub struct RemoteRead(quinn::RecvStream);
404450

451+
impl RemoteRead {
452+
pub(crate) fn new(recv: quinn::RecvStream) -> Self {
453+
Self(recv)
454+
}
455+
}
456+
405457
impl<T: DeserializeOwned> From<RemoteRead> for oneshot::Receiver<T> {
406458
fn from(read: RemoteRead) -> Self {
407459
let fut = async move {
@@ -432,9 +484,15 @@ pub mod rpc {
432484
}
433485
}
434486

435-
#[derive(Debug, derive_more::From)]
487+
#[derive(Debug)]
436488
pub struct RemoteWrite(quinn::SendStream);
437489

490+
impl RemoteWrite {
491+
pub(crate) fn new(send: quinn::SendStream) -> Self {
492+
Self(send)
493+
}
494+
}
495+
438496
impl<T: RpcMessage> From<RemoteWrite> for oneshot::Sender<T> {
439497
fn from(write: RemoteWrite) -> Self {
440498
let mut writer = write.0;
@@ -526,7 +584,7 @@ pub mod rpc {
526584
}
527585

528586
impl<R: Serialize, S> RemoteRequest<R, S> {
529-
pub async fn write(self, msg: impl Into<R>) -> anyhow::Result<(RemoteRead, RemoteWrite)> {
587+
pub async fn write(self, msg: impl Into<R>) -> io::Result<(RemoteRead, RemoteWrite)> {
530588
let RemoteRequest(mut send, recv, _) = self;
531589
let msg = msg.into();
532590
let mut buf = SmallVec::<[u8; 128]>::new();
@@ -538,51 +596,51 @@ pub mod rpc {
538596

539597
/// Type alias for a handler fn for remote requests
540598
pub type Handler<R> = Arc<
541-
dyn Fn(R, RemoteRead, RemoteWrite) -> n0_future::future::Boxed<anyhow::Result<()>>
599+
dyn Fn(R, RemoteRead, RemoteWrite) -> crate::BoxedFuture<'static, io::Result<()>>
542600
+ Send
543601
+ Sync
544602
+ 'static,
545603
>;
546604

547605
/// Utility function to listen for incoming connections and handle them with the provided handler
548-
pub fn listen<R: DeserializeOwned + 'static>(
606+
pub async fn listen<R: DeserializeOwned + 'static>(
549607
endpoint: quinn::Endpoint,
550608
handler: Handler<R>,
551-
) -> AbortOnDropHandle<()> {
552-
let task = tokio::spawn(async move {
553-
let mut tasks = JoinSet::new();
554-
while let Some(incoming) = endpoint.accept().await {
555-
let handler = handler.clone();
556-
tasks.spawn(async move {
557-
let connection = match incoming.await {
558-
Ok(connection) => connection,
609+
) {
610+
let mut tasks = JoinSet::new();
611+
while let Some(incoming) = endpoint.accept().await {
612+
let handler = handler.clone();
613+
tasks.spawn(async move {
614+
let connection = match incoming.await {
615+
Ok(connection) => connection,
616+
Err(cause) => {
617+
warn!("failed to accept connection {cause:?}");
618+
return io::Result::Ok(());
619+
}
620+
};
621+
loop {
622+
let (send, mut recv) = match connection.accept_bi().await {
623+
Ok((s, r)) => (s, r),
559624
Err(cause) => {
560-
warn!("failed to accept connection {cause:?}");
561-
return anyhow::Ok(());
625+
warn!("failed to accept bi stream {cause:?}");
626+
return Ok(());
562627
}
563628
};
564-
loop {
565-
let (send, mut recv) = match connection.accept_bi().await {
566-
Ok((s, r)) => (s, r),
567-
Err(cause) => {
568-
warn!("failed to accept bi stream {cause:?}");
569-
return anyhow::Ok(());
570-
}
571-
};
572-
let size = recv.read_varint_u64().await?.ok_or_else(|| {
573-
io::Error::new(io::ErrorKind::UnexpectedEof, "failed to read size")
574-
})?;
575-
let mut buf = vec![0; size as usize];
576-
recv.read_exact(&mut buf).await?;
577-
let msg: R = postcard::from_bytes(&buf)?;
578-
let rx = RemoteRead::from(recv);
579-
let tx = RemoteWrite::from(send);
580-
handler(msg, rx, tx).await?;
581-
}
582-
});
583-
}
584-
});
585-
AbortOnDropHandle::new(task)
629+
let size = recv.read_varint_u64().await?.ok_or_else(|| {
630+
io::Error::new(io::ErrorKind::UnexpectedEof, "failed to read size")
631+
})?;
632+
let mut buf = vec![0; size as usize];
633+
recv.read_exact(&mut buf)
634+
.await
635+
.map_err(|e| io::Error::new(io::ErrorKind::UnexpectedEof, e))?;
636+
let msg: R = postcard::from_bytes(&buf)
637+
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
638+
let rx = RemoteRead::new(recv);
639+
let tx = RemoteWrite::new(send);
640+
handler(msg, rx, tx).await?;
641+
}
642+
});
643+
}
586644
}
587645
}
588646

@@ -600,12 +658,15 @@ impl<M, R, S> From<LocalMpscChannel<M, S>> for ServiceRequest<M, R, S> {
600658
}
601659

602660
impl<M: Send + Sync + 'static, S: Service> LocalMpscChannel<M, S> {
603-
pub async fn send<T>(&self, value: impl Into<WithChannels<T, S>>) -> anyhow::Result<()>
661+
pub async fn send<T>(&self, value: impl Into<WithChannels<T, S>>) -> io::Result<()>
604662
where
605663
T: Channels<S>,
606664
M: From<WithChannels<T, S>>,
607665
{
608-
self.0.send(value.into().into()).await?;
666+
self.0
667+
.send(value.into().into())
668+
.await
669+
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
609670
Ok(())
610671
}
611672
}

0 commit comments

Comments
 (0)