Skip to content

Commit 6fc4cfc

Browse files
committed
replace UnoderedFutures on the main behaviour
for a channel that polls the futures on an async task.
1 parent 4172755 commit 6fc4cfc

File tree

6 files changed

+110
-46
lines changed

6 files changed

+110
-46
lines changed

Cargo.lock

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

protocols/upnp/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ libp2p-core = { workspace = true }
1919
libp2p-swarm = { workspace = true }
2020
log = "0.4.19"
2121
void = "1.0.2"
22+
tokio = { version = "1.29", default-features = false, features = ["rt", "rt-multi-thread"], optional = true }
23+
async-std = { version = "1.12.0"}
2224

2325
[features]
24-
tokio = ["dep:igd"]
26+
tokio = ["dep:igd", "dep:tokio"]
2527
async-std = ["dep:igd_async_std"]
2628

protocols/upnp/src/behaviour.rs

+71-26
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
use std::{
2424
borrow::Borrow,
2525
collections::HashMap,
26-
error::Error,
2726
hash::{Hash, Hasher},
2827
net::{Ipv4Addr, SocketAddrV4},
2928
pin::Pin,
@@ -36,7 +35,13 @@ use crate::{
3635
gateway::{Gateway, Protocol},
3736
Config,
3837
};
39-
use futures::{future::BoxFuture, stream::FuturesUnordered, Future, FutureExt, StreamExt};
38+
use futures::{
39+
channel::mpsc::{self, Receiver, UnboundedSender},
40+
future::BoxFuture,
41+
select,
42+
stream::FuturesUnordered,
43+
Future, FutureExt, SinkExt, StreamExt,
44+
};
4045
use futures_timer::Delay;
4146
use libp2p_core::{multiaddr, transport::ListenerId, Endpoint, Multiaddr};
4247
use libp2p_swarm::{
@@ -85,11 +90,11 @@ enum Event {
8590
/// Port was successfully mapped.
8691
Mapped(Mapping),
8792
/// There was a failure mapping port.
88-
MapFailure(Mapping, Box<dyn Error>),
93+
MapFailure(Mapping, String),
8994
/// Port was successfully removed.
9095
Removed(Mapping),
9196
/// There was a failure removing the mapping port.
92-
RemovalFailure(Mapping, Box<dyn Error>),
97+
RemovalFailure(Mapping, String),
9398
}
9499

95100
/// Mapping of a Protocol and Port on the gateway.
@@ -155,7 +160,10 @@ where
155160
mappings: HashMap<Mapping, MappingState>,
156161

157162
/// Pending gateway events.
158-
pending_events: FuturesUnordered<BoxFuture<'static, Event>>,
163+
events_queue: Receiver<Event>,
164+
165+
/// Events sender.
166+
events_sender: UnboundedSender<BoxFuture<'static, Event>>,
159167
}
160168

161169
impl<P> Default for Behaviour<P>
@@ -173,11 +181,29 @@ where
173181
{
174182
/// Builds a new `UPnP` behaviour.
175183
pub fn new(config: Config) -> Self {
184+
let (events_sender, mut task_receiver) = mpsc::unbounded();
185+
let (mut task_sender, events_queue) = mpsc::channel(0);
186+
P::spawn(async move {
187+
let mut futs = FuturesUnordered::new();
188+
loop {
189+
select! {
190+
fut = task_receiver.select_next_some() => {
191+
futs.push(fut);
192+
},
193+
event = futs.select_next_some() => {
194+
task_sender.send(event).await.expect("receiver should be available");
195+
}
196+
complete => break,
197+
}
198+
}
199+
});
200+
176201
Self {
177202
config,
178203
state: GatewayState::Searching(P::search(config).boxed()),
179204
mappings: Default::default(),
180-
pending_events: Default::default(),
205+
events_queue,
206+
events_sender,
181207
}
182208
}
183209
}
@@ -255,10 +281,16 @@ where
255281
multiaddr: multiaddr.clone(),
256282
};
257283

