async-rs / async-rs/async-std

Stream::merge for arbitrary number of Streams?

Open
#693 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
4.1k
Forks
339
PR merge metrics
No merged PRs in 30d

Description

Hey! A while ago I was trying out `async-std` to see if I could write a nice abstraction around a thing that I had implemented in C++ in the past and found super painful: listening on multiple network addresses and handling connections from any of them. This is usually to handle IPv4+IPv6, but listening on a specific set of available IP addresses or listening on multiple ports are not uncommon things either. I love how nice the [`TcpListener::incoming`](https://docs.rs/async-std/1.4.0/async_std/net/struct.TcpListener.html#method.incoming) API works in practice so I was trying to build something that felt the same but accepted multiple addresses. I got something working after a while but I struggled for a bit and figured I'd open an issue here to see if there's a place for an API that would make this easier. [Here's the implementation I ended up with](https://github.com/luser/async-server-test/blob/da51eccc08139014e605e8ecdb54bacd3176a7bb/src/main.rs#L14). It uses an `mpsc::unbounded` under the hood, spawns a task for each individual `TcpListener` and has them send their streams of `Result` over the channel for the caller to handle.

This certainly works, but I can't help but wonder if it could be nicer if we had an API like `Stream::merge` that supported an arbitrary number of `Stream`s. Something like `stream::from_iter(...).flatten()` but yielding the first available item from any stream would make this fairly trivial to write, something like:

```rust
async fn accept_on_addrs(addrs: impl ToSocketAddrs) -> Result> {
let addrs = addrs.to_socket_addrs().await?;
Ok(stream::merge_from(stream::from_iter(addrs)
.then(|addr| async move {
let listener = TcpListener::bind(addr).await?;
listener.incoming()
})))
}
```

Contributor guide

Open the contributing guide

Research direction

Start by reading the existing Stream and TcpListener::incoming APIs, then compare the linked async-server-test implementation and its mpsc::unbounded approach. Determine where an arbitrary-stream merge API would fit and define completion around supporting the multi-listener use case described in the issue without requiring each caller to build its own channel and tasks.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.