Skip to content

Commit 52c96ba

Browse files
authored
refactor(iroh)!: Eliminate the type parameter for the rpc service type (#2405)
## Description Eliminate the type parameter for the rpc service type in the builder. We are going to need more type parameters if we want to make rpc generic and extendable, so we need to make some room... :-) ~~todo: needs new minor version of quic-rpc to make boxed(...) public~~ ## Breaking Changes - Builder loses the `E` type parameter - ProtocolBuilder loses the `E` type parameter - rpc_endpoint takes a `boxed::ServerEndpoint` ## Notes & open questions Note: we now require the user to box the rpc_endpoint if they want to do a custom one. But since that is most likely a non-mem version it should not have a performance impact. If you want a mem rpc controller, we already have that... ## Change checklist - [x] Self-review. - [x] Documentation updates if relevant. - [x] Tests if relevant. - [x] All breaking changes documented.
1 parent d30ed19 commit 52c96ba

File tree

3 files changed

+58
-28
lines changed

3 files changed

+58
-28
lines changed

iroh/src/node/builder.rs

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,8 @@ use iroh_net::{
2121
relay::RelayMode,
2222
Endpoint,
2323
};
24-
use quic_rpc::{
25-
transport::{
26-
flume::FlumeServerEndpoint, misc::DummyServerEndpoint, quinn::QuinnServerEndpoint,
27-
},
28-
ServiceEndpoint,
24+
use quic_rpc::transport::{
25+
boxed::BoxableServerEndpoint, flume::FlumeServerEndpoint, quinn::QuinnServerEndpoint,
2926
};
3027
use serde::{Deserialize, Serialize};
3128
use tokio_util::{sync::CancellationToken, task::LocalPoolHandle};
@@ -56,6 +53,11 @@ const DEFAULT_GC_INTERVAL: Duration = Duration::from_secs(60 * 5);
5653
const MAX_CONNECTIONS: u32 = 1024;
5754
const MAX_STREAMS: u64 = 10;
5855

56+
type BoxedServerEndpoint = quic_rpc::transport::boxed::ServerEndpoint<
57+
crate::rpc_protocol::Request,
58+
crate::rpc_protocol::Response,
59+
>;
60+
5961
/// Storage backend for documents.
6062
#[derive(Debug, Clone)]
6163
pub enum DocsStorage {
@@ -81,15 +83,14 @@ pub enum DocsStorage {
8183
/// The returned [`Node`] is awaitable to know when it finishes. It can be terminated
8284
/// using [`Node::shutdown`].
8385
#[derive(derive_more::Debug)]
84-
pub struct Builder<D, E = DummyServerEndpoint>
86+
pub struct Builder<D>
8587
where
8688
D: Map,
87-
E: ServiceEndpoint<RpcService>,
8889
{
8990
storage: StorageConfig,
9091
bind_port: Option<u16>,
9192
secret_key: SecretKey,
92-
rpc_endpoint: E,
93+
rpc_endpoint: BoxedServerEndpoint,
9394
rpc_port: Option<u16>,
9495
blobs_store: D,
9596
keylog: bool,
@@ -146,6 +147,40 @@ impl From<Box<ConcurrentDiscovery>> for DiscoveryConfig {
146147
}
147148
}
148149

150+
/// A server endpoint that does nothing. Accept will never resolve.
151+
///
152+
/// This is used unless an external rpc endpoint is configured.
153+
#[derive(Debug, Default)]
154+
struct DummyServerEndpoint;
155+
156+
impl BoxableServerEndpoint<crate::rpc_protocol::Request, crate::rpc_protocol::Response>
157+
for DummyServerEndpoint
158+
{
159+
fn clone_box(
160+
&self,
161+
) -> Box<dyn BoxableServerEndpoint<crate::rpc_protocol::Request, crate::rpc_protocol::Response>>
162+
{
163+
Box::new(DummyServerEndpoint)
164+
}
165+
166+
fn accept_bi_boxed(
167+
&self,
168+
) -> quic_rpc::transport::boxed::AcceptFuture<
169+
crate::rpc_protocol::Request,
170+
crate::rpc_protocol::Response,
171+
> {
172+
quic_rpc::transport::boxed::AcceptFuture::boxed(futures_lite::future::pending())
173+
}
174+
175+
fn local_addr(&self) -> &[quic_rpc::transport::LocalAddr] {
176+
&[]
177+
}
178+
}
179+
180+
fn mk_external_rpc() -> BoxedServerEndpoint {
181+
quic_rpc::transport::boxed::ServerEndpoint::new(DummyServerEndpoint)
182+
}
183+
149184
impl Default for Builder<iroh_blobs::store::mem::Store> {
150185
fn default() -> Self {
151186
Self {
@@ -156,7 +191,7 @@ impl Default for Builder<iroh_blobs::store::mem::Store> {
156191
keylog: false,
157192
relay_mode: RelayMode::Default,
158193
dns_resolver: None,
159-
rpc_endpoint: Default::default(),
194+
rpc_endpoint: mk_external_rpc(),
160195
rpc_port: None,
161196
gc_policy: GcPolicy::Disabled,
162197
docs_storage: DocsStorage::Memory,
@@ -183,7 +218,7 @@ impl<D: Map> Builder<D> {
183218
keylog: false,
184219
relay_mode: RelayMode::Default,
185220
dns_resolver: None,
186-
rpc_endpoint: Default::default(),
221+
rpc_endpoint: mk_external_rpc(),
187222
rpc_port: None,
188223
gc_policy: GcPolicy::Disabled,
189224
docs_storage,
@@ -195,16 +230,15 @@ impl<D: Map> Builder<D> {
195230
}
196231
}
197232

198-
impl<D, E> Builder<D, E>
233+
impl<D> Builder<D>
199234
where
200235
D: BaoStore,
201-
E: ServiceEndpoint<RpcService>,
202236
{
203237
/// Persist all node data in the provided directory.
204238
pub async fn persist(
205239
self,
206240
root: impl AsRef<Path>,
207-
) -> Result<Builder<iroh_blobs::store::fs::Store, E>> {
241+
) -> Result<Builder<iroh_blobs::store::fs::Store>> {
208242
let root = root.as_ref();
209243
let blob_dir = IrohPaths::BaoStoreDir.with_root(root);
210244

@@ -260,11 +294,7 @@ where
260294
}
261295

262296
/// Configure rpc endpoint, changing the type of the builder to the new endpoint type.
263-
pub fn rpc_endpoint<E2: ServiceEndpoint<RpcService>>(
264-
self,
265-
value: E2,
266-
port: Option<u16>,
267-
) -> Builder<D, E2> {
297+
pub fn rpc_endpoint(self, value: BoxedServerEndpoint, port: Option<u16>) -> Builder<D> {
268298
// we can't use ..self here because the return type is different
269299
Builder {
270300
storage: self.storage,
@@ -286,8 +316,9 @@ where
286316
}
287317

288318
/// Configure the default iroh rpc endpoint.
289-
pub async fn enable_rpc(self) -> Result<Builder<D, QuinnServerEndpoint<RpcService>>> {
319+
pub async fn enable_rpc(self) -> Result<Builder<D>> {
290320
let (ep, actual_rpc_port) = make_rpc_endpoint(&self.secret_key, DEFAULT_RPC_PORT)?;
321+
let ep = quic_rpc::transport::boxed::ServerEndpoint::new(ep);
291322
if let StorageConfig::Persistent(ref root) = self.storage {
292323
// store rpc endpoint
293324
RpcStatus::store(root, actual_rpc_port).await?;
@@ -416,7 +447,7 @@ where
416447
///
417448
/// Returns an [`ProtocolBuilder`], on which custom protocols can be registered with
418449
/// [`ProtocolBuilder::accept`]. To spawn the node, call [`ProtocolBuilder::spawn`].
419-
pub async fn build(self) -> Result<ProtocolBuilder<D, E>> {
450+
pub async fn build(self) -> Result<ProtocolBuilder<D>> {
420451
// Clone the blob store to shutdown in case of error.
421452
let blobs_store = self.blobs_store.clone();
422453
match self.build_inner().await {
@@ -428,7 +459,7 @@ where
428459
}
429460
}
430461

431-
async fn build_inner(self) -> Result<ProtocolBuilder<D, E>> {
462+
async fn build_inner(self) -> Result<ProtocolBuilder<D>> {
432463
trace!("building node");
433464
let lp = LocalPoolHandle::new(num_cpus::get());
434465
let endpoint = {
@@ -547,17 +578,18 @@ where
547578
/// Note that RPC calls performed with client returned from [`Self::client`] will not complete
548579
/// until the node is spawned.
549580
#[derive(derive_more::Debug)]
550-
pub struct ProtocolBuilder<D, E> {
581+
pub struct ProtocolBuilder<D> {
551582
inner: Arc<NodeInner<D>>,
552583
internal_rpc: FlumeServerEndpoint<RpcService>,
553-
external_rpc: E,
584+
#[debug("external rpc")]
585+
external_rpc: BoxedServerEndpoint,
554586
protocols: ProtocolMap,
555587
#[debug("callback")]
556588
gc_done_callback: Option<Box<dyn Fn() + Send>>,
557589
gc_policy: GcPolicy,
558590
}
559591

560-
impl<D: iroh_blobs::store::Store, E: ServiceEndpoint<RpcService>> ProtocolBuilder<D, E> {
592+
impl<D: iroh_blobs::store::Store> ProtocolBuilder<D> {
561593
/// Registers a protocol handler for incoming connections.
562594
///
563595
/// Use this to register custom protocols onto the iroh node. Whenever a new connection for

iroh/tests/provide.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use futures_lite::FutureExt;
1111
use iroh::node::{Builder, DocsStorage};
1212
use iroh_base::node_addr::AddrInfoOptions;
1313
use iroh_net::{defaults::default_relay_map, key::SecretKey, NodeAddr, NodeId};
14-
use quic_rpc::transport::misc::DummyServerEndpoint;
1514
use rand::RngCore;
1615

1716
use bao_tree::{blake3, ChunkNum, ChunkRanges};
@@ -39,7 +38,7 @@ async fn dial(secret_key: SecretKey, peer: NodeAddr) -> anyhow::Result<quinn::Co
3938
.context("failed to connect to provider")
4039
}
4140

42-
fn test_node<D: Store>(db: D) -> Builder<D, DummyServerEndpoint> {
41+
fn test_node<D: Store>(db: D) -> Builder<D> {
4342
iroh::node::Builder::with_db_and_store(db, DocsStorage::Memory, iroh::node::StorageConfig::Mem)
4443
.bind_port(0)
4544
}

iroh/tests/sync.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use iroh::{
1818
net::key::{PublicKey, SecretKey},
1919
node::{Builder, Node},
2020
};
21-
use quic_rpc::transport::misc::DummyServerEndpoint;
2221
use rand::{CryptoRng, Rng, SeedableRng};
2322
use tracing::{debug, error_span, info, Instrument};
2423
use tracing_subscriber::{prelude::*, EnvFilter};
@@ -32,7 +31,7 @@ use iroh_net::relay::RelayMode;
3231

3332
const TIMEOUT: Duration = Duration::from_secs(60);
3433

35-
fn test_node(secret_key: SecretKey) -> Builder<iroh_blobs::store::mem::Store, DummyServerEndpoint> {
34+
fn test_node(secret_key: SecretKey) -> Builder<iroh_blobs::store::mem::Store> {
3635
Node::memory()
3736
.secret_key(secret_key)
3837
.relay_mode(RelayMode::Disabled)

0 commit comments

Comments
 (0)