258-
self.pending_events.push(
259-
map_port::<P>(gateway.clone(), mapping.clone(), self.config.permanent)
284+
self.events_sender
285+
.unbounded_send(
286+
map_port::<P>(
287+
gateway.clone(),
288+
mapping.clone(),
289+
self.config.permanent,
290+
)
260291
.boxed(),
261-
);
292+
)
293+
.expect("receiver should be available");
262294

263295
self.mappings.insert(mapping, MappingState::Pending);
264296
}
@@ -275,9 +307,11 @@ where
275307
}) => {
276308
if let GatewayState::Available((gateway, _external_addr)) = &self.state {
277309
if let Some((mapping, _state)) = self.mappings.remove_entry(&listener_id) {
278-
self.pending_events.push(
279-
remove_port_mapping::<P>(gateway.clone(), mapping.clone()).boxed(),
280-
);
310+
self.events_sender
311+
.unbounded_send(
312+
remove_port_mapping::<P>(gateway.clone(), mapping.clone()).boxed(),
313+
)
314+
.expect("receiver should be available");
281315
self.mappings.insert(mapping, MappingState::Pending);
282316
}
283317
}
@@ -328,7 +362,7 @@ where
328362
},
329363
GatewayState::Available((ref gateway, external_addr)) => {
330364
// Check pending mappings.
331-
if let Poll::Ready(Some(result)) = self.pending_events.poll_next_unpin(cx) {
365+
if let Poll::Ready(Some(result)) = self.events_queue.poll_next_unpin(cx) {
332366
match result {
333367
Event::Mapped(mapping) => {
334368
let state = self
@@ -430,9 +464,12 @@ where
430464
mapping.internal_addr,
431465
mapping.protocol
432466
);
433-
self.pending_events.push(
434-
remove_port_mapping::<P>(gateway.clone(), mapping).boxed(),
435-
);
467+
self.events_sender
468+
.unbounded_send(
469+
remove_port_mapping::<P>(gateway.clone(), mapping.clone())
470+
.boxed(),
471+
)
472+
.expect("receiver should be available");
436473
}
437474
}
438475
}
@@ -441,22 +478,30 @@ where
441478
for (mapping, state) in self.mappings.iter_mut() {
442479
match state {
443480
MappingState::Inactive => {
444-
self.pending_events.push(
445-
map_port::<P>(
446-
gateway.clone(),
447-
mapping.clone(),
448-
self.config.permanent,
481+
self.events_sender
482+
.unbounded_send(
483+
map_port::<P>(
484+
gateway.clone(),
485+
mapping.clone(),
486+
self.config.permanent,
487+
)
488+
.boxed(),
449489
)
450-
.boxed(),
451-
);
490+
.expect("receiver should be available");
452491
*state = MappingState::Pending;
453492
}
454493
MappingState::Active(timeout) => {
455494
if Pin::new(timeout).poll(cx).is_ready() {
456-
self.pending_events.push(
457-
map_port::<P>(gateway.clone(), mapping.clone(), false)
495+
self.events_sender
496+
.unbounded_send(
497+
map_port::<P>(
498+
gateway.clone(),
499+
mapping.clone(),
500+
self.config.permanent,
501+
)
458502
.boxed(),
459-
);
503+
)
504+
.expect("receiver should be available");
460505
}
461506
}
462507
MappingState::Pending | MappingState::Permanent => {}

protocols/upnp/src/gateway.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use std::{
2828

2929
use crate::Config;
3030
use async_trait::async_trait;
31+
use futures::Future;
3132

3233
#[cfg(feature = "async-std")]
3334
pub mod async_std;
@@ -63,9 +64,14 @@ pub trait Gateway: Sized + Send + Sync {
6364
protocol: Protocol,
6465
addr: SocketAddrV4,
6566
duration: Duration,
66-
) -> Result<(), Box<dyn Error>>;
67+
) -> Result<(), String>;
6768

6869
/// Remove port mapping on the gateway.
69-
async fn remove_port(_: Arc<Self>, protocol: Protocol, port: u16)
70-
-> Result<(), Box<dyn Error>>;
70+
async fn remove_port(_: Arc<Self>, protocol: Protocol, port: u16) -> Result<(), String>;
71+
72+
// /// Spawn a future on the executor.
73+
fn spawn<F>(f: F)
74+
where
75+
F: Future + Send + 'static,
76+
F::Output: Send + 'static;
7177
}

protocols/upnp/src/gateway/async_std.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use super::Protocol;
2929
use crate::Config;
3030

3131
use async_trait::async_trait;
32+
use futures::Future;
3233
use igd_async_std::{
3334
aio::{self, Gateway},
3435
PortMappingProtocol, SearchOptions,
@@ -52,7 +53,7 @@ impl super::Gateway for Gateway {
5253
protocol: Protocol,
5354
addr: SocketAddrV4,
5455
duration: Duration,
55-
) -> Result<(), Box<dyn Error>> {
56+
) -> Result<(), String> {
5657
let protocol = match protocol {
5758
Protocol::Tcp => PortMappingProtocol::TCP,
5859
Protocol::Udp => PortMappingProtocol::UDP,
@@ -66,22 +67,25 @@ impl super::Gateway for Gateway {
6667
"rust-libp2p mapping",
6768
)
6869
.await
69-
.map_err(|err| err.into())
70+
.map_err(|err| err.to_string())
7071
}
7172

72-
async fn remove_port(
73-
gateway: Arc<Self>,
74-
protocol: Protocol,
75-
port: u16,
76-
) -> Result<(), Box<dyn Error>> {
73+
async fn remove_port(gateway: Arc<Self>, protocol: Protocol, port: u16) -> Result<(), String> {
7774
let protocol = match protocol {
7875
Protocol::Tcp => PortMappingProtocol::TCP,
7976
Protocol::Udp => PortMappingProtocol::UDP,
8077
};
8178
gateway
8279
.remove_port(protocol, port)
8380
.await
84-
.map_err(|err| err.into())
81+
.map_err(|err| err.to_string())
82+
}
83+
fn spawn<F>(f: F)
84+
where
85+
F: Future + Send + 'static,
86+
F::Output: Send + 'static,
87+
{
88+
async_std::task::spawn(f);
8589
}
8690
}
8791

protocols/upnp/src/gateway/tokio.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use super::Protocol;
2929
use crate::Config;
3030

3131
use async_trait::async_trait;
32+
use futures::Future;
3233
use igd::{
3334
aio::{self, Gateway},
3435
PortMappingProtocol, SearchOptions,
@@ -52,7 +53,7 @@ impl super::Gateway for Gateway {
5253
protocol: Protocol,
5354
addr: SocketAddrV4,
5455
duration: Duration,
55-
) -> Result<(), Box<dyn Error>> {
56+
) -> Result<(), String> {
5657
let protocol = match protocol {
5758
Protocol::Tcp => PortMappingProtocol::TCP,
5859
Protocol::Udp => PortMappingProtocol::UDP,
@@ -66,22 +67,26 @@ impl super::Gateway for Gateway {
6667
"rust-libp2p mapping",
6768
)
6869
.await
69-
.map_err(|err| err.into())
70+
.map_err(|err| err.to_string())
7071
}
7172

72-
async fn remove_port(
73-
gateway: Arc<Self>,
74-
protocol: Protocol,
75-
port: u16,
76-
) -> Result<(), Box<dyn Error>> {
73+
async fn remove_port(gateway: Arc<Self>, protocol: Protocol, port: u16) -> Result<(), String> {
7774
let protocol = match protocol {
7875
Protocol::Tcp => PortMappingProtocol::TCP,
7976
Protocol::Udp => PortMappingProtocol::UDP,
8077
};
8178
gateway
8279
.remove_port(protocol, port)
8380
.await
84-
.map_err(|err| err.into())
81+
.map_err(|err| err.to_string())
82+
}
83+
84+
fn spawn<F>(f: F)
85+
where
86+
F: Future + Send + 'static,
87+
F::Output: Send + 'static,
88+
{
89+
tokio::spawn(f);
8590
}
8691
}
8792

0 commit comments

Comments
 (0)