7 releases
0.2.1 | Jun 17, 2020 |
---|---|
0.2.0 | Jan 19, 2020 |
0.1.5 | Jan 14, 2020 |
#2 in #accept
3,305 downloads per month
Used in vented
59KB
813 lines
Async Listen
The crate contains various helpers for writing production-ready servers in rust using async-std.
Features:
- Processing of errors in accept loop
- Limiting number of incomming connections
License
Licensed under either of
- Apache License, Version 2.0, (./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (./LICENSE-MIT or http://opensource.org/licenses/MIT) at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
lib.rs
:
Async Listen
The crate contains various helpers for writing production-ready servers in rust using async-std.
Utilities
- ListenExt -- extension trait for stream of accepted sockets, provides useful conbinators for a stream
- error_hint -- shows end-user hints no how to fix the most imporant errors
Low-Level Utilities
- is_transient_error -- determines if the
error returned from
accept()
can be ignored
Example
Here is a quite elaborate example that demonstrates:
- Backpressure (limit on the number of simultaneous connections)
- Error handling
- Unification of Tcp and Unix sockets
use std::env::args;
use std::error::Error;
use std::fs::remove_file;
use std::io;
use std::time::Duration;
use async_std::task;
use async_std::net::TcpListener;
use async_std::prelude::*;
use async_listen::{ListenExt, ByteStream, backpressure, error_hint};
fn main() -> Result<(), Box<dyn Error>> {
let (_, bp) = backpressure::new(10);
#[cfg(unix)] {
use async_std::os::unix::net::UnixListener;
if args().any(|x| x == "--unix") {
remove_file("./example.sock").ok();
return task::block_on(async {
let listener = UnixListener::bind("./example.sock").await?;
eprintln!("Accepting connections on ./example.sock");
let mut incoming = listener.incoming()
.log_warnings(log_accept_error)
.handle_errors(Duration::from_millis(500))
.backpressure_wrapper(bp);
while let Some(stream) = incoming.next().await {
task::spawn(connection_loop(stream));
}
Ok(())
});
}
}
task::block_on(async {
let listener = TcpListener::bind("localhost:8080").await?;
eprintln!("Accepting connections on localhost:8080");
let mut incoming = listener.incoming()
.log_warnings(log_accept_error)
.handle_errors(Duration::from_millis(500))
.backpressure_wrapper(bp);
while let Some(stream) = incoming.next().await {
task::spawn(async {
if let Err(e) = connection_loop(stream).await {
eprintln!("Error: {}", e);
}
});
}
Ok(())
})
}
async fn connection_loop(mut stream: ByteStream) -> Result<(), io::Error> {
println!("Connected from {}", stream.peer_addr()?);
task::sleep(Duration::from_secs(5)).await;
stream.write_all("hello\n".as_bytes()).await?;
Ok(())
}
fn log_accept_error(e: &io::Error) {
eprintln!("Accept error: {}. Sleeping 0.5s. {}", e, error_hint(&e));
}
Dependencies
~4–13MB
~164K SLoC