mirror of https://github.com/fafhrd91/actix-net
Merge branch 'master' into master
This commit is contained in:
commit
3c3c946556
|
@ -13,7 +13,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
version:
|
version:
|
||||||
- 1.39.0
|
- 1.42.0
|
||||||
- stable
|
- stable
|
||||||
- nightly
|
- nightly
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install ${{ matrix.version }}
|
- name: Install ${{ matrix.version }}
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
@ -65,7 +65,7 @@ jobs:
|
||||||
- name: Generate coverage file
|
- name: Generate coverage file
|
||||||
if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
|
if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
|
||||||
run: |
|
run: |
|
||||||
which cargo-tarpaulin || cargo install cargo-tarpaulin
|
cargo install cargo-tarpaulin
|
||||||
cargo tarpaulin --out Xml --workspace --all-features
|
cargo tarpaulin --out Xml --workspace --all-features
|
||||||
|
|
||||||
- name: Upload to Codecov
|
- name: Upload to Codecov
|
||||||
|
@ -76,5 +76,7 @@ jobs:
|
||||||
|
|
||||||
- name: Clear the cargo caches
|
- name: Clear the cargo caches
|
||||||
run: |
|
run: |
|
||||||
which cargo-cache || cargo install cargo-cache --no-default-features --features ci-autoclean
|
rustup update stable
|
||||||
|
rustup override set stable
|
||||||
|
cargo install cargo-cache --no-default-features --features ci-autoclean
|
||||||
cargo-cache
|
cargo-cache
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install ${{ matrix.version }}
|
- name: Install ${{ matrix.version }}
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install ${{ matrix.version }}
|
- name: Install ${{ matrix.version }}
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
@ -31,12 +31,12 @@ jobs:
|
||||||
override: true
|
override: true
|
||||||
|
|
||||||
- name: Install MSYS2
|
- name: Install MSYS2
|
||||||
uses: numworks/setup-msys2@v1
|
uses: msys2/setup-msys2@v2
|
||||||
|
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: |
|
run: |
|
||||||
msys2do pacman -Sy --noconfirm pacman
|
msys2 -c 'pacman -Sy --noconfirm pacman'
|
||||||
msys2do pacman --noconfirm -S base-devel pkg-config
|
msys2 -c 'pacman --noconfirm -S base-devel pkg-config'
|
||||||
|
|
||||||
- name: check build
|
- name: check build
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install ${{ matrix.version }}
|
- name: Install ${{ matrix.version }}
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
|
|
@ -13,8 +13,8 @@ Actix net - framework for composable network services
|
||||||
|
|
||||||
## Documentation & community resources
|
## Documentation & community resources
|
||||||
|
|
||||||
* [Chat on gitter](https://gitter.im/actix/actix)
|
* [Chat on Gitter](https://gitter.im/actix/actix)
|
||||||
* Minimum supported Rust version: 1.39 or later
|
* Minimum supported Rust version: 1.42 or later
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2020-xx-xx
|
## Unreleased - 2020-xx-xx
|
||||||
|
|
||||||
|
## 0.3.0 - 2020-08-23
|
||||||
|
* No changes from beta 2.
|
||||||
|
|
||||||
|
## 0.3.0-beta.2 - 2020-08-19
|
||||||
|
* Remove unused type parameter from `Framed::replace_codec`.
|
||||||
|
|
||||||
|
## 0.3.0-beta.1 - 2020-08-19
|
||||||
* Use `.advance()` instead of `.split_to()`.
|
* Use `.advance()` instead of `.split_to()`.
|
||||||
* Upgrade `tokio-util` to `0.3`.
|
* Upgrade `tokio-util` to `0.3`.
|
||||||
* Improve `BytesCodec` `.encode()` performance
|
* Improve `BytesCodec` `.encode()` performance
|
||||||
* Simplify `BytesCodec` `.decode()`
|
* Simplify `BytesCodec` `.decode()`
|
||||||
|
* Rename methods on `Framed` to better describe their use.
|
||||||
|
* Add method on `Framed` to get a pinned reference to the underlying I/O.
|
||||||
|
* Add method on `Framed` check emptiness of read buffer.
|
||||||
|
|
||||||
## [0.2.0] - 2019-12-10
|
## [0.2.0] - 2019-12-10
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "actix-codec"
|
name = "actix-codec"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Utilities for encoding and decoding frames"
|
description = "Codec utilities for working with framed protocols."
|
||||||
keywords = ["network", "framework", "async", "futures"]
|
keywords = ["network", "framework", "async", "futures"]
|
||||||
homepage = "https://actix.rs"
|
homepage = "https://actix.rs"
|
||||||
repository = "https://github.com/actix/actix-net.git"
|
repository = "https://github.com/actix/actix-net.git"
|
||||||
|
@ -10,7 +10,6 @@ documentation = "https://docs.rs/actix-codec/"
|
||||||
categories = ["network-programming", "asynchronous"]
|
categories = ["network-programming", "asynchronous"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
workspace = ".."
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "actix_codec"
|
name = "actix_codec"
|
||||||
|
@ -21,7 +20,7 @@ bitflags = "1.2.1"
|
||||||
bytes = "0.5.2"
|
bytes = "0.5.2"
|
||||||
futures-core = { version = "0.3.4", default-features = false }
|
futures-core = { version = "0.3.4", default-features = false }
|
||||||
futures-sink = { version = "0.3.4", default-features = false }
|
futures-sink = { version = "0.3.4", default-features = false }
|
||||||
tokio = { version = "0.2.5", default-features = false }
|
|
||||||
tokio-util = { version = "0.3.1", default-features = false, features = ["codec"] }
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pin-project = "0.4.17"
|
pin-project = "0.4.17"
|
||||||
|
tokio = { version = "0.2.5", default-features = false }
|
||||||
|
tokio-util = { version = "0.3.1", default-features = false, features = ["codec"] }
|
||||||
|
|
|
@ -23,6 +23,12 @@ bitflags::bitflags! {
|
||||||
|
|
||||||
/// A unified `Stream` and `Sink` interface to an underlying I/O object, using
|
/// A unified `Stream` and `Sink` interface to an underlying I/O object, using
|
||||||
/// the `Encoder` and `Decoder` traits to encode and decode frames.
|
/// the `Encoder` and `Decoder` traits to encode and decode frames.
|
||||||
|
///
|
||||||
|
/// Raw I/O objects work with byte sequences, but higher-level code usually
|
||||||
|
/// wants to batch these into meaningful chunks, called "frames". This
|
||||||
|
/// method layers framing on top of an I/O object, by using the `Encoder`/`Decoder`
|
||||||
|
/// traits to handle encoding and decoding of message frames. Note that
|
||||||
|
/// the incoming and outgoing frame types may be distinct.
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
pub struct Framed<T, U> {
|
pub struct Framed<T, U> {
|
||||||
#[pin]
|
#[pin]
|
||||||
|
@ -38,15 +44,6 @@ where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
U: Decoder,
|
U: Decoder,
|
||||||
{
|
{
|
||||||
/// Provides a `Stream` and `Sink` interface for reading and writing to this
|
|
||||||
/// `Io` object, using `Decode` and `Encode` to read and write the raw data.
|
|
||||||
///
|
|
||||||
/// Raw I/O objects work with byte sequences, but higher-level code usually
|
|
||||||
/// wants to batch these into meaningful chunks, called "frames". This
|
|
||||||
/// method layers framing on top of an I/O object, by using the `Codec`
|
|
||||||
/// traits to handle encoding and decoding of messages frames. Note that
|
|
||||||
/// the incoming and outgoing frame types may be distinct.
|
|
||||||
///
|
|
||||||
/// This function returns a *single* object that is both `Stream` and
|
/// This function returns a *single* object that is both `Stream` and
|
||||||
/// `Sink`; grouping this into a single object is often useful for layering
|
/// `Sink`; grouping this into a single object is often useful for layering
|
||||||
/// things like gzip or TLS, which require both read and write access to the
|
/// things like gzip or TLS, which require both read and write access to the
|
||||||
|
@ -63,40 +60,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Framed<T, U> {
|
impl<T, U> Framed<T, U> {
|
||||||
/// Provides a `Stream` and `Sink` interface for reading and writing to this
|
|
||||||
/// `Io` object, using `Decode` and `Encode` to read and write the raw data.
|
|
||||||
///
|
|
||||||
/// Raw I/O objects work with byte sequences, but higher-level code usually
|
|
||||||
/// wants to batch these into meaningful chunks, called "frames". This
|
|
||||||
/// method layers framing on top of an I/O object, by using the `Codec`
|
|
||||||
/// traits to handle encoding and decoding of messages frames. Note that
|
|
||||||
/// the incoming and outgoing frame types may be distinct.
|
|
||||||
///
|
|
||||||
/// This function returns a *single* object that is both `Stream` and
|
|
||||||
/// `Sink`; grouping this into a single object is often useful for layering
|
|
||||||
/// things like gzip or TLS, which require both read and write access to the
|
|
||||||
/// underlying object.
|
|
||||||
///
|
|
||||||
/// This objects takes a stream and a readbuffer and a writebuffer. These
|
|
||||||
/// field can be obtained from an existing `Framed` with the
|
|
||||||
/// `into_parts` method.
|
|
||||||
pub fn from_parts(parts: FramedParts<T, U>) -> Framed<T, U> {
|
|
||||||
Framed {
|
|
||||||
io: parts.io,
|
|
||||||
codec: parts.codec,
|
|
||||||
flags: parts.flags,
|
|
||||||
write_buf: parts.write_buf,
|
|
||||||
read_buf: parts.read_buf,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to the underlying codec.
|
/// Returns a reference to the underlying codec.
|
||||||
pub fn get_codec(&self) -> &U {
|
pub fn codec_ref(&self) -> &U {
|
||||||
&self.codec
|
&self.codec
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the underlying codec.
|
/// Returns a mutable reference to the underlying codec.
|
||||||
pub fn get_codec_mut(&mut self) -> &mut U {
|
pub fn codec_mut(&mut self) -> &mut U {
|
||||||
&mut self.codec
|
&mut self.codec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,20 +76,29 @@ impl<T, U> Framed<T, U> {
|
||||||
/// Note that care should be taken to not tamper with the underlying stream
|
/// Note that care should be taken to not tamper with the underlying stream
|
||||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||||
/// being worked with.
|
/// being worked with.
|
||||||
pub fn get_ref(&self) -> &T {
|
pub fn io_ref(&self) -> &T {
|
||||||
&self.io
|
&self.io
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the underlying I/O stream wrapped by
|
/// Returns a mutable reference to the underlying I/O stream.
|
||||||
/// `Frame`.
|
|
||||||
///
|
///
|
||||||
/// Note that care should be taken to not tamper with the underlying stream
|
/// Note that care should be taken to not tamper with the underlying stream
|
||||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||||
/// being worked with.
|
/// being worked with.
|
||||||
pub fn get_mut(&mut self) -> &mut T {
|
pub fn io_mut(&mut self) -> &mut T {
|
||||||
&mut self.io
|
&mut self.io
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a `Pin` of a mutable reference to the underlying I/O stream.
|
||||||
|
pub fn io_pin(self: Pin<&mut Self>) -> Pin<&mut T> {
|
||||||
|
self.project().io
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if read buffer is empty.
|
||||||
|
pub fn is_read_buf_empty(&self) -> bool {
|
||||||
|
self.read_buf.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if write buffer is empty.
|
/// Check if write buffer is empty.
|
||||||
pub fn is_write_buf_empty(&self) -> bool {
|
pub fn is_write_buf_empty(&self) -> bool {
|
||||||
self.write_buf.is_empty()
|
self.write_buf.is_empty()
|
||||||
|
@ -130,8 +109,15 @@ impl<T, U> Framed<T, U> {
|
||||||
self.write_buf.len() >= HW
|
self.write_buf.len() >= HW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if framed is able to write more data.
|
||||||
|
///
|
||||||
|
/// `Framed` object considers ready if there is free space in write buffer.
|
||||||
|
pub fn is_write_ready(&self) -> bool {
|
||||||
|
self.write_buf.len() < HW
|
||||||
|
}
|
||||||
|
|
||||||
/// Consume the `Frame`, returning `Frame` with different codec.
|
/// Consume the `Frame`, returning `Frame` with different codec.
|
||||||
pub fn into_framed<U2, I2>(self, codec: U2) -> Framed<T, U2> {
|
pub fn replace_codec<U2>(self, codec: U2) -> Framed<T, U2> {
|
||||||
Framed {
|
Framed {
|
||||||
codec,
|
codec,
|
||||||
io: self.io,
|
io: self.io,
|
||||||
|
@ -142,7 +128,7 @@ impl<T, U> Framed<T, U> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume the `Frame`, returning `Frame` with different io.
|
/// Consume the `Frame`, returning `Frame` with different io.
|
||||||
pub fn map_io<F, T2, I2>(self, f: F) -> Framed<T2, U>
|
pub fn into_map_io<F, T2>(self, f: F) -> Framed<T2, U>
|
||||||
where
|
where
|
||||||
F: Fn(T) -> T2,
|
F: Fn(T) -> T2,
|
||||||
{
|
{
|
||||||
|
@ -156,7 +142,7 @@ impl<T, U> Framed<T, U> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume the `Frame`, returning `Frame` with different codec.
|
/// Consume the `Frame`, returning `Frame` with different codec.
|
||||||
pub fn map_codec<F, U2, I2>(self, f: F) -> Framed<T, U2>
|
pub fn into_map_codec<F, U2>(self, f: F) -> Framed<T, U2>
|
||||||
where
|
where
|
||||||
F: Fn(U) -> U2,
|
F: Fn(U) -> U2,
|
||||||
{
|
{
|
||||||
|
@ -168,22 +154,6 @@ impl<T, U> Framed<T, U> {
|
||||||
write_buf: self.write_buf,
|
write_buf: self.write_buf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the `Frame`, returning its underlying I/O stream, the buffer
|
|
||||||
/// with unprocessed data, and the codec.
|
|
||||||
///
|
|
||||||
/// Note that care should be taken to not tamper with the underlying stream
|
|
||||||
/// of data coming in as it may corrupt the stream of frames otherwise
|
|
||||||
/// being worked with.
|
|
||||||
pub fn into_parts(self) -> FramedParts<T, U> {
|
|
||||||
FramedParts {
|
|
||||||
io: self.io,
|
|
||||||
codec: self.codec,
|
|
||||||
flags: self.flags,
|
|
||||||
read_buf: self.read_buf,
|
|
||||||
write_buf: self.write_buf,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Framed<T, U> {
|
impl<T, U> Framed<T, U> {
|
||||||
|
@ -203,13 +173,6 @@ impl<T, U> Framed<T, U> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if framed is able to write more data.
|
|
||||||
///
|
|
||||||
/// `Framed` object considers ready if there is free space in write buffer.
|
|
||||||
pub fn is_write_ready(&self) -> bool {
|
|
||||||
self.write_buf.len() < HW
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to read underlying I/O stream and decode item.
|
/// Try to read underlying I/O stream and decode item.
|
||||||
pub fn next_item(
|
pub fn next_item(
|
||||||
mut self: Pin<&mut Self>,
|
mut self: Pin<&mut Self>,
|
||||||
|
@ -376,6 +339,41 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T, U> Framed<T, U> {
|
||||||
|
/// This function returns a *single* object that is both `Stream` and
|
||||||
|
/// `Sink`; grouping this into a single object is often useful for layering
|
||||||
|
/// things like gzip or TLS, which require both read and write access to the
|
||||||
|
/// underlying object.
|
||||||
|
///
|
||||||
|
/// These objects take a stream, a read buffer and a write buffer. These
|
||||||
|
/// fields can be obtained from an existing `Framed` with the `into_parts` method.
|
||||||
|
pub fn from_parts(parts: FramedParts<T, U>) -> Framed<T, U> {
|
||||||
|
Framed {
|
||||||
|
io: parts.io,
|
||||||
|
codec: parts.codec,
|
||||||
|
flags: parts.flags,
|
||||||
|
write_buf: parts.write_buf,
|
||||||
|
read_buf: parts.read_buf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes the `Frame`, returning its underlying I/O stream, the buffer
|
||||||
|
/// with unprocessed data, and the codec.
|
||||||
|
///
|
||||||
|
/// Note that care should be taken to not tamper with the underlying stream
|
||||||
|
/// of data coming in as it may corrupt the stream of frames otherwise
|
||||||
|
/// being worked with.
|
||||||
|
pub fn into_parts(self) -> FramedParts<T, U> {
|
||||||
|
FramedParts {
|
||||||
|
io: self.io,
|
||||||
|
codec: self.codec,
|
||||||
|
flags: self.flags,
|
||||||
|
read_buf: self.read_buf,
|
||||||
|
write_buf: self.write_buf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `FramedParts` contains an export of the data of a Framed transport.
|
/// `FramedParts` contains an export of the data of a Framed transport.
|
||||||
/// It can be used to construct a new `Framed` with a different codec.
|
/// It can be used to construct a new `Framed` with a different codec.
|
||||||
/// It contains all current buffers and the inner transport.
|
/// It contains all current buffers and the inner transport.
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
//! [`AsyncWrite`]: AsyncWrite
|
//! [`AsyncWrite`]: AsyncWrite
|
||||||
//! [`Sink`]: futures_sink::Sink
|
//! [`Sink`]: futures_sink::Sink
|
||||||
//! [`Stream`]: futures_core::Stream
|
//! [`Stream`]: futures_core::Stream
|
||||||
|
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
mod bcodec;
|
mod bcodec;
|
||||||
mod framed;
|
mod framed;
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## [unreleased]
|
## Unreleased
|
||||||
|
|
||||||
|
|
||||||
|
## 2.0.0-alpha.4 - 2020-08-17
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
* Update `rustls` dependency to 0.18
|
* Update `rustls` dependency to 0.18
|
||||||
* Update `tokio-rustls` dependency to 0.14
|
* Update `tokio-rustls` dependency to 0.14
|
||||||
|
|
||||||
|
|
||||||
## [2.0.0-alpha.3] - 2020-05-08
|
## [2.0.0-alpha.3] - 2020-05-08
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "actix-connect"
|
name = "actix-connect"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix connect - tcp connector service"
|
description = "TCP connector service for Actix ecosystem."
|
||||||
keywords = ["network", "framework", "async", "futures"]
|
keywords = ["network", "framework", "async", "futures"]
|
||||||
homepage = "https://actix.rs"
|
homepage = "https://actix.rs"
|
||||||
repository = "https://github.com/actix/actix-net.git"
|
repository = "https://github.com/actix/actix-net.git"
|
||||||
|
@ -31,10 +31,11 @@ rustls = ["rust-tls", "tokio-rustls", "webpki"]
|
||||||
uri = ["http"]
|
uri = ["http"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "1.0.3"
|
actix-service = "1.0.6"
|
||||||
actix-codec = "0.2.0"
|
actix-codec = "0.3.0"
|
||||||
actix-utils = "1.0.6"
|
actix-utils = "2.0.0"
|
||||||
actix-rt = "1.0.0"
|
actix-rt = "1.1.1"
|
||||||
|
|
||||||
derive_more = "0.99.2"
|
derive_more = "0.99.2"
|
||||||
either = "1.5.3"
|
either = "1.5.3"
|
||||||
futures-util = { version = "0.3.4", default-features = false }
|
futures-util = { version = "0.3.4", default-features = false }
|
||||||
|
@ -44,14 +45,14 @@ trust-dns-proto = { version = "0.19", default-features = false, features = ["tok
|
||||||
trust-dns-resolver = { version = "0.19", default-features = false, features = ["tokio-runtime", "system-config"] }
|
trust-dns-resolver = { version = "0.19", default-features = false, features = ["tokio-runtime", "system-config"] }
|
||||||
|
|
||||||
# openssl
|
# openssl
|
||||||
open-ssl = { version="0.10", package = "openssl", optional = true }
|
open-ssl = { package = "openssl", version = "0.10", optional = true }
|
||||||
tokio-openssl = { version = "0.4.0", optional = true }
|
tokio-openssl = { version = "0.4.0", optional = true }
|
||||||
|
|
||||||
# rustls
|
# rustls
|
||||||
rust-tls = { version = "0.18.0", package = "rustls", optional = true }
|
rust-tls = { package = "rustls", version = "0.18.0", optional = true }
|
||||||
tokio-rustls = { version = "0.14.0", optional = true }
|
tokio-rustls = { version = "0.14.0", optional = true }
|
||||||
webpki = { version = "0.21", optional = true }
|
webpki = { version = "0.21", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bytes = "0.5.3"
|
bytes = "0.5.3"
|
||||||
actix-testing = { version="1.0.0" }
|
actix-testing = "1.0.0"
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub struct Connect<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address> Connect<T> {
|
impl<T: Address> Connect<T> {
|
||||||
/// Create `Connect` instance by spliting the string by ':' and convert the second part to u16
|
/// Create `Connect` instance by splitting the string by ':' and convert the second part to u16
|
||||||
pub fn new(req: T) -> Connect<T> {
|
pub fn new(req: T) -> Connect<T> {
|
||||||
let (_, port) = parse(req.host());
|
let (_, port) = parse(req.host());
|
||||||
Connect {
|
Connect {
|
||||||
|
@ -53,7 +53,8 @@ impl<T: Address> Connect<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create new `Connect` instance from host and address. Connector skips name resolution stage for such connect messages.
|
/// Create new `Connect` instance from host and address. Connector skips name resolution stage
|
||||||
|
/// for such connect messages.
|
||||||
pub fn with(req: T, addr: SocketAddr) -> Connect<T> {
|
pub fn with(req: T, addr: SocketAddr) -> Connect<T> {
|
||||||
Connect {
|
Connect {
|
||||||
req,
|
req,
|
||||||
|
@ -102,7 +103,7 @@ impl<T: Address> Connect<T> {
|
||||||
self.req.port().unwrap_or(self.port)
|
self.req.port().unwrap_or(self.port)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Preresolved addresses of the request.
|
/// Pre-resolved addresses of the request.
|
||||||
pub fn addrs(&self) -> ConnectAddrsIter<'_> {
|
pub fn addrs(&self) -> ConnectAddrsIter<'_> {
|
||||||
let inner = match self.addr {
|
let inner = match self.addr {
|
||||||
None => Either::Left(None),
|
None => Either::Left(None),
|
||||||
|
@ -113,7 +114,7 @@ impl<T: Address> Connect<T> {
|
||||||
ConnectAddrsIter { inner }
|
ConnectAddrsIter { inner }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes preresolved addresses of the request.
|
/// Takes pre-resolved addresses of the request.
|
||||||
pub fn take_addrs(&mut self) -> ConnectTakeAddrsIter {
|
pub fn take_addrs(&mut self) -> ConnectTakeAddrsIter {
|
||||||
let inner = match self.addr.take() {
|
let inner = match self.addr.take() {
|
||||||
None => Either::Left(None),
|
None => Either::Left(None),
|
||||||
|
|
|
@ -13,7 +13,7 @@ use futures_util::future::{err, ok, BoxFuture, Either, FutureExt, Ready};
|
||||||
use super::connect::{Address, Connect, Connection};
|
use super::connect::{Address, Connect, Connection};
|
||||||
use super::error::ConnectError;
|
use super::error::ConnectError;
|
||||||
|
|
||||||
/// Tcp connector service factory
|
/// TCP connector service factory
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TcpConnectorFactory<T>(PhantomData<T>);
|
pub struct TcpConnectorFactory<T>(PhantomData<T>);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ impl<T> TcpConnectorFactory<T> {
|
||||||
TcpConnectorFactory(PhantomData)
|
TcpConnectorFactory(PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create tcp connector service
|
/// Create TCP connector service
|
||||||
pub fn service(&self) -> TcpConnector<T> {
|
pub fn service(&self) -> TcpConnector<T> {
|
||||||
TcpConnector(PhantomData)
|
TcpConnector(PhantomData)
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ impl<T: Address> ServiceFactory for TcpConnectorFactory<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tcp connector service
|
/// TCP connector service
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct TcpConnector<T>(PhantomData<T>);
|
pub struct TcpConnector<T>(PhantomData<T>);
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ impl<T: Address> Service for TcpConnector<T> {
|
||||||
type Request = Connect<T>;
|
type Request = Connect<T>;
|
||||||
type Response = Connection<T, TcpStream>;
|
type Response = Connection<T, TcpStream>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
type Future = Either<TcpConnectorResponse<T>, Ready<Result<Self::Response, Self::Error>>>;
|
type Future = Either<TcpConnectorResponse<T>, Ready<Result<Self::Response, Self::Error>>>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
@ -94,7 +95,7 @@ impl<T: Address> Service for TcpConnector<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// Tcp stream connector response future
|
/// TCP stream connector response future
|
||||||
pub struct TcpConnectorResponse<T> {
|
pub struct TcpConnectorResponse<T> {
|
||||||
req: Option<T>,
|
req: Option<T>,
|
||||||
port: u16,
|
port: u16,
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub enum ConnectError {
|
||||||
#[display(fmt = "Connector received `Connect` method with unresolved host")]
|
#[display(fmt = "Connector received `Connect` method with unresolved host")]
|
||||||
Unresolved,
|
Unresolved,
|
||||||
|
|
||||||
/// Connection io error
|
/// Connection IO error
|
||||||
#[display(fmt = "{}", _0)]
|
#[display(fmt = "{}", _0)]
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
//! Actix connect - tcp connector service
|
//! TCP connector service for Actix ecosystem.
|
||||||
//!
|
//!
|
||||||
//! ## Package feature
|
//! ## Package feature
|
||||||
//!
|
//!
|
||||||
//! * `openssl` - enables ssl support via `openssl` crate
|
//! * `openssl` - enables ssl support via `openssl` crate
|
||||||
//! * `rustls` - enables ssl support via `rustls` crate
|
//! * `rustls` - enables ssl support via `rustls` crate
|
||||||
#![deny(rust_2018_idioms, warnings)]
|
|
||||||
#![allow(clippy::type_complexity)]
|
#![deny(rust_2018_idioms)]
|
||||||
#![recursion_limit = "128"]
|
#![recursion_limit = "128"]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -71,7 +71,7 @@ pub async fn start_default_resolver() -> Result<AsyncResolver, ConnectError> {
|
||||||
get_default_resolver().await
|
get_default_resolver().await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create tcp connector service
|
/// Create TCP connector service.
|
||||||
pub fn new_connector<T: Address + 'static>(
|
pub fn new_connector<T: Address + 'static>(
|
||||||
resolver: AsyncResolver,
|
resolver: AsyncResolver,
|
||||||
) -> impl Service<Request = Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
|
) -> impl Service<Request = Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
|
||||||
|
@ -79,7 +79,7 @@ pub fn new_connector<T: Address + 'static>(
|
||||||
pipeline(Resolver::new(resolver)).and_then(TcpConnector::new())
|
pipeline(Resolver::new(resolver)).and_then(TcpConnector::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create tcp connector service
|
/// Create TCP connector service factory.
|
||||||
pub fn new_connector_factory<T: Address + 'static>(
|
pub fn new_connector_factory<T: Address + 'static>(
|
||||||
resolver: AsyncResolver,
|
resolver: AsyncResolver,
|
||||||
) -> impl ServiceFactory<
|
) -> impl ServiceFactory<
|
||||||
|
@ -92,14 +92,14 @@ pub fn new_connector_factory<T: Address + 'static>(
|
||||||
pipeline_factory(ResolverFactory::new(resolver)).and_then(TcpConnectorFactory::new())
|
pipeline_factory(ResolverFactory::new(resolver)).and_then(TcpConnectorFactory::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create connector service with default parameters
|
/// Create connector service with default parameters.
|
||||||
pub fn default_connector<T: Address + 'static>(
|
pub fn default_connector<T: Address + 'static>(
|
||||||
) -> impl Service<Request = Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
|
) -> impl Service<Request = Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
|
||||||
+ Clone {
|
+ Clone {
|
||||||
pipeline(Resolver::default()).and_then(TcpConnector::new())
|
pipeline(Resolver::default()).and_then(TcpConnector::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create connector service factory with default parameters
|
/// Create connector service factory with default parameters.
|
||||||
pub fn default_connector_factory<T: Address + 'static>() -> impl ServiceFactory<
|
pub fn default_connector_factory<T: Address + 'static>() -> impl ServiceFactory<
|
||||||
Config = (),
|
Config = (),
|
||||||
Request = Connect<T>,
|
Request = Connect<T>,
|
||||||
|
|
|
@ -106,6 +106,7 @@ impl<T: Address> Service for Resolver<T> {
|
||||||
type Request = Connect<T>;
|
type Request = Connect<T>;
|
||||||
type Response = Connect<T>;
|
type Response = Connect<T>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
type Future = Either<
|
type Future = Either<
|
||||||
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>,
|
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>,
|
||||||
Ready<Result<Connect<T>, Self::Error>>,
|
Ready<Result<Connect<T>, Self::Error>>,
|
||||||
|
|
|
@ -114,6 +114,7 @@ enum ConnectState<T: Address> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address> ConnectState<T> {
|
impl<T: Address> ConnectState<T> {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
fn poll(
|
fn poll(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
Address, Connect, ConnectError, ConnectService, ConnectServiceFactory, Connection,
|
Address, Connect, ConnectError, ConnectService, ConnectServiceFactory, Connection,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Openssl connector factory
|
/// OpenSSL connector factory
|
||||||
pub struct OpensslConnector<T, U> {
|
pub struct OpensslConnector<T, U> {
|
||||||
connector: SslConnector,
|
connector: SslConnector,
|
||||||
_t: PhantomData<(T, U)>,
|
_t: PhantomData<(T, U)>,
|
||||||
|
@ -97,6 +97,7 @@ where
|
||||||
type Request = Connection<T, U>;
|
type Request = Connection<T, U>;
|
||||||
type Response = Connection<T, SslStream<U>>;
|
type Response = Connection<T, SslStream<U>>;
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
type Future = Either<ConnectAsyncExt<T, U>, Ready<Result<Self::Response, Self::Error>>>;
|
type Future = Either<ConnectAsyncExt<T, U>, Ready<Result<Self::Response, Self::Error>>>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
@ -164,7 +165,7 @@ impl<T> OpensslConnectServiceFactory<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct new connect service with custom dns resolver
|
/// Construct new connect service with custom DNS resolver
|
||||||
pub fn with_resolver(connector: SslConnector, resolver: AsyncResolver) -> Self {
|
pub fn with_resolver(connector: SslConnector, resolver: AsyncResolver) -> Self {
|
||||||
OpensslConnectServiceFactory {
|
OpensslConnectServiceFactory {
|
||||||
tcp: ConnectServiceFactory::with_resolver(resolver),
|
tcp: ConnectServiceFactory::with_resolver(resolver),
|
||||||
|
@ -172,7 +173,7 @@ impl<T> OpensslConnectServiceFactory<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct openssl connect service
|
/// Construct OpenSSL connect service
|
||||||
pub fn service(&self) -> OpensslConnectService<T> {
|
pub fn service(&self) -> OpensslConnectService<T> {
|
||||||
OpensslConnectService {
|
OpensslConnectService {
|
||||||
tcp: self.tcp.service(),
|
tcp: self.tcp.service(),
|
||||||
|
|
|
@ -88,9 +88,9 @@ async fn test_new_service() {
|
||||||
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "openssl")]
|
#[cfg(all(feature = "openssl", feature = "uri"))]
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_uri() {
|
async fn test_openssl_uri() {
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
let srv = TestServer::with(|| {
|
let srv = TestServer::with(|| {
|
||||||
|
@ -107,7 +107,7 @@ async fn test_uri() {
|
||||||
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(all(feature = "rustls", feature = "uri"))]
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_rustls_uri() {
|
async fn test_rustls_uri() {
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* workers must be greater than 0
|
||||||
|
|
||||||
## [1.0.3] - 2020-05-19
|
## [1.0.3] - 2020-05-19
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -23,8 +23,8 @@ default = []
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "1.0.1"
|
actix-service = "1.0.1"
|
||||||
actix-rt = "1.0.0"
|
actix-rt = "1.0.0"
|
||||||
actix-codec = "0.2.0"
|
actix-codec = "0.3.0"
|
||||||
actix-utils = "1.0.4"
|
actix-utils = "2.0.0"
|
||||||
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
num_cpus = "1.11"
|
num_cpus = "1.11"
|
||||||
|
|
|
@ -72,8 +72,9 @@ impl ServerBuilder {
|
||||||
/// Set number of workers to start.
|
/// Set number of workers to start.
|
||||||
///
|
///
|
||||||
/// By default server uses number of available logical cpu as workers
|
/// By default server uses number of available logical cpu as workers
|
||||||
/// count.
|
/// count. Workers must be greater than 0.
|
||||||
pub fn workers(mut self, num: usize) -> Self {
|
pub fn workers(mut self, num: usize) -> Self {
|
||||||
|
assert_ne!(num, 0, "workers must be greater than 0");
|
||||||
self.threads = num;
|
self.threads = num;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -276,7 +277,7 @@ impl ServerBuilder {
|
||||||
info!("Starting \"{}\" service on {}", sock.1, sock.2);
|
info!("Starting \"{}\" service on {}", sock.1, sock.2);
|
||||||
}
|
}
|
||||||
self.accept.start(
|
self.accept.start(
|
||||||
mem::replace(&mut self.sockets, Vec::new())
|
mem::take(&mut self.sockets)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|t| (t.0, t.2))
|
.map(|t| (t.0, t.2))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -355,7 +356,7 @@ impl ServerBuilder {
|
||||||
|
|
||||||
// stop accept thread
|
// stop accept thread
|
||||||
self.accept.send(Command::Stop);
|
self.accept.send(Command::Stop);
|
||||||
let notify = std::mem::replace(&mut self.notify, Vec::new());
|
let notify = std::mem::take(&mut self.notify);
|
||||||
|
|
||||||
// stop workers
|
// stop workers
|
||||||
if !self.workers.is_empty() && graceful {
|
if !self.workers.is_empty() && graceful {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased - 2020-xx-xx
|
||||||
|
|
||||||
|
|
||||||
|
## 1.0.6 - 2020-08-09
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
[package]
|
[package]
|
||||||
name = "actix-service"
|
name = "actix-service"
|
||||||
version = "1.0.5"
|
version = "1.0.6"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix service"
|
description = "Service trait and combinators for representing asynchronous request/response operations."
|
||||||
keywords = ["network", "framework", "async", "futures"]
|
keywords = ["network", "framework", "async", "futures", "service"]
|
||||||
homepage = "https://actix.rs"
|
homepage = "https://actix.rs"
|
||||||
repository = "https://github.com/actix/actix-net.git"
|
repository = "https://github.com/actix/actix-net.git"
|
||||||
documentation = "https://docs.rs/actix-service/"
|
documentation = "https://docs.rs/actix-service"
|
||||||
|
readme = "README.md"
|
||||||
categories = ["network-programming", "asynchronous"]
|
categories = ["network-programming", "asynchronous"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# actix-service
|
||||||
|
|
||||||
|
> Service trait and combinators for representing asynchronous request/response operations.
|
||||||
|
|
||||||
|
See documentation for detailed explanations these components: [https://docs.rs/actix-service](docs).
|
||||||
|
|
||||||
|
[docs]: https://docs.rs/actix-service
|
|
@ -293,9 +293,8 @@ where
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
// benchmark body
|
// benchmark body
|
||||||
rt.block_on(async move { join_all(srvs.iter_mut().map(|srv| srv.call(()))).await });
|
rt.block_on(async move { join_all(srvs.iter_mut().map(|srv| srv.call(()))).await });
|
||||||
let elapsed = start.elapsed();
|
|
||||||
// check that at least first request succeeded
|
// check that at least first request succeeded
|
||||||
elapsed
|
start.elapsed()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,9 +95,8 @@ where
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
// benchmark body
|
// benchmark body
|
||||||
rt.block_on(async move { join_all(srvs.iter_mut().map(|srv| srv.call(()))).await });
|
rt.block_on(async move { join_all(srvs.iter_mut().map(|srv| srv.call(()))).await });
|
||||||
let elapsed = start.elapsed();
|
|
||||||
// check that at least first request succeeded
|
// check that at least first request succeeded
|
||||||
elapsed
|
start.elapsed()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ where
|
||||||
/// /// Service that divides two usize values.
|
/// /// Service that divides two usize values.
|
||||||
/// async fn div((x, y): (usize, usize)) -> Result<usize, io::Error> {
|
/// async fn div((x, y): (usize, usize)) -> Result<usize, io::Error> {
|
||||||
/// if y == 0 {
|
/// if y == 0 {
|
||||||
/// Err(io::Error::new(io::ErrorKind::Other, "divide by zdro"))
|
/// Err(io::Error::new(io::ErrorKind::Other, "divide by zero"))
|
||||||
/// } else {
|
/// } else {
|
||||||
/// Ok(x / y)
|
/// Ok(x / y)
|
||||||
/// }
|
/// }
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! See [`Service`](trait.Service.html) docs for information on this crate's foundational trait.
|
||||||
|
|
||||||
#![deny(rust_2018_idioms, warnings)]
|
#![deny(rust_2018_idioms, warnings)]
|
||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
|
|
||||||
|
@ -29,21 +31,23 @@ pub use self::map_config::{map_config, unit_config};
|
||||||
pub use self::pipeline::{pipeline, pipeline_factory, Pipeline, PipelineFactory};
|
pub use self::pipeline::{pipeline, pipeline_factory, Pipeline, PipelineFactory};
|
||||||
pub use self::transform::{apply, Transform};
|
pub use self::transform::{apply, Transform};
|
||||||
|
|
||||||
/// An asynchronous function from `Request` to a `Response`.
|
/// An asynchronous operation from `Request` to a `Response`.
|
||||||
///
|
///
|
||||||
/// `Service` represents a service that represanting interation, taking requests and giving back
|
/// The `Service` trait models a request/response interaction, receiving requests and returning
|
||||||
/// replies. You can think about service as a function with one argument and result as a return
|
/// replies. You can think about a service as a function with one argument that returns some result
|
||||||
/// type. In general form it looks like `async fn(Req) -> Result<Res, Err>`. `Service`
|
/// asynchronously. Conceptually, the operation looks like this:
|
||||||
/// trait just generalizing form of this function. Each parameter described as an assotiated type.
|
|
||||||
///
|
///
|
||||||
/// Services provides a symmetric and uniform API, same abstractions represents
|
/// ```rust,ignore
|
||||||
/// clients and servers. Services describe only `transforamtion` operation
|
/// async fn(Request) -> Result<Response, Err>
|
||||||
/// which encorouge to simplify api surface and phrases `value transformation`.
|
/// ```
|
||||||
/// That leads to simplier design of each service. That also allows better testability
|
|
||||||
/// and better composition.
|
|
||||||
///
|
///
|
||||||
/// Services could be represented in several different forms. In general,
|
/// The `Service` trait just generalizes this form where each parameter is described as an
|
||||||
/// Service is a type that implements `Service` trait.
|
/// associated type on the trait. Services can also have mutable state that influence computation.
|
||||||
|
///
|
||||||
|
/// `Service` provides a symmetric and uniform API; the same abstractions can be used to represent
|
||||||
|
/// both clients and servers. Services describe only _transformation_ operations which encourage
|
||||||
|
/// simple API surfaces. This leads to simpler design of each service, improves test-ability and
|
||||||
|
/// makes composition easier.
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// struct MyService;
|
/// struct MyService;
|
||||||
|
@ -52,7 +56,7 @@ pub use self::transform::{apply, Transform};
|
||||||
/// type Request = u8;
|
/// type Request = u8;
|
||||||
/// type Response = u64;
|
/// type Response = u64;
|
||||||
/// type Error = MyError;
|
/// type Error = MyError;
|
||||||
/// type Future = Pin<Box<Future<Output=Result<Self::Response, Self::Error>>>;
|
/// type Future = Pin<Box<Future<Output=Result<Self::Response, Self::Error>>>>;
|
||||||
///
|
///
|
||||||
/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ... }
|
/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ... }
|
||||||
///
|
///
|
||||||
|
@ -60,8 +64,8 @@ pub use self::transform::{apply, Transform};
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Service can have mutable state that influence computation.
|
/// Sometimes it is not necessary to implement the Service trait. For example, the above service
|
||||||
/// This service could be rewritten as a simple function:
|
/// could be rewritten as a simple function and passed to [fn_service](fn.fn_service.html).
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// async fn my_service(req: u8) -> Result<u64, MyError>;
|
/// async fn my_service(req: u8) -> Result<u64, MyError>;
|
||||||
|
@ -89,11 +93,9 @@ pub trait Service {
|
||||||
/// It is permitted for the service to return `Ready` from a `poll_ready`
|
/// It is permitted for the service to return `Ready` from a `poll_ready`
|
||||||
/// call and the next invocation of `call` results in an error.
|
/// call and the next invocation of `call` results in an error.
|
||||||
///
|
///
|
||||||
/// There are several notes to consider:
|
/// # Notes
|
||||||
///
|
|
||||||
/// 1. `.poll_ready()` might be called on different task from actual service call.
|
/// 1. `.poll_ready()` might be called on different task from actual service call.
|
||||||
///
|
/// 1. In case of chained services, `.poll_ready()` get called for all services at once.
|
||||||
/// 2. In case of chained services, `.poll_ready()` get called for all services at once.
|
|
||||||
fn poll_ready(&mut self, ctx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
|
fn poll_ready(&mut self, ctx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
|
||||||
|
|
||||||
/// Process the request and return the response asynchronously.
|
/// Process the request and return the response asynchronously.
|
||||||
|
@ -127,7 +129,7 @@ pub trait Service {
|
||||||
/// Map this service's error to a different error, returning a new service.
|
/// Map this service's error to a different error, returning a new service.
|
||||||
///
|
///
|
||||||
/// This function is similar to the `Result::map_err` where it will change
|
/// This function is similar to the `Result::map_err` where it will change
|
||||||
/// the error type of the underlying service. This is useful for example to
|
/// the error type of the underlying service. For example, this can be useful to
|
||||||
/// ensure that services have the same error type.
|
/// ensure that services have the same error type.
|
||||||
///
|
///
|
||||||
/// Note that this function consumes the receiving service and returns a
|
/// Note that this function consumes the receiving service and returns a
|
||||||
|
@ -141,42 +143,42 @@ pub trait Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new `Service` values.
|
/// Factory for creating `Service`s.
|
||||||
///
|
///
|
||||||
/// Acts as a service factory. This is useful for cases where new `Service`
|
/// Acts as a service factory. This is useful for cases where new `Service`s
|
||||||
/// values must be produced. One case is a TCP server listener. The listener
|
/// must be produced. One case is a TCP server listener. The listener
|
||||||
/// accepts new TCP streams, obtains a new `Service` value using the
|
/// accepts new TCP streams, obtains a new `Service` using the
|
||||||
/// `ServiceFactory` trait, and uses that new `Service` value to process inbound
|
/// `ServiceFactory` trait, and uses the new `Service` to process inbound
|
||||||
/// requests on that new TCP stream.
|
/// requests on that new TCP stream.
|
||||||
///
|
///
|
||||||
/// `Config` is a service factory configuration type.
|
/// `Config` is a service factory configuration type.
|
||||||
pub trait ServiceFactory {
|
pub trait ServiceFactory {
|
||||||
/// Requests handled by the service.
|
/// Requests handled by the created services.
|
||||||
type Request;
|
type Request;
|
||||||
|
|
||||||
/// Responses given by the service
|
/// Responses given by the created services.
|
||||||
type Response;
|
type Response;
|
||||||
|
|
||||||
/// Errors produced by the service
|
/// Errors produced by the created services.
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
/// Service factory configuration
|
/// Service factory configuration.
|
||||||
type Config;
|
type Config;
|
||||||
|
|
||||||
/// The `Service` value created by this factory
|
/// The kind of `Service` created by this factory.
|
||||||
type Service: Service<
|
type Service: Service<
|
||||||
Request = Self::Request,
|
Request = Self::Request,
|
||||||
Response = Self::Response,
|
Response = Self::Response,
|
||||||
Error = Self::Error,
|
Error = Self::Error,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
/// Errors produced while building a service.
|
/// Errors potentially raised while building a service.
|
||||||
type InitError;
|
type InitError;
|
||||||
|
|
||||||
/// The future of the `Service` instance.
|
/// The future of the `Service` instance.
|
||||||
type Future: Future<Output = Result<Self::Service, Self::InitError>>;
|
type Future: Future<Output = Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
/// Create and return a new service value asynchronously.
|
/// Create and return a new service asynchronously.
|
||||||
fn new_service(&self, cfg: Self::Config) -> Self::Future;
|
fn new_service(&self, cfg: Self::Config) -> Self::Future;
|
||||||
|
|
||||||
/// Map this service's output to a different type, returning a new service
|
/// Map this service's output to a different type, returning a new service
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## [unreleased]
|
## Unreleased
|
||||||
|
|
||||||
|
|
||||||
|
## 2.0.0-alpha.2 - 2020-08-17
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -8,6 +11,7 @@
|
||||||
* Update `tokio-rustls` dependency to 0.14
|
* Update `tokio-rustls` dependency to 0.14
|
||||||
* Update `webpki-roots` dependency to 0.20
|
* Update `webpki-roots` dependency to 0.20
|
||||||
|
|
||||||
|
|
||||||
## [2.0.0-alpha.1] - 2020-03-03
|
## [2.0.0-alpha.1] - 2020-03-03
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "actix-tls"
|
name = "actix-tls"
|
||||||
version = "2.0.0-alpha.1"
|
version = "2.0.0-alpha.2"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix tls services"
|
description = "Actix tls services"
|
||||||
keywords = ["network", "framework", "async", "futures"]
|
keywords = ["network", "framework", "async", "futures"]
|
||||||
|
@ -33,8 +33,8 @@ nativetls = ["native-tls", "tokio-tls"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "1.0.0"
|
actix-service = "1.0.0"
|
||||||
actix-codec = "0.2.0"
|
actix-codec = "0.3.0"
|
||||||
actix-utils = "1.0.0"
|
actix-utils = "2.0.0"
|
||||||
actix-rt = "1.0.0"
|
actix-rt = "1.0.0"
|
||||||
derive_more = "0.99.2"
|
derive_more = "0.99.2"
|
||||||
either = "1.5.2"
|
either = "1.5.2"
|
||||||
|
|
|
@ -2,8 +2,13 @@
|
||||||
|
|
||||||
## Unreleased - 2020-xx-xx
|
## Unreleased - 2020-xx-xx
|
||||||
|
|
||||||
|
## 2.0.0 - 2020-08-23
|
||||||
|
* No changes from beta 1.
|
||||||
|
|
||||||
|
## 2.0.0-beta.1 - 2020-08-19
|
||||||
* Upgrade `tokio-util` to `0.3`.
|
* Upgrade `tokio-util` to `0.3`.
|
||||||
* Remove unsound custom Cell and use `std::cell::RefCell` instead, as well as `actix-service`.
|
* Remove unsound custom Cell and use `std::cell::RefCell` instead, as well as `actix-service`.
|
||||||
|
* Rename method to correctly spelled `LocalWaker::is_registered`.
|
||||||
|
|
||||||
## [1.0.6] - 2020-01-08
|
## [1.0.6] - 2020-01-08
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "actix-utils"
|
name = "actix-utils"
|
||||||
version = "1.0.6"
|
version = "2.0.0"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix utils - various actix net related services"
|
description = "Various network related services and utilities for the Actix ecosystem."
|
||||||
keywords = ["network", "framework", "async", "futures"]
|
keywords = ["network", "framework", "async", "futures"]
|
||||||
homepage = "https://actix.rs"
|
homepage = "https://actix.rs"
|
||||||
repository = "https://github.com/actix/actix-net.git"
|
repository = "https://github.com/actix/actix-net.git"
|
||||||
|
@ -16,15 +16,15 @@ name = "actix_utils"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "1.0.1"
|
actix-codec = "0.3.0"
|
||||||
actix-rt = "1.0.0"
|
actix-rt = "1.1.1"
|
||||||
actix-codec = "0.2.0"
|
actix-service = "1.0.6"
|
||||||
bitflags = "1.2"
|
bitflags = "1.2.1"
|
||||||
bytes = "0.5.3"
|
bytes = "0.5.3"
|
||||||
either = "1.5.3"
|
either = "1.5.3"
|
||||||
futures-channel = { version = "0.3.4", default-features = false }
|
futures-channel = { version = "0.3.4", default-features = false }
|
||||||
futures-sink = { version = "0.3.4", default-features = false }
|
futures-sink = { version = "0.3.4", default-features = false }
|
||||||
futures-util = { version = "0.3.4", default-features = false }
|
futures-util = { version = "0.3.4", default-features = false }
|
||||||
pin-project = "0.4.17"
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
pin-project = "0.4.17"
|
||||||
slab = "0.4"
|
slab = "0.4"
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::task::LocalWaker;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
/// Simple counter with ability to notify task on reaching specific number
|
/// Simple counter with ability to notify task on reaching specific number
|
||||||
///
|
///
|
||||||
/// Counter could be cloned, total ncount is shared across all clones.
|
/// Counter could be cloned, total n-count is shared across all clones.
|
||||||
pub struct Counter(Rc<CounterInner>);
|
pub struct Counter(Rc<CounterInner>);
|
||||||
|
|
||||||
struct CounterInner {
|
struct CounterInner {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
//! Framed dispatcher service and related utilities
|
//! Framed dispatcher service and related utilities
|
||||||
|
|
||||||
#![allow(type_alias_bounds)]
|
#![allow(type_alias_bounds)]
|
||||||
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use std::{fmt, mem};
|
use std::{fmt, mem};
|
|
@ -152,7 +152,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_newtransform() {
|
async fn test_new_transform() {
|
||||||
let wait_time = Duration::from_millis(50);
|
let wait_time = Duration::from_millis(50);
|
||||||
|
|
||||||
let srv = apply(InFlight::new(1), fn_factory(|| ok(SleepService(wait_time))));
|
let srv = apply(InFlight::new(1), fn_factory(|| ok(SleepService(wait_time))));
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
//! Actix utils - various helper services
|
//! Actix utils - various helper services
|
||||||
|
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms)]
|
||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
|
|
||||||
pub mod condition;
|
pub mod condition;
|
||||||
pub mod counter;
|
pub mod counter;
|
||||||
|
pub mod dispatcher;
|
||||||
pub mod either;
|
pub mod either;
|
||||||
pub mod framed;
|
|
||||||
pub mod inflight;
|
pub mod inflight;
|
||||||
pub mod keepalive;
|
pub mod keepalive;
|
||||||
pub mod mpsc;
|
pub mod mpsc;
|
||||||
|
|
|
@ -170,7 +170,7 @@ pub struct PReceiver<T> {
|
||||||
inner: Rc<RefCell<Slab<PoolInner<T>>>>,
|
inner: Rc<RefCell<Slab<PoolInner<T>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The oneshots do not ever project Pin to the inner T
|
// The one-shots do not ever project Pin to the inner T
|
||||||
impl<T> Unpin for PReceiver<T> {}
|
impl<T> Unpin for PReceiver<T> {}
|
||||||
impl<T> Unpin for PSender<T> {}
|
impl<T> Unpin for PSender<T> {}
|
||||||
|
|
||||||
|
|
|
@ -231,7 +231,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_inorder() {
|
async fn test_in_order() {
|
||||||
let (tx1, rx1) = oneshot::channel();
|
let (tx1, rx1) = oneshot::channel();
|
||||||
let (tx2, rx2) = oneshot::channel();
|
let (tx2, rx2) = oneshot::channel();
|
||||||
let (tx3, rx3) = oneshot::channel();
|
let (tx3, rx3) = oneshot::channel();
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl LocalWaker {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Check if waker has been registered.
|
/// Check if waker has been registered.
|
||||||
pub fn is_registed(&self) -> bool {
|
pub fn is_registered(&self) -> bool {
|
||||||
unsafe { (*self.waker.get()).is_some() }
|
unsafe { (*self.waker.get()).is_some() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ mod tests {
|
||||||
///
|
///
|
||||||
/// Expected Behavior: Two back-to-back calls of `LowResTimeService::now()` return the same value.
|
/// Expected Behavior: Two back-to-back calls of `LowResTimeService::now()` return the same value.
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn lowres_time_service_time_does_not_immediately_change() {
|
async fn low_res_time_service_time_does_not_immediately_change() {
|
||||||
let resolution = Duration::from_millis(50);
|
let resolution = Duration::from_millis(50);
|
||||||
let time_service = LowResTimeService::with(resolution);
|
let time_service = LowResTimeService::with(resolution);
|
||||||
assert_eq!(time_service.now(), time_service.now());
|
assert_eq!(time_service.now(), time_service.now());
|
||||||
|
@ -210,7 +210,7 @@ mod tests {
|
||||||
/// Expected Behavior: Two calls of `LowResTimeService::now()` made in subsequent resolution interval return different values
|
/// Expected Behavior: Two calls of `LowResTimeService::now()` made in subsequent resolution interval return different values
|
||||||
/// and second value is greater than the first one at least by a resolution interval.
|
/// and second value is greater than the first one at least by a resolution interval.
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn lowres_time_service_time_updates_after_resolution_interval() {
|
async fn low_res_time_service_time_updates_after_resolution_interval() {
|
||||||
let resolution = Duration::from_millis(100);
|
let resolution = Duration::from_millis(100);
|
||||||
let wait_time = Duration::from_millis(300);
|
let wait_time = Duration::from_millis(300);
|
||||||
let time_service = LowResTimeService::with(resolution);
|
let time_service = LowResTimeService::with(resolution);
|
||||||
|
|
|
@ -58,10 +58,7 @@ impl<E: PartialEq> PartialEq for TimeoutError<E> {
|
||||||
TimeoutError::Service(e2) => e1 == e2,
|
TimeoutError::Service(e2) => e1 == e2,
|
||||||
TimeoutError::Timeout => false,
|
TimeoutError::Timeout => false,
|
||||||
},
|
},
|
||||||
TimeoutError::Timeout => match other {
|
TimeoutError::Timeout => matches!(other, TimeoutError::Timeout),
|
||||||
TimeoutError::Service(_) => false,
|
|
||||||
TimeoutError::Timeout => true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,7 +220,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_timeout_newservice() {
|
async fn test_timeout_new_service() {
|
||||||
let resolution = Duration::from_millis(100);
|
let resolution = Duration::from_millis(100);
|
||||||
let wait_time = Duration::from_millis(500);
|
let wait_time = Duration::from_millis(500);
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ impl ResourcePath for bytestring::ByteString {
|
||||||
|
|
||||||
/// Helper trait for type that could be converted to path pattern
|
/// Helper trait for type that could be converted to path pattern
|
||||||
pub trait IntoPattern {
|
pub trait IntoPattern {
|
||||||
/// Signle patter
|
|
||||||
fn is_single(&self) -> bool;
|
fn is_single(&self) -> bool;
|
||||||
|
|
||||||
fn patterns(&self) -> Vec<String>;
|
fn patterns(&self) -> Vec<String>;
|
||||||
|
|
Loading…
Reference in New Issue