diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..2bb9a234
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,131 @@
+name: CI
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+ push:
+ branches: [master]
+
+jobs:
+ build_and_test:
+ strategy:
+ fail-fast: false
+ matrix:
+ target:
+ - { name: Linux, os: ubuntu-latest, triple: x86_64-unknown-linux-gnu }
+ - { name: macOS, os: macos-latest, triple: x86_64-apple-darwin }
+ - { name: Windows, os: windows-latest, triple: x86_64-pc-windows-msvc }
+ - { name: Windows (MinGW), os: windows-latest, triple: x86_64-pc-windows-gnu }
+ - { name: Windows (32-bit), os: windows-latest, triple: i686-pc-windows-msvc }
+ version:
+ - 1.46.0 # MSRV
+ - stable
+ - nightly
+
+ name: ${{ matrix.target.name }} / ${{ matrix.version }}
+ runs-on: ${{ matrix.target.os }}
+
+ env:
+ VCPKGRS_DYNAMIC: 1
+
+ steps:
+ - name: Setup Routing
+ if: matrix.target.os == 'macos-latest'
+ run: sudo ifconfig lo0 alias 127.0.0.3
+
+ - uses: actions/checkout@v2
+
+ # install OpenSSL on Windows
+ - name: Set vcpkg root
+ if: matrix.target.triple == 'x86_64-pc-windows-msvc' || matrix.target.triple == 'i686-pc-windows-msvc'
+ run: echo "VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT" | Out-File -FilePath $env:GITHUB_ENV -Append
+ - name: Install OpenSSL
+ if: matrix.target.triple == 'x86_64-pc-windows-msvc'
+ run: vcpkg install openssl:x64-windows
+ - name: Install OpenSSL
+ if: matrix.target.triple == 'i686-pc-windows-msvc'
+ run: vcpkg install openssl:x86-windows
+
+ - name: Install ${{ matrix.version }}
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.version }}-${{ matrix.target.triple }}
+ profile: minimal
+ override: true
+
+ # - name: Install MSYS2
+ # if: matrix.target.triple == 'x86_64-pc-windows-gnu'
+ # uses: msys2/setup-msys2@v2
+ # - name: Install MinGW Packages
+ # if: matrix.target.triple == 'x86_64-pc-windows-gnu'
+ # run: |
+ # msys2 -c 'pacman -Sy --noconfirm pacman'
+ # msys2 -c 'pacman --noconfirm -S base-devel pkg-config'
+
+ # - name: Generate Cargo.lock
+ # uses: actions-rs/cargo@v1
+ # with:
+ # command: generate-lockfile
+ # - name: Cache Dependencies
+ # uses: Swatinem/rust-cache@v1.2.0
+
+ - name: Install cargo-hack
+ uses: actions-rs/cargo@v1
+ with:
+ command: install
+ args: cargo-hack
+
+ - name: check minimal
+ uses: actions-rs/cargo@v1
+ with:
+ command: hack
+ args: check --workspace --no-default-features
+
+ - name: check minimal + tests
+ uses: actions-rs/cargo@v1
+ with:
+ command: hack
+ args: check --workspace --no-default-features --tests --examples
+
+ - name: check default
+ uses: actions-rs/cargo@v1
+ with:
+ command: check
+ args: --workspace --tests --examples
+
+ - name: check full
+ # TODO: compile OpenSSL and run tests on MinGW
+ if: matrix.target.triple != 'x86_64-pc-windows-gnu'
+ uses: actions-rs/cargo@v1
+ with:
+ command: check
+ args: --workspace --all-features --tests --examples
+
+ - name: tests
+ if: matrix.target.triple != 'x86_64-pc-windows-gnu'
+ uses: actions-rs/cargo@v1
+ with:
+ command: test
+ args: --workspace --all-features --no-fail-fast -- --nocapture
+
+ - name: Generate coverage file
+ if: >
+ matrix.target.os == 'ubuntu-latest'
+ && matrix.version == 'stable'
+ && github.ref == 'refs/heads/master'
+ run: |
+ cargo install cargo-tarpaulin
+ cargo tarpaulin --out Xml --verbose
+ - name: Upload to Codecov
+ if: >
+ matrix.target.os == 'ubuntu-latest'
+ && matrix.version == 'stable'
+ && github.ref == 'refs/heads/master'
+ uses: codecov/codecov-action@v1
+ with:
+ file: cobertura.xml
+
+ - name: Clear the cargo caches
+ run: |
+ cargo install cargo-cache --no-default-features --features ci-autoclean
+ cargo-cache
diff --git a/.github/workflows/clippy-fmt.yml b/.github/workflows/clippy-fmt.yml
index 12343dd4..3bef81db 100644
--- a/.github/workflows/clippy-fmt.yml
+++ b/.github/workflows/clippy-fmt.yml
@@ -1,34 +1,42 @@
+name: Lint
+
on:
pull_request:
types: [opened, synchronize, reopened]
-name: Clippy and rustfmt Check
jobs:
- clippy_check:
+ fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- - uses: actions-rs/toolchain@v1
+ - name: Install Rust
+ uses: actions-rs/toolchain@v1
with:
toolchain: stable
- components: rustfmt
profile: minimal
+ components: rustfmt
override: true
- - name: Check with rustfmt
+ - name: Rustfmt Check
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- - uses: actions-rs/toolchain@v1
+ clippy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Install Rust
+ uses: actions-rs/toolchain@v1
with:
- toolchain: nightly
- components: clippy
+ toolchain: stable
profile: minimal
+ components: clippy
override: true
- - name: Check with Clippy
+ - name: Clippy Check
uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
- args: --workspace --tests
+ args: --workspace --tests --all-features
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
deleted file mode 100644
index 8ea7823d..00000000
--- a/.github/workflows/linux.yml
+++ /dev/null
@@ -1,82 +0,0 @@
-name: CI (Linux)
-
-on:
- pull_request:
- types: [opened, synchronize, reopened]
- push:
- branches:
- - master
- - '1.0'
-
-jobs:
- build_and_test:
- strategy:
- fail-fast: false
- matrix:
- version:
- - 1.46.0
- - stable
- - nightly
-
- name: ${{ matrix.version }} - x86_64-unknown-linux-gnu
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Install ${{ matrix.version }}
- uses: actions-rs/toolchain@v1
- with:
- toolchain: ${{ matrix.version }}-x86_64-unknown-linux-gnu
- profile: minimal
- override: true
-
- - name: Generate Cargo.lock
- uses: actions-rs/cargo@v1
- with:
- command: generate-lockfile
- - name: Cache cargo dirs
- uses: actions/cache@v2
- with:
- path:
- ~/.cargo/registry
- ~/.cargo/git
- ~/.cargo/bin
- key: ${{ matrix.version }}-x86_64-unknown-linux-gnu-cargo-trimmed-${{ hashFiles('**/Cargo.lock') }}
- - name: Cache cargo build
- uses: actions/cache@v2
- with:
- path: target
- key: ${{ matrix.version }}-x86_64-unknown-linux-gnu-cargo-build-trimmed-${{ hashFiles('**/Cargo.lock') }}
-
- - name: check build
- uses: actions-rs/cargo@v1
- with:
- command: check
- args: --workspace --bins --examples --tests
-
- - name: tests
- uses: actions-rs/cargo@v1
- timeout-minutes: 40
- with:
- command: test
- args: --workspace --exclude=actix-tls --no-fail-fast -- --nocapture
-
- - name: Generate coverage file
- if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
- run: |
- cargo install cargo-tarpaulin
- cargo tarpaulin --out Xml --workspace
-
- - name: Upload to Codecov
- if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
- uses: codecov/codecov-action@v1
- with:
- file: cobertura.xml
-
- - name: Clear the cargo caches
- run: |
- rustup update stable
- rustup override set stable
- cargo install cargo-cache --no-default-features --features ci-autoclean
- cargo-cache
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
deleted file mode 100644
index b2555bd3..00000000
--- a/.github/workflows/macos.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-name: CI (macOS)
-
-on:
- pull_request:
- types: [opened, synchronize, reopened]
- push:
- branches:
- - master
- - '1.0'
-
-jobs:
- build_and_test:
- strategy:
- fail-fast: false
- matrix:
- version:
- - stable
- - nightly
-
- name: ${{ matrix.version }} - x86_64-apple-darwin
- runs-on: macos-latest
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Install ${{ matrix.version }}
- uses: actions-rs/toolchain@v1
- with:
- toolchain: ${{ matrix.version }}-x86_64-apple-darwin
- profile: minimal
- override: true
-
- - name: check build
- uses: actions-rs/cargo@v1
- with:
- command: check
- args: --workspace --bins --examples --tests
-
- - name: tests
- uses: actions-rs/cargo@v1
- with:
- command: test
- args: --workspace --exclude=actix-tls --no-fail-fast -- --nocapture
diff --git a/.github/workflows/upload-doc.yml b/.github/workflows/upload-doc.yml
new file mode 100644
index 00000000..36044230
--- /dev/null
+++ b/.github/workflows/upload-doc.yml
@@ -0,0 +1,35 @@
+name: Upload documentation
+
+on:
+ push:
+ branches: [master]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Install Rust
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: nightly-x86_64-unknown-linux-gnu
+ profile: minimal
+ override: true
+
+ - name: Build Docs
+ uses: actions-rs/cargo@v1
+ with:
+ command: doc
+ args: --workspace --all-features --no-deps
+
+ - name: Tweak HTML
+ run: echo '' > target/doc/index.html
+
+ - name: Deploy to GitHub Pages
+ uses: JamesIves/github-pages-deploy-action@3.7.1
+ with:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ BRANCH: gh-pages
+ FOLDER: target/doc
diff --git a/.github/workflows/windows-mingw.yml b/.github/workflows/windows-mingw.yml
deleted file mode 100644
index 1fd5fc59..00000000
--- a/.github/workflows/windows-mingw.yml
+++ /dev/null
@@ -1,45 +0,0 @@
-name: CI (Windows-mingw)
-
-on:
- pull_request:
- types: [opened, synchronize, reopened]
- push:
- branches:
- - master
- - '1.0'
-
-jobs:
- build_and_test:
- strategy:
- fail-fast: false
- matrix:
- version:
- - stable
- - nightly
-
- name: ${{ matrix.version }} - x86_64-pc-windows-gnu
- runs-on: windows-latest
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Install ${{ matrix.version }}
- uses: actions-rs/toolchain@v1
- with:
- toolchain: ${{ matrix.version }}-x86_64-pc-windows-gnu
- profile: minimal
- override: true
-
- - name: Install MSYS2
- uses: msys2/setup-msys2@v2
-
- - name: Install packages
- run: |
- msys2 -c 'pacman -Sy --noconfirm pacman'
- msys2 -c 'pacman --noconfirm -S base-devel pkg-config'
-
- - name: check build
- uses: actions-rs/cargo@v1
- with:
- command: check
- args: --workspace --bins --examples --tests
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
deleted file mode 100644
index b2b57989..00000000
--- a/.github/workflows/windows.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-name: CI (Windows)
-
-on:
- pull_request:
- types: [opened, synchronize, reopened]
- push:
- branches:
- - master
- - '1.0'
-
-env:
- VCPKGRS_DYNAMIC: 1
-
-jobs:
- build_and_test:
- strategy:
- fail-fast: false
- matrix:
- version:
- - stable
- - nightly
- target:
- - x86_64-pc-windows-msvc
- - i686-pc-windows-msvc
-
- name: ${{ matrix.version }} - ${{ matrix.target }}
- runs-on: windows-latest
-
- steps:
- - uses: actions/checkout@v2
-
- - name: Install ${{ matrix.version }}
- uses: actions-rs/toolchain@v1
- with:
- toolchain: ${{ matrix.version }}-${{ matrix.target }}
- profile: minimal
- override: true
-
- - name: Install OpenSSL (x64)
- if: matrix.target == 'x86_64-pc-windows-msvc'
- run: |
- vcpkg integrate install
- vcpkg install openssl:x64-windows
- Get-ChildItem C:\vcpkg\installed\x64-windows\bin
- Get-ChildItem C:\vcpkg\installed\x64-windows\lib
- Copy-Item C:\vcpkg\installed\x64-windows\bin\libcrypto-1_1-x64.dll C:\vcpkg\installed\x64-windows\bin\libcrypto.dll
- Copy-Item C:\vcpkg\installed\x64-windows\bin\libssl-1_1-x64.dll C:\vcpkg\installed\x64-windows\bin\libssl.dll
-
- - name: Install OpenSSL (x86)
- if: matrix.target == 'i686-pc-windows-msvc'
- run: |
- vcpkg integrate install
- vcpkg install openssl:x86-windows
- Get-ChildItem C:\vcpkg\installed\x86-windows\bin
- Get-ChildItem C:\vcpkg\installed\x86-windows\lib
- Copy-Item C:\vcpkg\installed\x86-windows\bin\libcrypto-1_1.dll C:\vcpkg\installed\x86-windows\bin\libcrypto.dll
- Copy-Item C:\vcpkg\installed\x86-windows\bin\libssl-1_1.dll C:\vcpkg\installed\x86-windows\bin\libssl.dll
-
- - name: check build
- uses: actions-rs/cargo@v1
- with:
- command: check
- args: --workspace --bins --examples --tests
-
- - name: tests
- uses: actions-rs/cargo@v1
- with:
- command: test
- args: --workspace --exclude=actix-tls --no-fail-fast -- --nocapture
diff --git a/actix-router/src/resource.rs b/actix-router/src/resource.rs
index 8dbef26c..98b4a709 100644
--- a/actix-router/src/resource.rs
+++ b/actix-router/src/resource.rs
@@ -670,8 +670,6 @@ pub(crate) fn insert_slash(path: &str) -> String {
#[cfg(test)]
mod tests {
use super::*;
- use http::Uri;
- use std::convert::TryFrom;
#[test]
fn test_parse_static() {
@@ -833,8 +831,11 @@ mod tests {
assert!(re.is_match("/user/2345/sdg"));
}
+ #[cfg(feature = "http")]
#[test]
fn test_parse_urlencoded_param() {
+ use std::convert::TryFrom;
+
let re = ResourceDef::new("/user/{id}/test");
let mut path = Path::new("/user/2345/test");
@@ -845,7 +846,7 @@ mod tests {
assert!(re.match_path(&mut path));
assert_eq!(path.get("id").unwrap(), "qwe%25");
- let uri = Uri::try_from("/user/qwe%25/test").unwrap();
+ let uri = http::Uri::try_from("/user/qwe%25/test").unwrap();
let mut path = Path::new(uri);
assert!(re.match_path(&mut path));
assert_eq!(path.get("id").unwrap(), "qwe%25");
diff --git a/actix-rt/CHANGES.md b/actix-rt/CHANGES.md
index 6754ca33..83ecc5ed 100644
--- a/actix-rt/CHANGES.md
+++ b/actix-rt/CHANGES.md
@@ -1,6 +1,17 @@
# Changes
## Unreleased - 2021-xx-xx
+* `ActixStream::{poll_read_ready, poll_write_ready}` would return `Ready` in Ok variant. [#293]
+
+[#293] https://github.com/actix/actix-net/pull/293
+
+
+## 2.1.0 - 2021-02-24
+* Add `ActixStream` extension trait to include readiness methods. [#276]
+* Re-export `tokio::net::TcpSocket` in `net` module [#282]
+
+[#276]: https://github.com/actix/actix-net/pull/276
+[#282]: https://github.com/actix/actix-net/pull/282
## 2.0.2 - 2021-02-06
diff --git a/actix-rt/Cargo.toml b/actix-rt/Cargo.toml
index 7990e67d..126056ec 100644
--- a/actix-rt/Cargo.toml
+++ b/actix-rt/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "actix-rt"
-version = "2.0.2"
+version = "2.1.0"
authors = [
"Nikolay Kim ",
"Rob Ede ",
@@ -8,7 +8,7 @@ authors = [
description = "Tokio-based single-threaded async runtime for the Actix ecosystem"
keywords = ["async", "futures", "io", "runtime"]
homepage = "https://actix.rs"
-repository = "https://github.com/actix/actix-net.git"
+repository = "https://github.com/actix/actix-net"
documentation = "https://docs.rs/actix-rt"
categories = ["network-programming", "asynchronous"]
license = "MIT OR Apache-2.0"
@@ -26,7 +26,7 @@ macros = ["actix-macros"]
actix-macros = { version = "0.2.0", optional = true }
futures-core = { version = "0.3", default-features = false }
-tokio = { version = "1.2", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] }
+tokio = { version = "1.3", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] }
[dev-dependencies]
tokio = { version = "1.2", features = ["full"] }
diff --git a/actix-rt/README.md b/actix-rt/README.md
index c29d563d..f9a3ed31 100644
--- a/actix-rt/README.md
+++ b/actix-rt/README.md
@@ -2,4 +2,13 @@
> Tokio-based single-threaded async runtime for the Actix ecosystem.
+[](https://crates.io/crates/actix-rt)
+[](https://docs.rs/actix-rt/2.1.0)
+[](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html)
+
+
+[](https://deps.rs/crate/actix-rt/2.1.0)
+
+[](https://discord.gg/WghFtEH6Hb)
+
See crate documentation for more: https://docs.rs/actix-rt.
diff --git a/actix-rt/src/lib.rs b/actix-rt/src/lib.rs
index a7e9f309..bd2e165d 100644
--- a/actix-rt/src/lib.rs
+++ b/actix-rt/src/lib.rs
@@ -70,13 +70,63 @@ pub mod signal {
}
pub mod net {
- //! TCP/UDP/Unix bindings (Tokio re-exports).
+ //! TCP/UDP/Unix bindings (mostly Tokio re-exports).
+ use std::{
+ future::Future,
+ io,
+ task::{Context, Poll},
+ };
+
+ pub use tokio::io::Ready;
+ use tokio::io::{AsyncRead, AsyncWrite, Interest};
pub use tokio::net::UdpSocket;
- pub use tokio::net::{TcpListener, TcpStream};
+ pub use tokio::net::{TcpListener, TcpSocket, TcpStream};
#[cfg(unix)]
pub use tokio::net::{UnixDatagram, UnixListener, UnixStream};
+
+ /// Extension trait over async read+write types that can also signal readiness.
+ pub trait ActixStream: AsyncRead + AsyncWrite + Unpin + 'static {
+ /// Poll stream and check read readiness of Self.
+ ///
+ /// See [tokio::net::TcpStream::poll_read_ready] for detail on intended use.
+ fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll>;
+
+ /// Poll stream and check write readiness of Self.
+ ///
+ /// See [tokio::net::TcpStream::poll_write_ready] for detail on intended use.
+ fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll>;
+ }
+
+ impl ActixStream for TcpStream {
+ fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll> {
+ let ready = self.ready(Interest::READABLE);
+ tokio::pin!(ready);
+ ready.poll(cx)
+ }
+
+ fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> {
+ let ready = self.ready(Interest::WRITABLE);
+ tokio::pin!(ready);
+ ready.poll(cx)
+ }
+ }
+
+ #[cfg(unix)]
+ impl ActixStream for UnixStream {
+ fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll> {
+ let ready = self.ready(Interest::READABLE);
+ tokio::pin!(ready);
+ ready.poll(cx)
+ }
+
+ fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> {
+ let ready = self.ready(Interest::WRITABLE);
+ tokio::pin!(ready);
+ ready.poll(cx)
+ }
+ }
}
pub mod time {
diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml
index 1b088e30..83350a81 100755
--- a/actix-server/Cargo.toml
+++ b/actix-server/Cargo.toml
@@ -12,7 +12,6 @@ repository = "https://github.com/actix/actix-net.git"
documentation = "https://docs.rs/actix-server"
categories = ["network-programming", "asynchronous"]
license = "MIT OR Apache-2.0"
-exclude = [".gitignore", ".cargo/config"]
edition = "2018"
[lib]
@@ -25,7 +24,7 @@ default = []
[dependencies]
actix-codec = "0.4.0-beta.1"
actix-rt = { version = "2.0.0", default-features = false }
-actix-service = "2.0.0-beta.4"
+actix-service = "2.0.0-beta.5"
actix-utils = "3.0.0-beta.2"
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
@@ -33,7 +32,7 @@ log = "0.4"
mio = { version = "0.7.6", features = ["os-poll", "net"] }
num_cpus = "1.13"
slab = "0.4"
-tokio = { version = "1", features = ["sync"] }
+tokio = { version = "1.2", features = ["sync"] }
[dev-dependencies]
actix-rt = "2.0.0"
diff --git a/actix-server/examples/basic.rs b/actix-server/examples/tcp-echo.rs
similarity index 98%
rename from actix-server/examples/basic.rs
rename to actix-server/examples/tcp-echo.rs
index 76918967..ad18a1ac 100644
--- a/actix-server/examples/basic.rs
+++ b/actix-server/examples/tcp-echo.rs
@@ -16,7 +16,7 @@ use std::sync::{
use std::{env, io};
use actix_rt::net::TcpStream;
-use actix_server::ServerHandle;
+use actix_server::Server;
use actix_service::pipeline_factory;
use bytes::BytesMut;
use futures_util::future::ok;
@@ -36,7 +36,7 @@ async fn main() -> io::Result<()> {
// Bind socket address and start worker(s). By default, the server uses the number of available
// logical CPU cores as the worker count. For this reason, the closure passed to bind needs
// to return a service *factory*; so it can be created once per worker.
- ServerHandle::build()
+ Server::build()
.bind("echo", addr, move || {
let count = Arc::clone(&count);
let num2 = Arc::clone(&count);
diff --git a/actix-server/src/accept.rs b/actix-server/src/accept.rs
index b78ebf70..2b5bd764 100644
--- a/actix-server/src/accept.rs
+++ b/actix-server/src/accept.rs
@@ -5,7 +5,7 @@ use log::{error, info};
use mio::{Interest, Poll, Token as MioToken};
use slab::Slab;
-use crate::server_handle::ServerHandle;
+use crate::server_handle::Server;
use crate::socket::{MioListener, SocketAddr};
use crate::waker_queue::{WakerInterest, WakerQueue, WAKER_TOKEN};
use crate::worker::{Conn, WorkerHandle};
@@ -29,7 +29,7 @@ pub(crate) struct Accept {
poll: Poll,
waker_queue: WakerQueue,
handles: Vec,
- srv: ServerHandle,
+ srv: Server,
next: usize,
backpressure: bool,
// poll time duration.
@@ -53,7 +53,7 @@ fn connection_error(e: &io::Error) -> bool {
impl Accept {
pub(crate) fn start(
sockets: Vec<(Token, MioListener)>,
- server_handle: ServerHandle,
+ server_handle: Server,
worker_factory: F,
) -> WakerQueue
where
@@ -92,7 +92,7 @@ impl Accept {
waker_queue: WakerQueue,
socks: Vec<(Token, MioListener)>,
handles: Vec,
- srv: ServerHandle,
+ srv: Server,
) -> (Accept, Slab) {
let mut sockets = Slab::new();
for (hnd_token, mut lst) in socks.into_iter() {
diff --git a/actix-server/src/builder.rs b/actix-server/src/builder.rs
index 7fed6f5e..8fd130fc 100644
--- a/actix-server/src/builder.rs
+++ b/actix-server/src/builder.rs
@@ -14,7 +14,7 @@ use tokio::sync::oneshot;
use crate::accept::Accept;
use crate::config::{ConfiguredService, ServiceConfig};
-use crate::server_handle::{ServerCommand, ServerHandle};
+use crate::server_handle::{Server, ServerCommand};
use crate::service::{InternalServiceFactory, ServiceFactory, StreamNewService};
use crate::signals::{Signal, Signals};
use crate::socket::{MioListener, StdSocketAddr, StdTcpListener, ToSocketAddrs};
@@ -285,7 +285,7 @@ impl ServerBuilder {
// start accept thread. return waker_queue for wake up it.
let waker_queue = Accept::start(
sockets,
- ServerHandle::new(self.cmd_tx.clone()),
+ Server::new(self.cmd_tx.clone()),
// closure for construct worker and return it's handler.
|waker| {
(0..self.threads)
@@ -349,8 +349,8 @@ impl ServerFuture {
/// Obtain a Handle for ServerFuture that can be used to change state of actix server.
///
/// See [ServerHandle](crate::server::ServerHandle) for usage.
- pub fn handle(&self) -> ServerHandle {
- ServerHandle::new(self.cmd_tx.clone())
+ pub fn handle(&self) -> Server {
+ Server::new(self.cmd_tx.clone())
}
fn handle_cmd(&mut self, item: ServerCommand) -> Option> {
diff --git a/actix-server/src/lib.rs b/actix-server/src/lib.rs
index d9c1eeb2..6be373bd 100644
--- a/actix-server/src/lib.rs
+++ b/actix-server/src/lib.rs
@@ -15,9 +15,9 @@ mod test_server;
mod waker_queue;
mod worker;
-pub use self::builder::ServerBuilder;
+pub use self::builder::{ServerBuilder, ServerFuture};
pub use self::config::{ServiceConfig, ServiceRuntime};
-pub use self::server_handle::ServerHandle;
+pub use self::server_handle::Server;
pub use self::service::ServiceFactory;
pub use self::test_server::TestServer;
diff --git a/actix-server/src/server_handle.rs b/actix-server/src/server_handle.rs
index 679dc1a1..74228b3f 100644
--- a/actix-server/src/server_handle.rs
+++ b/actix-server/src/server_handle.rs
@@ -25,14 +25,14 @@ pub(crate) enum ServerCommand {
}
#[derive(Debug)]
-pub struct ServerHandle(
+pub struct Server(
UnboundedSender,
Option>,
);
-impl ServerHandle {
+impl Server {
pub(crate) fn new(tx: UnboundedSender) -> Self {
- ServerHandle(tx, None)
+ Server(tx, None)
}
/// Start server building process
@@ -80,13 +80,13 @@ impl ServerHandle {
}
}
-impl Clone for ServerHandle {
+impl Clone for Server {
fn clone(&self) -> Self {
Self(self.0.clone(), None)
}
}
-impl Future for ServerHandle {
+impl Future for Server {
type Output = io::Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
diff --git a/actix-server/src/test_server.rs b/actix-server/src/test_server.rs
index 996faa2a..c8e5941c 100644
--- a/actix-server/src/test_server.rs
+++ b/actix-server/src/test_server.rs
@@ -3,7 +3,7 @@ use std::{net, thread};
use actix_rt::{net::TcpStream, System};
-use crate::{ServerBuilder, ServerHandle, ServiceFactory};
+use crate::{Server, ServerBuilder, ServiceFactory};
/// The `TestServer` type.
///
@@ -51,7 +51,7 @@ impl TestServer {
let sys = System::new();
sys.block_on(async {
actix_rt::spawn(async move {
- let _ = factory(ServerHandle::build())
+ let _ = factory(Server::build())
.workers(1)
.disable_signals()
.run()
@@ -84,7 +84,7 @@ impl TestServer {
sys.block_on(async {
actix_rt::spawn(async move {
- let _ = ServerHandle::build()
+ let _ = Server::build()
.listen("test", tcp, factory)
.unwrap()
.workers(1)
diff --git a/actix-server/src/waker_queue.rs b/actix-server/src/waker_queue.rs
index 6b103689..9ac101b3 100644
--- a/actix-server/src/waker_queue.rs
+++ b/actix-server/src/waker_queue.rs
@@ -8,7 +8,7 @@ use mio::{Registry, Token as MioToken, Waker};
use crate::worker::WorkerHandle;
-/// waker token for `mio::Poll` instance
+/// Waker token for `mio::Poll` instance.
pub(crate) const WAKER_TOKEN: MioToken = MioToken(usize::MAX);
/// `mio::Waker` with a queue for waking up the `Accept`'s `Poll` and contains the `WakerInterest`
@@ -30,7 +30,7 @@ impl Deref for WakerQueue {
}
impl WakerQueue {
- /// construct a waker queue with given `Poll`'s `Registry` and capacity.
+ /// Construct a waker queue with given `Poll`'s `Registry` and capacity.
///
/// A fixed `WAKER_TOKEN` is used to identify the wake interest and the `Poll` needs to match
/// event's token for it to properly handle `WakerInterest`.
@@ -41,7 +41,7 @@ impl WakerQueue {
Ok(Self(Arc::new((waker, queue))))
}
- /// push a new interest to the queue and wake up the accept poll afterwards.
+ /// Push a new interest to the queue and wake up the accept poll afterwards.
pub(crate) fn wake(&self, interest: WakerInterest) {
let (waker, queue) = self.deref();
@@ -55,20 +55,20 @@ impl WakerQueue {
.unwrap_or_else(|e| panic!("can not wake up Accept Poll: {}", e));
}
- /// get a MutexGuard of the waker queue.
+ /// Get a MutexGuard of the waker queue.
pub(crate) fn guard(&self) -> MutexGuard<'_, VecDeque> {
self.deref().1.lock().expect("Failed to lock WakerQueue")
}
- /// reset the waker queue so it does not grow infinitely.
+ /// Reset the waker queue so it does not grow infinitely.
pub(crate) fn reset(queue: &mut VecDeque) {
std::mem::swap(&mut VecDeque::::with_capacity(16), queue);
}
}
-/// types of interests we would look into when `Accept`'s `Poll` is waked up by waker.
+/// Types of interests we would look into when `Accept`'s `Poll` is waked up by waker.
///
-/// *. These interests should not be confused with `mio::Interest` and mostly not I/O related
+/// These interests should not be confused with `mio::Interest` and mostly not I/O related
pub(crate) enum WakerInterest {
/// `WorkerAvailable` is an interest from `Worker` notifying `Accept` there is a worker
/// available and can accept new tasks.
diff --git a/actix-server/src/worker.rs b/actix-server/src/worker.rs
index aad4c7a3..a6527fc0 100644
--- a/actix-server/src/worker.rs
+++ b/actix-server/src/worker.rs
@@ -199,62 +199,59 @@ impl ServerWorker {
availability.set(false);
+ let handle = tokio::runtime::Handle::current();
+
// every worker runs in it's own arbiter.
// use a custom tokio runtime builder to change the settings of runtime.
std::thread::spawn(move || {
- let mut wrk = MAX_CONNS_COUNTER.with(move |conns| ServerWorker {
- rx,
- rx2,
- availability,
- factories,
- config,
- services: Vec::new(),
- conns: conns.clone(),
- state: WorkerState::Unavailable,
- });
- let fut = wrk
- .factories
- .iter()
- .enumerate()
- .map(|(idx, factory)| {
- let fut = factory.create();
- async move {
- fut.await.map(|r| {
- r.into_iter().map(|(t, s)| (idx, t, s)).collect::>()
- })
- }
- })
- .collect::>();
+ handle.block_on(tokio::task::LocalSet::new().run_until(async move {
+ let mut wrk = MAX_CONNS_COUNTER.with(move |conns| ServerWorker {
+ rx,
+ rx2,
+ availability,
+ factories,
+ config,
+ services: Vec::new(),
+ conns: conns.clone(),
+ state: WorkerState::Unavailable,
+ });
+ let fut = wrk
+ .factories
+ .iter()
+ .enumerate()
+ .map(|(idx, factory)| {
+ let fut = factory.create();
+ async move {
+ fut.await.map(|r| {
+ r.into_iter().map(|(t, s)| (idx, t, s)).collect::>()
+ })
+ }
+ })
+ .collect::>();
- tokio::runtime::Builder::new_current_thread()
- .enable_all()
- .max_blocking_threads(config.max_blocking_threads)
- .build()
- .unwrap()
- .block_on(tokio::task::LocalSet::new().run_until(async move {
- let res = join_all(fut)
- .await
- .into_iter()
- .collect::, _>>();
- match res {
- Ok(services) => {
- for item in services {
- for (factory, token, service) in item {
- assert_eq!(token.0, wrk.services.len());
- wrk.services.push(WorkerService {
- factory,
- service,
- status: WorkerServiceStatus::Unavailable,
- });
- }
+ let res = join_all(fut)
+ .await
+ .into_iter()
+ .collect::, _>>();
+ match res {
+ Ok(services) => {
+ for item in services {
+ for (factory, token, service) in item {
+ assert_eq!(token.0, wrk.services.len());
+ wrk.services.push(WorkerService {
+ factory,
+ service,
+ status: WorkerServiceStatus::Unavailable,
+ });
}
}
- Err(e) => {
- error!("Can not start worker: {:?}", e);
- }
}
- wrk.await
- }))
+ Err(e) => {
+ error!("Can not start worker: {:?}", e);
+ }
+ }
+ wrk.await
+ }))
});
WorkerHandle::new(idx, tx1, tx2, avail)
diff --git a/actix-server/tests/test_server.rs b/actix-server/tests/test_server.rs
index 23e4635c..55774b1f 100644
--- a/actix-server/tests/test_server.rs
+++ b/actix-server/tests/test_server.rs
@@ -2,7 +2,7 @@ use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
use std::sync::{mpsc, Arc};
use std::{net, thread, time};
-use actix_server::ServerHandle;
+use actix_server::Server;
use actix_service::fn_service;
use futures_util::future::{lazy, ok};
@@ -24,7 +24,7 @@ fn test_bind() {
let sys = actix_rt::System::new();
sys.block_on(async {
actix_rt::spawn(async move {
- let _ = ServerHandle::build()
+ let _ = Server::build()
.workers(1)
.disable_signals()
.bind("test", addr, move || fn_service(|_| ok::<_, ()>(())))
@@ -54,7 +54,7 @@ fn test_listen() {
let lst = net::TcpListener::bind(addr).unwrap();
sys.block_on(async {
actix_rt::spawn(async move {
- let _ = ServerHandle::build()
+ let _ = Server::build()
.disable_signals()
.workers(1)
.listen("test", lst, move || fn_service(|_| ok::<_, ()>(())))
@@ -88,7 +88,7 @@ fn test_start() {
let h = thread::spawn(move || {
actix_rt::System::new().block_on(async {
- let server = ServerHandle::build()
+ let server = Server::build()
.backlog(100)
.disable_signals()
.bind("test", addr, move || {
@@ -156,7 +156,7 @@ fn test_configure() {
let h = thread::spawn(move || {
let num = num2.clone();
actix_rt::System::new().block_on(async {
- let server = ServerHandle::build()
+ let server = Server::build()
.disable_signals()
.configure(move |cfg| {
let num = num.clone();
diff --git a/actix-service/CHANGES.md b/actix-service/CHANGES.md
index f5da9d2e..51749ecd 100644
--- a/actix-service/CHANGES.md
+++ b/actix-service/CHANGES.md
@@ -3,6 +3,14 @@
## Unreleased - 2021-xx-xx
+## 2.0.0-beta.5 - 2021-03-15
+* Add default `Service` trait impl for `Rc` and `&S: Service`. [#288]
+* Add `boxed::rc_service` function for constructing `boxed::RcService` type [#290]
+
+[#288]: https://github.com/actix/actix-net/pull/288
+[#290]: https://github.com/actix/actix-net/pull/290
+
+
## 2.0.0-beta.4 - 2021-02-04
* `Service::poll_ready` and `Service::call` receive `&self`. [#247]
* `apply_fn` and `apply_fn_factory` now receive `Fn(Req, &Service)` function type. [#247]
diff --git a/actix-service/Cargo.toml b/actix-service/Cargo.toml
index eecf4669..84a0c172 100644
--- a/actix-service/Cargo.toml
+++ b/actix-service/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "actix-service"
-version = "2.0.0-beta.4"
+version = "2.0.0-beta.5"
authors = [
"Nikolay Kim ",
"Rob Ede ",
diff --git a/actix-service/README.md b/actix-service/README.md
index 28c38295..54171274 100644
--- a/actix-service/README.md
+++ b/actix-service/README.md
@@ -3,11 +3,11 @@
> Service trait and combinators for representing asynchronous request/response operations.
[](https://crates.io/crates/actix-service)
-[](https://docs.rs/actix-service/2.0.0-beta.4)
+[](https://docs.rs/actix-service/2.0.0-beta.5)
[](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html)

-[](https://deps.rs/crate/actix-service/2.0.0-beta.4)
-[](https://crates.io/crates/actix-service)
+[](https://deps.rs/crate/actix-service/2.0.0-beta.5)
+
[](https://discord.gg/NWpN5mmg3x)
See documentation for detailed explanations of these components: https://docs.rs/actix-service.
diff --git a/actix-service/src/boxed.rs b/actix-service/src/boxed.rs
index 6ad2eaf4..a872ca9f 100644
--- a/actix-service/src/boxed.rs
+++ b/actix-service/src/boxed.rs
@@ -1,21 +1,65 @@
-use alloc::boxed::Box;
-use core::{
- future::Future,
- marker::PhantomData,
- pin::Pin,
- task::{Context, Poll},
-};
+//! Trait object forms of services and service factories.
+
+use alloc::{boxed::Box, rc::Rc};
+use core::{future::Future, pin::Pin};
use crate::{Service, ServiceFactory};
+/// A boxed future without a Send bound or lifetime parameters.
pub type BoxFuture = Pin>>;
-pub type BoxService =
- Box>>>;
+macro_rules! service_object {
+ ($name: ident, $type: tt, $fn_name: ident) => {
+ /// Type alias for service trait object.
+ pub type $name = $type<
+ dyn Service>>,
+ >;
+ /// Create service trait object.
+ pub fn $fn_name(service: S) -> $name
+ where
+ S: Service + 'static,
+ Req: 'static,
+ S::Future: 'static,
+ {
+ $type::new(ServiceWrapper::new(service))
+ }
+ };
+}
+
+service_object!(BoxService, Box, service);
+service_object!(RcService, Rc, rc_service);
+
+struct ServiceWrapper {
+ inner: S,
+}
+
+impl ServiceWrapper {
+ fn new(inner: S) -> Self {
+ Self { inner }
+ }
+}
+
+impl Service for ServiceWrapper
+where
+ S: Service,
+ S::Future: 'static,
+{
+ type Response = Res;
+ type Error = Err;
+ type Future = BoxFuture>;
+
+ crate::forward_ready!(inner);
+
+ fn call(&self, req: Req) -> Self::Future {
+ Box::pin(self.inner.call(req))
+ }
+}
+
+/// Wrapper for a service factory trait object that will produce a boxed trait object service.
pub struct BoxServiceFactory(Inner);
-/// Create boxed service factory
+/// Create service factory trait object.
pub fn factory(
factory: SF,
) -> BoxServiceFactory
@@ -28,20 +72,7 @@ where
SF::Error: 'static,
SF::InitError: 'static,
{
- BoxServiceFactory(Box::new(FactoryWrapper {
- factory,
- _t: PhantomData,
- }))
-}
-
-/// Create boxed service
-pub fn service(service: S) -> BoxService
-where
- S: Service + 'static,
- Req: 'static,
- S::Future: 'static,
-{
- Box::new(ServiceWrapper(service, PhantomData))
+ BoxServiceFactory(Box::new(FactoryWrapper(factory)))
}
type Inner = Box<
@@ -66,9 +97,9 @@ where
{
type Response = Res;
type Error = Err;
- type InitError = InitErr;
type Config = C;
type Service = BoxService;
+ type InitError = InitErr;
type Future = BoxFuture>;
@@ -77,12 +108,9 @@ where
}
}
-struct FactoryWrapper {
- factory: SF,
- _t: PhantomData<(Req, Cfg)>,
-}
+struct FactoryWrapper(SF);
-impl ServiceFactory for FactoryWrapper
+impl ServiceFactory for FactoryWrapper
where
Req: 'static,
Res: 'static,
@@ -95,47 +123,13 @@ where
{
type Response = Res;
type Error = Err;
- type InitError = InitErr;
type Config = Cfg;
type Service = BoxService;
+ type InitError = InitErr;
type Future = BoxFuture>;
fn new_service(&self, cfg: Cfg) -> Self::Future {
- let fut = self.factory.new_service(cfg);
- Box::pin(async {
- let res = fut.await;
- res.map(ServiceWrapper::boxed)
- })
- }
-}
-
-struct ServiceWrapper, Req>(S, PhantomData);
-
-impl ServiceWrapper
-where
- S: Service + 'static,
- Req: 'static,
- S::Future: 'static,
-{
- fn boxed(service: S) -> BoxService {
- Box::new(ServiceWrapper(service, PhantomData))
- }
-}
-
-impl Service for ServiceWrapper
-where
- S: Service,
- S::Future: 'static,
-{
- type Response = Res;
- type Error = Err;
- type Future = BoxFuture>;
-
- fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> {
- self.0.poll_ready(ctx)
- }
-
- fn call(&self, req: Req) -> Self::Future {
- Box::pin(self.0.call(req))
+ let f = self.0.new_service(cfg);
+ Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as _) })
}
}
diff --git a/actix-service/src/ext.rs b/actix-service/src/ext.rs
index e778d11e..d931596b 100644
--- a/actix-service/src/ext.rs
+++ b/actix-service/src/ext.rs
@@ -1,4 +1,7 @@
-use crate::{dev, Service, ServiceFactory};
+use crate::{
+ map::Map, map_err::MapErr, transform_err::TransformMapInitErr, Service, ServiceFactory,
+ Transform,
+};
pub trait ServiceExt: Service {
/// Map this service's output to a different type, returning a new service
@@ -10,12 +13,12 @@ pub trait ServiceExt: Service {
/// Note that this function consumes the receiving service and returns a
/// wrapped version of it, similar to the existing `map` methods in the
/// standard library.
- fn map(self, f: F) -> dev::Map
+ fn map(self, f: F) -> Map
where
Self: Sized,
F: FnMut(Self::Response) -> R,
{
- dev::Map::new(self, f)
+ Map::new(self, f)
}
/// Map this service's error to a different error, returning a new service.
@@ -26,12 +29,12 @@ pub trait ServiceExt: Service {
///
/// Note that this function consumes the receiving service and returns a
/// wrapped version of it.
- fn map_err(self, f: F) -> dev::MapErr
+ fn map_err(self, f: F) -> MapErr
where
Self: Sized,
F: Fn(Self::Error) -> E,
{
- dev::MapErr::new(self, f)
+ MapErr::new(self, f)
}
}
@@ -67,4 +70,17 @@ pub trait ServiceFactoryExt: ServiceFactory {
}
}
-impl ServiceFactoryExt for S where S: ServiceFactory {}
+impl ServiceFactoryExt for SF where SF: ServiceFactory {}
+
+pub trait TransformExt: Transform {
+ /// Return a new `Transform` whose init error is mapped to to a different type.
+ fn map_init_err(self, f: F) -> TransformMapInitErr
+ where
+ Self: Sized,
+ F: Fn(Self::InitError) -> E + Clone,
+ {
+ TransformMapInitErr::new(self, f)
+ }
+}
+
+impl TransformExt for T where T: Transform {}
diff --git a/actix-service/src/fn_service.rs b/actix-service/src/fn_service.rs
index 230f437b..8c1a6f51 100644
--- a/actix-service/src/fn_service.rs
+++ b/actix-service/src/fn_service.rs
@@ -1,4 +1,4 @@
-use core::{future::Future, marker::PhantomData, task::Poll};
+use core::{future::Future, marker::PhantomData};
use crate::{ok, IntoService, IntoServiceFactory, Ready, Service, ServiceFactory};
@@ -15,8 +15,7 @@ where
/// Create `ServiceFactory` for function that can produce services
///
-/// # Example
-///
+/// # Examples
/// ```
/// use std::io;
/// use actix_service::{fn_factory, fn_service, Service, ServiceFactory};
@@ -62,11 +61,10 @@ where
/// Create `ServiceFactory` for function that accepts config argument and can produce services
///
-/// Any function that has following form `Fn(Config) -> Future