1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
//! # Async Listen
//!
//! The crate contains various helpers for writing production-ready servers in
//! rust using [async-std](https://async.rs/).
//!
//! [Docs](https://docs.rs/async-listen/) |
//! [Github](https://github.com/tailhook/async-listen/) |
//! [Crate](https://crates.io/crates/async-listen)
//!
//! # Utilities
//! * [ListenExt](trait.ListenExt.html) -- extension trait for stream of
//!   accepted sockets, provides useful conbinators for a stream
//! * [error_hint](fn.error_hint.html) -- shows end-user hints no how to fix
//!   [the most imporant errors](errors/index.html)
//!
//! # Low-Level Utilities
//!
//! * [is_transient_error](fn.is_transient_error.html) -- 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
//!
//! ```no_run
//! 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));
//! }
//! ```
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![forbid(unsafe_code)]

mod error;
mod listen_ext;
mod log;
mod sleep;
mod byte_stream;
pub mod backpressure;
pub mod wrapper_types;
pub mod errors;

pub use byte_stream::{ByteStream, PeerAddr};
pub use error::{is_transient_error, error_hint};
pub use listen_ext::ListenExt;