From 20f72cab3eae5fa6273d976f6949acec4b334e9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 17:07:54 +0100 Subject: [PATCH 01/15] Bump taiki-e/install-action from 2.20.3 to 2.20.15 (#355) Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.20.3 to 2.20.15. - [Release notes](https://github.com/taiki-e/install-action/releases) - [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/install-action/compare/v2.20.3...v2.20.15) --- updated-dependencies: - dependency-name: taiki-e/install-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-post-merge.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-post-merge.yml b/.github/workflows/ci-post-merge.yml index ff0a5fd9f..bb790489a 100644 --- a/.github/workflows/ci-post-merge.yml +++ b/.github/workflows/ci-post-merge.yml @@ -35,7 +35,7 @@ jobs: with: toolchain: nightly - - uses: taiki-e/install-action@v2.20.3 + - uses: taiki-e/install-action@v2.20.15 with: tool: cargo-hack @@ -77,7 +77,7 @@ jobs: with: toolchain: nightly - - uses: taiki-e/install-action@v2.20.3 + - uses: taiki-e/install-action@v2.20.15 with: tool: cargo-hack diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8571d0532..799846849 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: toolchain: ${{ matrix.version.version }} - name: Install cargo-hack - uses: taiki-e/install-action@v2.20.3 + uses: taiki-e/install-action@v2.20.15 with: tool: cargo-hack @@ -100,7 +100,7 @@ jobs: toolchain: ${{ matrix.version.version }} - name: Install cargo-hack - uses: taiki-e/install-action@v2.20.3 + uses: taiki-e/install-action@v2.20.15 with: tool: cargo-hack From fad631c448533f3c117dfab69df2bb7c4752b4cf Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Mon, 30 Oct 2023 04:07:57 +0530 Subject: [PATCH 02/15] fix: typo in actix-session cargo.toml file (#356) --- actix-session/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actix-session/Cargo.toml b/actix-session/Cargo.toml index d65ae3133..761bef971 100644 --- a/actix-session/Cargo.toml +++ b/actix-session/Cargo.toml @@ -5,7 +5,7 @@ authors = [ "Nikolay Kim ", "Luca Palmieri ", ] -description = "Session management for Actix We" +description = "Session management for Actix Web" keywords = ["http", "web", "framework", "async", "session"] homepage = "https://actix.rs" repository = "https://github.com/actix/actix-extras.git" From 077c6edced10b1c8fc9ad9f2209f2afb85da268e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:54:04 +0000 Subject: [PATCH 03/15] Bump taiki-e/install-action from 2.20.15 to 2.21.3 (#360) Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.20.15 to 2.21.3. - [Release notes](https://github.com/taiki-e/install-action/releases) - [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/install-action/compare/v2.20.15...v2.21.3) --- updated-dependencies: - dependency-name: taiki-e/install-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-post-merge.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-post-merge.yml b/.github/workflows/ci-post-merge.yml index bb790489a..6fa7d7db6 100644 --- a/.github/workflows/ci-post-merge.yml +++ b/.github/workflows/ci-post-merge.yml @@ -35,7 +35,7 @@ jobs: with: toolchain: nightly - - uses: taiki-e/install-action@v2.20.15 + - uses: taiki-e/install-action@v2.21.3 with: tool: cargo-hack @@ -77,7 +77,7 @@ jobs: with: toolchain: nightly - - uses: taiki-e/install-action@v2.20.15 + - uses: taiki-e/install-action@v2.21.3 with: tool: cargo-hack diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 799846849..0cbf6d55b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: toolchain: ${{ matrix.version.version }} - name: Install cargo-hack - uses: taiki-e/install-action@v2.20.15 + uses: taiki-e/install-action@v2.21.3 with: tool: cargo-hack @@ -100,7 +100,7 @@ jobs: toolchain: ${{ matrix.version.version }} - name: Install cargo-hack - uses: taiki-e/install-action@v2.20.15 + uses: taiki-e/install-action@v2.21.3 with: tool: cargo-hack From 471f07e27fd69ef500d2e45e7cdb81bce40c24d2 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 19:44:12 +0000 Subject: [PATCH 04/15] improve actix-cors docs --- actix-cors/src/builder.rs | 86 +++++++++++++++++++-------------------- justfile | 37 +++++++++++++++++ 2 files changed, 78 insertions(+), 45 deletions(-) create mode 100644 justfile diff --git a/actix-cors/src/builder.rs b/actix-cors/src/builder.rs index 51c89223c..a71a9255d 100644 --- a/actix-cors/src/builder.rs +++ b/actix-cors/src/builder.rs @@ -52,13 +52,20 @@ static ALL_METHODS_SET: Lazy> = Lazy::new(|| { /// The alternative [`Cors::permissive()`] constructor is available for local development, allowing /// all origins and headers, etc. **The permissive constructor should not be used in production.** /// +/// # Behavior +/// +/// In all cases, behavior for this crate follows the [Fetch Standard CORS protocol]. See that +/// document for information on exact semantics for configuration options and combinations. +/// /// # Errors +/// /// Errors surface in the middleware initialization phase. This means that, if you have logs enabled /// in Actix Web (using `env_logger` or other crate that exposes logs from the `log` crate), error /// messages will outline what is wrong with the CORS configuration in the server logs and the /// server will fail to start up or serve requests. /// /// # Example +/// /// ``` /// use actix_cors::Cors; /// use actix_web::http::header; @@ -72,6 +79,8 @@ static ALL_METHODS_SET: Lazy> = Lazy::new(|| { /// /// // `cors` can now be used in `App::wrap`. /// ``` +/// +/// [Fetch Standard CORS protocol]: https://fetch.spec.whatwg.org/#http-cors-protocol #[derive(Debug)] pub struct Cors { inner: Rc, @@ -79,7 +88,8 @@ pub struct Cors { } impl Cors { - /// A very permissive set of default for quick development. Not recommended for production use. + /// Constructs a very permissive set of defaults for quick development. (Not recommended for + /// production use.) /// /// *All* origins, methods, request headers and exposed headers allowed. Credentials supported. /// Max age 1 hour. Does not send wildcard. @@ -124,7 +134,7 @@ impl Cors { self } - /// Add an origin that is allowed to make requests. + /// Adds an origin that is allowed to make requests. /// /// This method allows specifying a finite set of origins to verify the value of the `Origin` /// request header. These are `origin-or-null` types in the [Fetch Standard]. @@ -177,7 +187,7 @@ impl Cors { self } - /// Determinate allowed origins by processing requests which didn't match any origins specified + /// Determinates allowed origins by processing requests which didn't match any origins specified /// in the `allowed_origin`. /// /// The function will receive two parameters, the Origin header value, and the `RequestHead` of @@ -209,14 +219,11 @@ impl Cors { self } - /// Set a list of methods which allowed origins can perform. + /// Sets a list of methods which allowed origins can perform. /// - /// These will be sent in the `Access-Control-Allow-Methods` response header as specified in - /// the [Fetch Standard CORS protocol]. + /// These will be sent in the `Access-Control-Allow-Methods` response header. /// /// This defaults to an empty set. - /// - /// [Fetch Standard CORS protocol]: https://fetch.spec.whatwg.org/#http-cors-protocol pub fn allowed_methods(mut self, methods: U) -> Cors where U: IntoIterator, @@ -279,16 +286,13 @@ impl Cors { self } - /// Set a list of request header field names which can be used when this resource is accessed by - /// allowed origins. + /// Sets a list of request header field names which can be used when this resource is accessed + /// by allowed origins. /// /// If `All` is set, whatever is requested by the client in `Access-Control-Request-Headers` - /// will be echoed back in the `Access-Control-Allow-Headers` header as specified in - /// the [Fetch Standard CORS protocol]. + /// will be echoed back in the `Access-Control-Allow-Headers` header. /// /// This defaults to an empty set. - /// - /// [Fetch Standard CORS protocol]: https://fetch.spec.whatwg.org/#http-cors-protocol pub fn allowed_headers(mut self, headers: U) -> Cors where U: IntoIterator, @@ -329,13 +333,11 @@ impl Cors { self } - /// Set a list of headers which are safe to expose to the API of a CORS API specification. - /// This corresponds to the `Access-Control-Expose-Headers` response header as specified in - /// the [Fetch Standard CORS protocol]. + /// Sets a list of headers which are safe to expose to the API of a CORS API specification. + /// + /// This corresponds to the `Access-Control-Expose-Headers` response header. /// /// This defaults to an empty set. - /// - /// [Fetch Standard CORS protocol]: https://fetch.spec.whatwg.org/#http-cors-protocol pub fn expose_headers(mut self, headers: U) -> Cors where U: IntoIterator, @@ -364,12 +366,11 @@ impl Cors { self } - /// Set a maximum time (in seconds) for which this CORS request may be cached. This value is set - /// as the `Access-Control-Max-Age` header as specified in the [Fetch Standard CORS protocol]. + /// Sets a maximum time (in seconds) for which this CORS request may be cached. + /// + /// This value is set as the `Access-Control-Max-Age` header. /// /// Pass a number (of seconds) or use None to disable sending max age header. - /// - /// [Fetch Standard CORS protocol]: https://fetch.spec.whatwg.org/#http-cors-protocol pub fn max_age(mut self, max_age: impl Into>) -> Cors { if let Some(cors) = cors(&mut self.inner, &self.error) { cors.max_age = max_age.into(); @@ -378,17 +379,17 @@ impl Cors { self } - /// Set to use wildcard origins. + /// Configures use of wildcard (`*`) origin in responses when appropriate. /// /// If send wildcard is set and the `allowed_origins` parameter is `All`, a wildcard /// `Access-Control-Allow-Origin` response header is sent, rather than the request’s /// `Origin` header. /// - /// This **CANNOT** be used in conjunction with `allowed_origins` set to `All` and - /// `allow_credentials` set to `true`. Depending on the mode of usage, this will either result - /// in an `CorsError::CredentialsWithWildcardOrigin` error during actix launch or runtime. + /// This option **CANNOT** be used in conjunction with a [credential + /// supported](Self::supports_credentials()) configuration. Doing so will result in an error + /// during server startup. /// - /// Defaults to `false`. + /// Defaults to disabled. pub fn send_wildcard(mut self) -> Cors { if let Some(cors) = cors(&mut self.inner, &self.error) { cors.send_wildcard = true; @@ -397,21 +398,16 @@ impl Cors { self } - /// Allows users to make authenticated requests + /// Allows users to make authenticated requests. /// /// If true, injects the `Access-Control-Allow-Credentials` header in responses. This allows - /// cookies and credentials to be submitted across domains as specified in - /// the [Fetch Standard CORS protocol]. + /// cookies and credentials to be submitted across domains. /// - /// This option cannot be used in conjunction with an `allowed_origin` set to `All` and - /// `send_wildcards` set to `true`. + /// This option **CANNOT** be used in conjunction with option cannot be used in conjunction + /// with [wildcard origins](Self::send_wildcard()) configured. Doing so will result in an error + /// during server startup. /// - /// Defaults to `false`. - /// - /// A server initialization error will occur if credentials are allowed, but the Origin is set - /// to send wildcards (`*`); this is not allowed by the CORS protocol. - /// - /// [Fetch Standard CORS protocol]: https://fetch.spec.whatwg.org/#http-cors-protocol + /// Defaults to disabled. pub fn supports_credentials(mut self) -> Cors { if let Some(cors) = cors(&mut self.inner, &self.error) { cors.supports_credentials = true; @@ -439,7 +435,7 @@ impl Cors { self } - /// Disable `Vary` header support. + /// Disables `Vary` header support. /// /// When enabled the header `Vary: Origin` will be returned as per the Fetch Standard /// implementation guidelines. @@ -457,12 +453,12 @@ impl Cors { self } - /// Disable support for preflight requests. + /// Disables preflight request handling. /// - /// When enabled CORS middleware automatically handles `OPTIONS` requests. - /// This is useful for application level middleware. + /// When enabled CORS middleware automatically handles `OPTIONS` requests. This is useful for + /// application level middleware. /// - /// By default *preflight* support is enabled. + /// By default, preflight support is enabled. pub fn disable_preflight(mut self) -> Cors { if let Some(cors) = cors(&mut self.inner, &self.error) { cors.preflight = false; @@ -480,7 +476,7 @@ impl Cors { /// and block requests based on pre-flight requests. Use this setting to allow cURL and other /// non-browser HTTP clients to function as normal, no matter what `Origin` the request has. /// - /// Defaults to `true`. + /// Defaults to true. pub fn block_on_origin_mismatch(mut self, block: bool) -> Cors { if let Some(cors) = cors(&mut self.inner, &self.error) { cors.block_on_origin_mismatch = block; diff --git a/justfile b/justfile new file mode 100644 index 000000000..8c41c8715 --- /dev/null +++ b/justfile @@ -0,0 +1,37 @@ +_list: + @just --list + +# Document crates in workspace. +doc: + RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace --all-features + +# Document crates in workspace and watch for changes. +doc-watch: + RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace --all-features --open + cargo watch -- RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace --all-features + +# Check for unintentional external type exposure on all crates in workspace. +check-external-types-all toolchain="+nightly": + #!/usr/bin/env bash + set -euo pipefail + exit=0 + for f in $(find . -mindepth 2 -maxdepth 2 -name Cargo.toml | grep -vE "\-codegen/|\-derive/|\-macros/"); do + if ! just check-external-types-manifest "$f" {{toolchain}}; then exit=1; fi + echo + echo + done + exit $exit + +# Check for unintentional external type exposure on all crates in workspace. +check-external-types-all-table toolchain="+nightly": + #!/usr/bin/env bash + set -euo pipefail + for f in $(find . -mindepth 2 -maxdepth 2 -name Cargo.toml | grep -vE "\-codegen/|\-derive/|\-macros/"); do + echo + echo "Checking for $f" + just check-external-types-manifest "$f" {{toolchain}} --output-format=markdown-table + done + +# Check for unintentional external type exposure on a crate. +check-external-types-manifest manifest_path toolchain="+nightly" *extra_args="": + cargo {{toolchain}} check-external-types --manifest-path "{{manifest_path}}" {{extra_args}} From ecd2016c09262f1ca7f6c22f2250ce33f83fa9b4 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 19:46:12 +0000 Subject: [PATCH 05/15] use standard attributes for all crates --- actix-identity/src/lib.rs | 3 +++ actix-limitation/src/lib.rs | 1 + actix-protobuf/src/lib.rs | 3 +++ actix-redis/src/lib.rs | 3 +++ actix-settings/src/lib.rs | 1 + actix-web-httpauth/src/lib.rs | 3 +++ 6 files changed, 14 insertions(+) diff --git a/actix-identity/src/lib.rs b/actix-identity/src/lib.rs index f88c9ca23..4b4a04202 100644 --- a/actix-identity/src/lib.rs +++ b/actix-identity/src/lib.rs @@ -89,6 +89,9 @@ #![forbid(unsafe_code)] #![deny(rust_2018_idioms, nonstandard_style, missing_docs)] #![warn(future_incompatible)] +#![doc(html_logo_url = "https://actix.rs/img/logo.png")] +#![doc(html_favicon_url = "https://actix.rs/favicon.ico")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod config; pub mod error; diff --git a/actix-limitation/src/lib.rs b/actix-limitation/src/lib.rs index 384f51dad..27d79d7b0 100644 --- a/actix-limitation/src/lib.rs +++ b/actix-limitation/src/lib.rs @@ -49,6 +49,7 @@ #![warn(future_incompatible, missing_docs, missing_debug_implementations)] #![doc(html_logo_url = "https://actix.rs/img/logo.png")] #![doc(html_favicon_url = "https://actix.rs/favicon.ico")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] use std::{borrow::Cow, fmt, sync::Arc, time::Duration}; diff --git a/actix-protobuf/src/lib.rs b/actix-protobuf/src/lib.rs index f2f7e0160..adfba4f43 100644 --- a/actix-protobuf/src/lib.rs +++ b/actix-protobuf/src/lib.rs @@ -3,6 +3,9 @@ #![forbid(unsafe_code)] #![deny(rust_2018_idioms, nonstandard_style)] #![warn(future_incompatible)] +#![doc(html_logo_url = "https://actix.rs/img/logo.png")] +#![doc(html_favicon_url = "https://actix.rs/favicon.ico")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] use std::{ fmt, diff --git a/actix-redis/src/lib.rs b/actix-redis/src/lib.rs index 6d0ca7c40..1d3856443 100644 --- a/actix-redis/src/lib.rs +++ b/actix-redis/src/lib.rs @@ -3,6 +3,9 @@ #![forbid(unsafe_code)] #![deny(rust_2018_idioms, nonstandard_style)] #![warn(future_incompatible)] +#![doc(html_logo_url = "https://actix.rs/img/logo.png")] +#![doc(html_favicon_url = "https://actix.rs/favicon.ico")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] use derive_more::{Display, Error, From}; pub use redis_async::{error::Error as RespError, resp::RespValue, resp_array}; diff --git a/actix-settings/src/lib.rs b/actix-settings/src/lib.rs index 3422549ff..2f26ab164 100644 --- a/actix-settings/src/lib.rs +++ b/actix-settings/src/lib.rs @@ -65,6 +65,7 @@ #![warn(future_incompatible, missing_docs, missing_debug_implementations)] #![doc(html_logo_url = "https://actix.rs/img/logo.png")] #![doc(html_favicon_url = "https://actix.rs/favicon.ico")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] use std::{ env, fmt, diff --git a/actix-web-httpauth/src/lib.rs b/actix-web-httpauth/src/lib.rs index 628ea8e73..56ee6962d 100644 --- a/actix-web-httpauth/src/lib.rs +++ b/actix-web-httpauth/src/lib.rs @@ -17,6 +17,9 @@ #![forbid(unsafe_code)] #![deny(rust_2018_idioms, nonstandard_style)] #![warn(future_incompatible, missing_docs)] +#![doc(html_logo_url = "https://actix.rs/img/logo.png")] +#![doc(html_favicon_url = "https://actix.rs/favicon.ico")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod extractors; pub mod headers; From 61f16c609a801bc5be65952b213af3177b0542c5 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 20:00:56 +0000 Subject: [PATCH 06/15] fix doc warnings --- actix-settings/src/settings/mod.rs | 2 +- actix-web-httpauth/src/extractors/config.rs | 2 +- actix-web-httpauth/src/headers/authorization/scheme/bearer.rs | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/actix-settings/src/settings/mod.rs b/actix-settings/src/settings/mod.rs index 839649e14..514b01fa3 100644 --- a/actix-settings/src/settings/mod.rs +++ b/actix-settings/src/settings/mod.rs @@ -26,7 +26,7 @@ pub struct ActixSettings { /// Marker of intended deployment environment. pub mode: Mode, - /// True if the [`Compress`](actix_web::middleware::Compress) middleware should be enabled. + /// True if the `Compress` middleware should be enabled. pub enable_compression: bool, /// True if the [`Logger`](actix_web::middleware::Logger) middleware should be enabled. diff --git a/actix-web-httpauth/src/extractors/config.rs b/actix-web-httpauth/src/extractors/config.rs index 761e989d1..d1d7d89b3 100644 --- a/actix-web-httpauth/src/extractors/config.rs +++ b/actix-web-httpauth/src/extractors/config.rs @@ -2,7 +2,7 @@ use super::AuthenticationError; use crate::headers::www_authenticate::Challenge; /// Trait implemented for types that provides configuration for the authentication -/// [extractors](super::AuthExtractor). +/// [extractors](crate::extractors). pub trait AuthExtractorConfig { /// Associated challenge type. type Inner: Challenge; diff --git a/actix-web-httpauth/src/headers/authorization/scheme/bearer.rs b/actix-web-httpauth/src/headers/authorization/scheme/bearer.rs index 13068b67f..842c9be76 100644 --- a/actix-web-httpauth/src/headers/authorization/scheme/bearer.rs +++ b/actix-web-httpauth/src/headers/authorization/scheme/bearer.rs @@ -9,9 +9,10 @@ use crate::headers::authorization::{errors::ParseError, scheme::Scheme}; /// Credentials for `Bearer` authentication scheme, defined in [RFC 6750]. /// -/// Should be used in combination with [`Authorization`](super::Authorization) header. +/// Should be used in combination with [`Authorization`] header. /// /// [RFC 6750]: https://tools.ietf.org/html/rfc6750 +/// [`Authorization`]: crate::headers::authorization::Authorization #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] pub struct Bearer { token: Cow<'static, str>, From 373a89a97813e2e53b3d4a1abffc16d0b8308714 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 20:02:50 +0000 Subject: [PATCH 07/15] fix warnings on doc upload workflow --- .github/workflows/upload-doc.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/upload-doc.yml b/.github/workflows/upload-doc.yml index 3abf6d1c8..ac0ec3f94 100644 --- a/.github/workflows/upload-doc.yml +++ b/.github/workflows/upload-doc.yml @@ -1,9 +1,11 @@ name: Upload Documentation on: - push: { branches: [master] } + push: + branches: [master] -permissions: { contents: write } +permissions: + contents: write concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -18,10 +20,11 @@ jobs: - name: Install Rust (nightly) uses: actions-rust-lang/setup-rust-toolchain@v1.5.0 - with: { toolchain: nightly } + with: + toolchain: nightly - name: Build Docs - run: cargo doc --workspace --all-features --no-deps + run: cargo doc --no-deps --workspace --all-features - name: Tweak HTML run: echo '' > target/doc/index.html @@ -29,6 +32,5 @@ jobs: - name: Deploy to GitHub Pages uses: JamesIves/github-pages-deploy-action@v4.4.3 with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BRANCH: gh-pages - FOLDER: target/doc + folder: target/doc + branch: gh-pages From 76d931317161bda8b32671ea25ca41378043d4f6 Mon Sep 17 00:00:00 2001 From: Heki <75025611+LinuxHeki@users.noreply.github.com> Date: Fri, 3 Nov 2023 20:16:31 +0000 Subject: [PATCH 08/15] Allow ActixSettings to be applied to HttpServer in actix-settings (#321) * allow other settings objects to be applied * update changelog * update changelog --------- Co-authored-by: LinuxHeki Co-authored-by: Rob Ede --- actix-settings/CHANGES.md | 2 ++ actix-settings/src/lib.rs | 54 +++++++++++++++++++++++---------------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/actix-settings/CHANGES.md b/actix-settings/CHANGES.md index 8efdeae48..dbb4d3f25 100644 --- a/actix-settings/CHANGES.md +++ b/actix-settings/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +- The `ApplySettings` trait now includes a type parameter, allowing multiple types to be implemented per configuration target. +- Implement `ApplySettings` for `ActixSettings`. - Rename `AtError => Error`. - Remove `AtResult` type alias. - Update `toml` dependency to `0.8`. diff --git a/actix-settings/src/lib.rs b/actix-settings/src/lib.rs index 2f26ab164..ba558331f 100644 --- a/actix-settings/src/lib.rs +++ b/actix-settings/src/lib.rs @@ -243,17 +243,13 @@ where } /// Extension trait for applying parsed settings to the server object. -pub trait ApplySettings { - /// Apply a [`BasicSettings`] value to `self`. - /// - /// [`BasicSettings`]: ./struct.BasicSettings.html +pub trait ApplySettings { + /// Apply some settings object value to `self`. #[must_use] - fn apply_settings(self, settings: &BasicSettings) -> Self - where - A: de::DeserializeOwned; + fn apply_settings(self, settings: &S) -> Self; } -impl ApplySettings for HttpServer +impl ApplySettings for HttpServer where F: Fn() -> I + Send + Clone + 'static, I: IntoServiceFactory, @@ -264,51 +260,48 @@ where S::Future: 'static, B: MessageBody + 'static, { - fn apply_settings(mut self, settings: &BasicSettings) -> Self - where - A: de::DeserializeOwned, - { - if settings.actix.tls.enabled { + fn apply_settings(mut self, settings: &ActixSettings) -> Self { + if settings.tls.enabled { // for Address { host, port } in &settings.actix.hosts { // self = self.bind(format!("{}:{}", host, port)) // .unwrap(/*TODO*/); // } todo!("[ApplySettings] TLS support has not been implemented yet."); } else { - for Address { host, port } in &settings.actix.hosts { + for Address { host, port } in &settings.hosts { self = self.bind(format!("{host}:{port}")) .unwrap(/*TODO*/); } } - self = match settings.actix.num_workers { + self = match settings.num_workers { NumWorkers::Default => self, NumWorkers::Manual(n) => self.workers(n), }; - self = match settings.actix.backlog { + self = match settings.backlog { Backlog::Default => self, Backlog::Manual(n) => self.backlog(n as u32), }; - self = match settings.actix.max_connections { + self = match settings.max_connections { MaxConnections::Default => self, MaxConnections::Manual(n) => self.max_connections(n), }; - self = match settings.actix.max_connection_rate { + self = match settings.max_connection_rate { MaxConnectionRate::Default => self, MaxConnectionRate::Manual(n) => self.max_connection_rate(n), }; - self = match settings.actix.keep_alive { + self = match settings.keep_alive { KeepAlive::Default => self, KeepAlive::Disabled => self.keep_alive(ActixKeepAlive::Disabled), KeepAlive::Os => self.keep_alive(ActixKeepAlive::Os), KeepAlive::Seconds(n) => self.keep_alive(Duration::from_secs(n as u64)), }; - self = match settings.actix.client_timeout { + self = match settings.client_timeout { Timeout::Default => self, Timeout::Milliseconds(n) => { self.client_request_timeout(Duration::from_millis(n as u64)) @@ -316,7 +309,7 @@ where Timeout::Seconds(n) => self.client_request_timeout(Duration::from_secs(n as u64)), }; - self = match settings.actix.client_shutdown { + self = match settings.client_shutdown { Timeout::Default => self, Timeout::Milliseconds(n) => { self.client_disconnect_timeout(Duration::from_millis(n as u64)) @@ -324,7 +317,7 @@ where Timeout::Seconds(n) => self.client_disconnect_timeout(Duration::from_secs(n as u64)), }; - self = match settings.actix.shutdown_timeout { + self = match settings.shutdown_timeout { Timeout::Default => self, Timeout::Milliseconds(_) => self.shutdown_timeout(1), Timeout::Seconds(n) => self.shutdown_timeout(n as u64), @@ -334,6 +327,23 @@ where } } +impl ApplySettings> for HttpServer +where + F: Fn() -> I + Send + Clone + 'static, + I: IntoServiceFactory, + S: ServiceFactory + 'static, + S::Error: Into + 'static, + S::InitError: fmt::Debug, + S::Response: Into> + 'static, + S::Future: 'static, + B: MessageBody + 'static, + A: de::DeserializeOwned, +{ + fn apply_settings(self, settings: &BasicSettings) -> Self { + self.apply_settings(&settings.actix) + } +} + #[cfg(test)] mod tests { use actix_web::App; From 73b2aac6d677d464a4594e5fdb364a9072dc1755 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 20:23:55 +0000 Subject: [PATCH 09/15] make Settings::from_default_template infallible --- actix-settings/CHANGES.md | 1 + actix-settings/src/lib.rs | 69 +++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/actix-settings/CHANGES.md b/actix-settings/CHANGES.md index dbb4d3f25..9a5e99379 100644 --- a/actix-settings/CHANGES.md +++ b/actix-settings/CHANGES.md @@ -4,6 +4,7 @@ - The `ApplySettings` trait now includes a type parameter, allowing multiple types to be implemented per configuration target. - Implement `ApplySettings` for `ActixSettings`. +- `BasicSettings::from_default_template()` is now infallible. - Rename `AtError => Error`. - Remove `AtResult` type alias. - Update `toml` dependency to `0.8`. diff --git a/actix-settings/src/lib.rs b/actix-settings/src/lib.rs index ba558331f..33c46b630 100644 --- a/actix-settings/src/lib.rs +++ b/actix-settings/src/lib.rs @@ -155,14 +155,11 @@ where } /// Parse an instance of `Self` straight from the default TOML template. - // TODO: make infallible - // TODO: consider "template" rename - pub fn from_default_template() -> AsResult { - Self::from_template(Self::DEFAULT_TOML_TEMPLATE) + pub fn from_default_template() -> Self { + Self::from_template(Self::DEFAULT_TOML_TEMPLATE).unwrap() } /// Parse an instance of `Self` straight from the default TOML template. - // TODO: consider "template" rename pub fn from_template(template: &str) -> AsResult { Ok(toml::from_str(template)?) } @@ -266,7 +263,7 @@ where // self = self.bind(format!("{}:{}", host, port)) // .unwrap(/*TODO*/); // } - todo!("[ApplySettings] TLS support has not been implemented yet."); + unimplemented!("[ApplySettings] TLS support has not been implemented yet."); } else { for Address { host, port } in &settings.hosts { self = self.bind(format!("{host}:{port}")) @@ -358,7 +355,7 @@ mod tests { #[test] fn override_field_hosts() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!( settings.actix.hosts, @@ -394,7 +391,7 @@ mod tests { #[test] fn override_field_with_env_var_hosts() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!( settings.actix.hosts, @@ -432,7 +429,7 @@ mod tests { #[test] fn override_field_mode() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.mode, Mode::Development); Settings::override_field(&mut settings.actix.mode, "production").unwrap(); assert_eq!(settings.actix.mode, Mode::Production); @@ -440,7 +437,7 @@ mod tests { #[test] fn override_field_with_env_var_mode() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.mode, Mode::Development); std::env::set_var("OVERRIDE__MODE", "production"); Settings::override_field_with_env_var(&mut settings.actix.mode, "OVERRIDE__MODE").unwrap(); @@ -449,7 +446,7 @@ mod tests { #[test] fn override_field_enable_compression() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert!(settings.actix.enable_compression); Settings::override_field(&mut settings.actix.enable_compression, "false").unwrap(); assert!(!settings.actix.enable_compression); @@ -457,7 +454,7 @@ mod tests { #[test] fn override_field_with_env_var_enable_compression() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert!(settings.actix.enable_compression); std::env::set_var("OVERRIDE__ENABLE_COMPRESSION", "false"); Settings::override_field_with_env_var( @@ -470,7 +467,7 @@ mod tests { #[test] fn override_field_enable_log() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert!(settings.actix.enable_log); Settings::override_field(&mut settings.actix.enable_log, "false").unwrap(); assert!(!settings.actix.enable_log); @@ -478,7 +475,7 @@ mod tests { #[test] fn override_field_with_env_var_enable_log() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert!(settings.actix.enable_log); std::env::set_var("OVERRIDE__ENABLE_LOG", "false"); Settings::override_field_with_env_var( @@ -491,7 +488,7 @@ mod tests { #[test] fn override_field_num_workers() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.num_workers, NumWorkers::Default); Settings::override_field(&mut settings.actix.num_workers, "42").unwrap(); assert_eq!(settings.actix.num_workers, NumWorkers::Manual(42)); @@ -499,7 +496,7 @@ mod tests { #[test] fn override_field_with_env_var_num_workers() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.num_workers, NumWorkers::Default); std::env::set_var("OVERRIDE__NUM_WORKERS", "42"); Settings::override_field_with_env_var( @@ -512,7 +509,7 @@ mod tests { #[test] fn override_field_backlog() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.backlog, Backlog::Default); Settings::override_field(&mut settings.actix.backlog, "42").unwrap(); assert_eq!(settings.actix.backlog, Backlog::Manual(42)); @@ -520,7 +517,7 @@ mod tests { #[test] fn override_field_with_env_var_backlog() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.backlog, Backlog::Default); std::env::set_var("OVERRIDE__BACKLOG", "42"); Settings::override_field_with_env_var(&mut settings.actix.backlog, "OVERRIDE__BACKLOG") @@ -530,7 +527,7 @@ mod tests { #[test] fn override_field_max_connections() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.max_connections, MaxConnections::Default); Settings::override_field(&mut settings.actix.max_connections, "42").unwrap(); assert_eq!(settings.actix.max_connections, MaxConnections::Manual(42)); @@ -538,7 +535,7 @@ mod tests { #[test] fn override_field_with_env_var_max_connections() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.max_connections, MaxConnections::Default); std::env::set_var("OVERRIDE__MAX_CONNECTIONS", "42"); Settings::override_field_with_env_var( @@ -551,7 +548,7 @@ mod tests { #[test] fn override_field_max_connection_rate() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!( settings.actix.max_connection_rate, MaxConnectionRate::Default @@ -565,7 +562,7 @@ mod tests { #[test] fn override_field_with_env_var_max_connection_rate() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!( settings.actix.max_connection_rate, MaxConnectionRate::Default @@ -584,7 +581,7 @@ mod tests { #[test] fn override_field_keep_alive() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.keep_alive, KeepAlive::Default); Settings::override_field(&mut settings.actix.keep_alive, "42 seconds").unwrap(); assert_eq!(settings.actix.keep_alive, KeepAlive::Seconds(42)); @@ -592,7 +589,7 @@ mod tests { #[test] fn override_field_with_env_var_keep_alive() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.keep_alive, KeepAlive::Default); std::env::set_var("OVERRIDE__KEEP_ALIVE", "42 seconds"); Settings::override_field_with_env_var( @@ -605,7 +602,7 @@ mod tests { #[test] fn override_field_client_timeout() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.client_timeout, Timeout::Default); Settings::override_field(&mut settings.actix.client_timeout, "42 seconds").unwrap(); assert_eq!(settings.actix.client_timeout, Timeout::Seconds(42)); @@ -613,7 +610,7 @@ mod tests { #[test] fn override_field_with_env_var_client_timeout() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.client_timeout, Timeout::Default); std::env::set_var("OVERRIDE__CLIENT_TIMEOUT", "42 seconds"); Settings::override_field_with_env_var( @@ -626,7 +623,7 @@ mod tests { #[test] fn override_field_client_shutdown() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.client_shutdown, Timeout::Default); Settings::override_field(&mut settings.actix.client_shutdown, "42 seconds").unwrap(); assert_eq!(settings.actix.client_shutdown, Timeout::Seconds(42)); @@ -634,7 +631,7 @@ mod tests { #[test] fn override_field_with_env_var_client_shutdown() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.client_shutdown, Timeout::Default); std::env::set_var("OVERRIDE__CLIENT_SHUTDOWN", "42 seconds"); Settings::override_field_with_env_var( @@ -647,7 +644,7 @@ mod tests { #[test] fn override_field_shutdown_timeout() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.shutdown_timeout, Timeout::Default); Settings::override_field(&mut settings.actix.shutdown_timeout, "42 seconds").unwrap(); assert_eq!(settings.actix.shutdown_timeout, Timeout::Seconds(42)); @@ -655,7 +652,7 @@ mod tests { #[test] fn override_field_with_env_var_shutdown_timeout() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!(settings.actix.shutdown_timeout, Timeout::Default); std::env::set_var("OVERRIDE__SHUTDOWN_TIMEOUT", "42 seconds"); Settings::override_field_with_env_var( @@ -668,7 +665,7 @@ mod tests { #[test] fn override_field_tls_enabled() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert!(!settings.actix.tls.enabled); Settings::override_field(&mut settings.actix.tls.enabled, "true").unwrap(); assert!(settings.actix.tls.enabled); @@ -676,7 +673,7 @@ mod tests { #[test] fn override_field_with_env_var_tls_enabled() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert!(!settings.actix.tls.enabled); std::env::set_var("OVERRIDE__TLS_ENABLED", "true"); Settings::override_field_with_env_var( @@ -689,7 +686,7 @@ mod tests { #[test] fn override_field_tls_certificate() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!( settings.actix.tls.certificate, Path::new("path/to/cert/cert.pem") @@ -707,7 +704,7 @@ mod tests { #[test] fn override_field_with_env_var_tls_certificate() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!( settings.actix.tls.certificate, Path::new("path/to/cert/cert.pem") @@ -729,7 +726,7 @@ mod tests { #[test] fn override_field_tls_private_key() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!( settings.actix.tls.private_key, Path::new("path/to/cert/key.pem") @@ -747,7 +744,7 @@ mod tests { #[test] fn override_field_with_env_var_tls_private_key() { - let mut settings = Settings::from_default_template().unwrap(); + let mut settings = Settings::from_default_template(); assert_eq!( settings.actix.tls.private_key, Path::new("path/to/cert/key.pem") From 11046d7663d259037395c2c9679ad3bb4e4985e6 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 20:24:04 +0000 Subject: [PATCH 10/15] chore(actix-settings): prepare release 0.7.0 --- actix-settings/CHANGES.md | 2 ++ actix-settings/Cargo.toml | 2 +- actix-settings/README.md | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/actix-settings/CHANGES.md b/actix-settings/CHANGES.md index 9a5e99379..1b784f7c0 100644 --- a/actix-settings/CHANGES.md +++ b/actix-settings/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.7.0 + - The `ApplySettings` trait now includes a type parameter, allowing multiple types to be implemented per configuration target. - Implement `ApplySettings` for `ActixSettings`. - `BasicSettings::from_default_template()` is now infallible. diff --git a/actix-settings/Cargo.toml b/actix-settings/Cargo.toml index 781dc8e4e..c67a30f6a 100644 --- a/actix-settings/Cargo.toml +++ b/actix-settings/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-settings" -version = "0.6.0" +version = "0.7.0" authors = [ "Joey Ezechiels ", "Rob Ede ", diff --git a/actix-settings/README.md b/actix-settings/README.md index c26b98bca..efcdca229 100644 --- a/actix-settings/README.md +++ b/actix-settings/README.md @@ -3,9 +3,9 @@ > Easily manage Actix Web's settings from a TOML file and environment variables. [![crates.io](https://img.shields.io/crates/v/actix-settings?label=latest)](https://crates.io/crates/actix-settings) -[![Documentation](https://docs.rs/actix-settings/badge.svg?version=0.6.0)](https://docs.rs/actix-settings/0.6.0) +[![Documentation](https://docs.rs/actix-settings/badge.svg?version=0.7.0)](https://docs.rs/actix-settings/0.7.0) ![Apache 2.0 or MIT licensed](https://img.shields.io/crates/l/actix-settings) -[![Dependency Status](https://deps.rs/crate/actix-settings/0.6.0/status.svg)](https://deps.rs/crate/actix-settings/0.6.0) +[![Dependency Status](https://deps.rs/crate/actix-settings/0.7.0/status.svg)](https://deps.rs/crate/actix-settings/0.7.0) ## Documentation & Resources From 31540f8e4b10181907efb45429882d402f03dc8a Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 20:30:00 +0000 Subject: [PATCH 11/15] chore(actix-settings): prepare release 0.7.1 --- actix-settings/CHANGES.md | 4 ++++ actix-settings/Cargo.toml | 2 +- actix-settings/README.md | 4 ++-- actix-settings/src/lib.rs | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/actix-settings/CHANGES.md b/actix-settings/CHANGES.md index 1b784f7c0..492e44c17 100644 --- a/actix-settings/CHANGES.md +++ b/actix-settings/CHANGES.md @@ -2,6 +2,10 @@ ## Unreleased +## 0.7.1 + +- Fix doc examples. + ## 0.7.0 - The `ApplySettings` trait now includes a type parameter, allowing multiple types to be implemented per configuration target. diff --git a/actix-settings/Cargo.toml b/actix-settings/Cargo.toml index c67a30f6a..7da827e64 100644 --- a/actix-settings/Cargo.toml +++ b/actix-settings/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-settings" -version = "0.7.0" +version = "0.7.1" authors = [ "Joey Ezechiels ", "Rob Ede ", diff --git a/actix-settings/README.md b/actix-settings/README.md index efcdca229..cbe71fa90 100644 --- a/actix-settings/README.md +++ b/actix-settings/README.md @@ -3,9 +3,9 @@ > Easily manage Actix Web's settings from a TOML file and environment variables. [![crates.io](https://img.shields.io/crates/v/actix-settings?label=latest)](https://crates.io/crates/actix-settings) -[![Documentation](https://docs.rs/actix-settings/badge.svg?version=0.7.0)](https://docs.rs/actix-settings/0.7.0) +[![Documentation](https://docs.rs/actix-settings/badge.svg?version=0.7.1)](https://docs.rs/actix-settings/0.7.1) ![Apache 2.0 or MIT licensed](https://img.shields.io/crates/l/actix-settings) -[![Dependency Status](https://deps.rs/crate/actix-settings/0.7.0/status.svg)](https://deps.rs/crate/actix-settings/0.7.0) +[![Dependency Status](https://deps.rs/crate/actix-settings/0.7.1/status.svg)](https://deps.rs/crate/actix-settings/0.7.1) ## Documentation & Resources diff --git a/actix-settings/src/lib.rs b/actix-settings/src/lib.rs index 33c46b630..d837759af 100644 --- a/actix-settings/src/lib.rs +++ b/actix-settings/src/lib.rs @@ -194,7 +194,7 @@ where /// use actix_settings::{Settings, Mode}; /// /// # fn inner() -> Result<(), actix_settings::Error> { - /// let mut settings = Settings::from_default_template()?; + /// let mut settings = Settings::from_default_template(); /// assert_eq!(settings.actix.mode, Mode::Development); /// /// Settings::override_field(&mut settings.actix.mode, "production")?; @@ -219,7 +219,7 @@ where /// std::env::set_var("OVERRIDE__MODE", "production"); /// /// # fn inner() -> Result<(), actix_settings::Error> { - /// let mut settings = Settings::from_default_template()?; + /// let mut settings = Settings::from_default_template(); /// assert_eq!(settings.actix.mode, Mode::Development); /// /// Settings::override_field_with_env_var(&mut settings.actix.mode, "OVERRIDE__MODE")?; From 4d79d263efd2f7322a1c402841be983aebab1e69 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 20:37:18 +0000 Subject: [PATCH 12/15] update readme versions --- README.md | 56 +++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index b2c830bfd..71a4695f3 100644 --- a/README.md +++ b/README.md @@ -9,16 +9,16 @@ ## Crates by @actix -| Crate | | | -| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -| [actix-cors] | [![crates.io](https://img.shields.io/crates/v/actix-cors?label=latest)](https://crates.io/crates/actix-cors) [![dependency status](https://deps.rs/crate/actix-cors/0.6.4/status.svg)](https://deps.rs/crate/actix-cors/0.6.4) | Cross-Origin Resource Sharing (CORS) controls. | -| [actix-identity] | [![crates.io](https://img.shields.io/crates/v/actix-identity?label=latest)](https://crates.io/crates/actix-identity) [![dependency status](https://deps.rs/crate/actix-identity/0.6.0/status.svg)](https://deps.rs/crate/actix-identity/0.6.0) | Identity management. | -| [actix-limitation] | [![crates.io](https://img.shields.io/crates/v/actix-limitation?label=latest)](https://crates.io/crates/actix-limitation) [![dependency status](https://deps.rs/crate/actix-limitation/0.5.1/status.svg)](https://deps.rs/crate/actix-limitation/0.5.1) | Rate-limiting using a fixed window counter for arbitrary keys, backed by Redis. | -| [actix-protobuf] | [![crates.io](https://img.shields.io/crates/v/actix-protobuf?label=latest)](https://crates.io/crates/actix-protobuf) [![dependency status](https://deps.rs/crate/actix-protobuf/0.10.0/status.svg)](https://deps.rs/crate/actix-protobuf/0.10.0) | Protobuf payload extractor. | -| [actix-redis] | [![crates.io](https://img.shields.io/crates/v/actix-redis?label=latest)](https://crates.io/crates/actix-redis) [![dependency status](https://deps.rs/crate/actix-redis/0.13.0/status.svg)](https://deps.rs/crate/actix-redis/0.13.0) | Actor-based Redis client. | -| [actix-session] | [![crates.io](https://img.shields.io/crates/v/actix-session?label=latest)](https://crates.io/crates/actix-session) [![dependency status](https://deps.rs/crate/actix-session/0.8.0/status.svg)](https://deps.rs/crate/actix-session/0.8.0) | Session management. | -| [actix-settings] | [![crates.io](https://img.shields.io/crates/v/actix-settings?label=latest)](https://crates.io/crates/actix-settings) [![dependency status](https://deps.rs/crate/actix-settings/0.6.0/status.svg)](https://deps.rs/crate/actix-settings/0.6.0) | Easily manage Actix Web's settings from a TOML file and environment variables. | -| [actix-web-httpauth] | [![crates.io](https://img.shields.io/crates/v/actix-web-httpauth?label=latest)](https://crates.io/crates/actix-web-httpauth) [![dependency status](https://deps.rs/crate/actix-web-httpauth/0.8.1/status.svg)](https://deps.rs/crate/actix-web-httpauth/0.8.1) | HTTP authentication schemes. | +| Crate | | | +| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +| [actix-cors] | [![crates.io](https://img.shields.io/crates/v/actix-cors?label=latest)](https://crates.io/crates/actix-cors) [![dependency status](https://deps.rs/crate/actix-cors/latest/status.svg)](https://deps.rs/crate/actix-cors) | Cross-Origin Resource Sharing (CORS) controls. | +| [actix-identity] | [![crates.io](https://img.shields.io/crates/v/actix-identity?label=latest)](https://crates.io/crates/actix-identity) [![dependency status](https://deps.rs/crate/actix-identity/latest/status.svg)](https://deps.rs/crate/actix-identity) | Identity management. | +| [actix-limitation] | [![crates.io](https://img.shields.io/crates/v/actix-limitation?label=latest)](https://crates.io/crates/actix-limitation) [![dependency status](https://deps.rs/crate/actix-limitation/latest/status.svg)](https://deps.rs/crate/actix-limitation) | Rate-limiting using a fixed window counter for arbitrary keys, backed by Redis. | +| [actix-protobuf] | [![crates.io](https://img.shields.io/crates/v/actix-protobuf?label=latest)](https://crates.io/crates/actix-protobuf) [![dependency status](https://deps.rs/crate/actix-protobuf/latest/status.svg)](https://deps.rs/crate/actix-protobuf) | Protobuf payload extractor. | +| [actix-redis] | [![crates.io](https://img.shields.io/crates/v/actix-redis?label=latest)](https://crates.io/crates/actix-redis) [![dependency status](https://deps.rs/crate/actix-redis/latest/status.svg)](https://deps.rs/crate/actix-redis) | Actor-based Redis client. | +| [actix-session] | [![crates.io](https://img.shields.io/crates/v/actix-session?label=latest)](https://crates.io/crates/actix-session) [![dependency status](https://deps.rs/crate/actix-session/latest/status.svg)](https://deps.rs/crate/actix-session) | Session management. | +| [actix-settings] | [![crates.io](https://img.shields.io/crates/v/actix-settings?label=latest)](https://crates.io/crates/actix-settings) [![dependency status](https://deps.rs/crate/actix-settings/latest/status.svg)](https://deps.rs/crate/actix-settings) | Easily manage Actix Web's settings from a TOML file and environment variables. | +| [actix-web-httpauth] | [![crates.io](https://img.shields.io/crates/v/actix-web-httpauth?label=latest)](https://crates.io/crates/actix-web-httpauth) [![dependency status](https://deps.rs/crate/actix-web-httpauth/latest/status.svg)](https://deps.rs/crate/actix-web-httpauth) | HTTP authentication schemes. | --- @@ -26,24 +26,24 @@ These crates are provided by the community. -| Crate | | | -| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| [actix-web-lab] | [![crates.io](https://img.shields.io/crates/v/actix-web-lab?label=latest)][actix-web-lab] [![dependency status](https://deps.rs/crate/actix-web-lab/0.19.1/status.svg)](https://deps.rs/crate/actix-web-lab/0.19.1) | Experimental extractors, middleware, and other extras for possible inclusion in Actix Web. | -| [actix-multipart-extract] | [![crates.io](https://img.shields.io/crates/v/actix-multipart-extract?label=latest)][actix-multipart-extract] [![dependency status](https://deps.rs/crate/actix-multipart-extract/0.1.5/status.svg)](https://deps.rs/crate/actix-multipart-extract/0.1.5) | Better multipart form support for Actix Web. | -| [actix-form-data] | [![crates.io](https://img.shields.io/crates/v/actix-form-data?label=latest)][actix-form-data] [![dependency status](https://deps.rs/crate/actix-form-data/0.7.0-beta.4/status.svg)](https://deps.rs/crate/actix-form-data/0.7.0-beta.4) | Multipart form data from actix multipart streams | -| [actix-governor] | [![crates.io](https://img.shields.io/crates/v/actix-governor?label=latest)][actix-governor] [![dependency status](https://deps.rs/crate/actix-governor/0.5.1/status.svg)](https://deps.rs/crate/actix-governor/0.5.1) | Rate-limiting backed by governor. | -| [actix-casbin] | [![crates.io](https://img.shields.io/crates/v/actix-casbin?label=latest)][actix-casbin] [![dependency status](https://deps.rs/crate/actix-casbin/0.4.2/status.svg)](https://deps.rs/crate/actix-casbin/0.4.2) | Authorization library that supports access control models like ACL, RBAC & ABAC. | -| [actix-ip-filter] | [![crates.io](https://img.shields.io/crates/v/actix-ip-filter?label=latest)][actix-ip-filter] [![dependency status](https://deps.rs/crate/actix-ip-filter/0.3.1/status.svg)](https://deps.rs/crate/actix-ip-filter/0.3.1) | IP address filter. Supports glob patterns. | -| [actix-web-static-files] | [![crates.io](https://img.shields.io/crates/v/actix-web-static-files?label=latest)][actix-web-static-files] [![dependency status](https://deps.rs/crate/actix-web-static-files/4.0.1/status.svg)](https://deps.rs/crate/actix-web-static-files/4.0.1) | Static files as embedded resources. | -| [actix-web-grants] | [![crates.io](https://img.shields.io/crates/v/actix-web-grants?label=latest)][actix-web-grants] [![dependency status](https://deps.rs/crate/actix-web-grants/3.0.2/status.svg)](https://deps.rs/crate/actix-web-grants/3.0.2) | Extension for validating user authorities. | -| [aliri_actix] | [![crates.io](https://img.shields.io/crates/v/aliri_actix?label=latest)][aliri_actix] [![dependency status](https://deps.rs/crate/aliri_actix/0.9.0/status.svg)](https://deps.rs/crate/aliri_actix/0.9.0) | Endpoint authorization and authentication using scoped OAuth2 JWT tokens. | -| [actix-web-flash-messages] | [![crates.io](https://img.shields.io/crates/v/actix-web-flash-messages?label=latest)][actix-web-flash-messages] [![dependency status](https://deps.rs/crate/actix-web-flash-messages/0.4.2/status.svg)](https://deps.rs/crate/actix-web-flash-messages/0.4.2) | Support for flash messages/one-time notifications in `actix-web`. | -| [awmp] | [![crates.io](https://img.shields.io/crates/v/awmp?label=latest)][awmp] [![dependency status](https://deps.rs/crate/awmp/0.8.1/status.svg)](https://deps.rs/crate/awmp/0.8.1) | An easy to use wrapper around multipart fields for Actix Web. | -| [tracing-actix-web] | [![crates.io](https://img.shields.io/crates/v/tracing-actix-web?label=latest)][tracing-actix-web] [![dependency status](https://deps.rs/crate/tracing-actix-web/0.7.6/status.svg)](https://deps.rs/crate/tracing-actix-web/0.7.6) | A middleware to collect telemetry data from applications built on top of the Actix Web framework. | -| [actix-ws] | [![crates.io](https://img.shields.io/crates/v/actix-ws?label=latest)][actix-ws] [![dependency status](https://deps.rs/crate/actix-ws/0.2.5/status.svg)](https://deps.rs/crate/actix-ws/0.2.5) | Actor-less WebSockets for the Actix Runtime. | -| [actix-hash] | [![crates.io](https://img.shields.io/crates/v/actix-hash?label=latest)][actix-hash] [![dependency status](https://deps.rs/crate/actix-hash/0.5.0/status.svg)](https://deps.rs/crate/actix-hash/0.5.0) | Hashing utilities for Actix Web. | -| [actix-bincode] | ![crates.io](https://img.shields.io/crates/v/actix-bincode?label=latest) [![dependency status](https://deps.rs/crate/actix-bincode/0.2.2/status.svg)](https://deps.rs/crate/actix-bincode/0.2.2) | Bincode payload extractor for Actix Web | -| [sentinel-actix] | ![crates.io](https://img.shields.io/crates/v/sentinel-actix?label=latest) [![dependency status](https://deps.rs/crate/sentinel-actix/0.1.0/status.svg)](https://deps.rs/crate/sentinel-actix/0.1.0) | General and flexible protection for Actix Web | +| Crate | | | +| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | +| [actix-web-lab] | [![crates.io](https://img.shields.io/crates/v/actix-web-lab?label=latest)][actix-web-lab] [![dependency status](https://deps.rs/crate/actix-web-lab/latest/status.svg)](https://deps.rs/crate/actix-web-lab) | Experimental extractors, middleware, and other extras for possible inclusion in Actix Web. | +| [actix-multipart-extract] | [![crates.io](https://img.shields.io/crates/v/actix-multipart-extract?label=latest)][actix-multipart-extract] [![dependency status](https://deps.rs/crate/actix-multipart-extract/latest/status.svg)](https://deps.rs/crate/actix-multipart-extract) | Better multipart form support for Actix Web. | +| [actix-form-data] | [![crates.io](https://img.shields.io/crates/v/actix-form-data?label=latest)][actix-form-data] [![dependency status](https://deps.rs/crate/actix-form-data/0.7.latest/status.svg)](https://deps.rs/crate/actix-form-data) | Multipart form data from actix multipart streams | +| [actix-governor] | [![crates.io](https://img.shields.io/crates/v/actix-governor?label=latest)][actix-governor] [![dependency status](https://deps.rs/crate/actix-governor/latest/status.svg)](https://deps.rs/crate/actix-governor) | Rate-limiting backed by governor. | +| [actix-casbin] | [![crates.io](https://img.shields.io/crates/v/actix-casbin?label=latest)][actix-casbin] [![dependency status](https://deps.rs/crate/actix-casbin/latest/status.svg)](https://deps.rs/crate/actix-casbin) | Authorization library that supports access control models like ACL, RBAC & ABAC. | +| [actix-ip-filter] | [![crates.io](https://img.shields.io/crates/v/actix-ip-filter?label=latest)][actix-ip-filter] [![dependency status](https://deps.rs/crate/actix-ip-filter/latest/status.svg)](https://deps.rs/crate/actix-ip-filter) | IP address filter. Supports glob patterns. | +| [actix-web-static-files] | [![crates.io](https://img.shields.io/crates/v/actix-web-static-files?label=latest)][actix-web-static-files] [![dependency status](https://deps.rs/crate/actix-web-static-files/latest/status.svg)](https://deps.rs/crate/actix-web-static-files) | Static files as embedded resources. | +| [actix-web-grants] | [![crates.io](https://img.shields.io/crates/v/actix-web-grants?label=latest)][actix-web-grants] [![dependency status](https://deps.rs/crate/actix-web-grants/latest/status.svg)](https://deps.rs/crate/actix-web-grants) | Extension for validating user authorities. | +| [aliri_actix] | [![crates.io](https://img.shields.io/crates/v/aliri_actix?label=latest)][aliri_actix] [![dependency status](https://deps.rs/crate/aliri_actix/latest/status.svg)](https://deps.rs/crate/aliri_actix) | Endpoint authorization and authentication using scoped OAuth2 JWT tokens. | +| [actix-web-flash-messages] | [![crates.io](https://img.shields.io/crates/v/actix-web-flash-messages?label=latest)][actix-web-flash-messages] [![dependency status](https://deps.rs/crate/actix-web-flash-messages/latest/status.svg)](https://deps.rs/crate/actix-web-flash-messages) | Support for flash messages/one-time notifications in `actix-web`. | +| [awmp] | [![crates.io](https://img.shields.io/crates/v/awmp?label=latest)][awmp] [![dependency status](https://deps.rs/crate/awmp/latest/status.svg)](https://deps.rs/crate/awmp) | An easy to use wrapper around multipart fields for Actix Web. | +| [tracing-actix-web] | [![crates.io](https://img.shields.io/crates/v/tracing-actix-web?label=latest)][tracing-actix-web] [![dependency status](https://deps.rs/crate/tracing-actix-web/latest/status.svg)](https://deps.rs/crate/tracing-actix-web) | A middleware to collect telemetry data from applications built on top of the Actix Web framework. | +| [actix-ws] | [![crates.io](https://img.shields.io/crates/v/actix-ws?label=latest)][actix-ws] [![dependency status](https://deps.rs/crate/actix-ws/latest/status.svg)](https://deps.rs/crate/actix-ws) | Actor-less WebSockets for the Actix Runtime. | +| [actix-hash] | [![crates.io](https://img.shields.io/crates/v/actix-hash?label=latest)][actix-hash] [![dependency status](https://deps.rs/crate/actix-hash/latest/status.svg)](https://deps.rs/crate/actix-hash) | Hashing utilities for Actix Web. | +| [actix-bincode] | ![crates.io](https://img.shields.io/crates/v/actix-bincode?label=latest) [![dependency status](https://deps.rs/crate/actix-bincode/latest/status.svg)](https://deps.rs/crate/actix-bincode) | Bincode payload extractor for Actix Web | +| [sentinel-actix] | ![crates.io](https://img.shields.io/crates/v/sentinel-actix?label=latest) [![dependency status](https://deps.rs/crate/sentinel-actix/latest/status.svg)](https://deps.rs/crate/sentinel-actix) | General and flexible protection for Actix Web | To add a crate to this list, submit a pull request. From a593a8dc904c93fd88d4d0774072a5592f79d64f Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 20:39:32 +0000 Subject: [PATCH 13/15] fix readme version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71a4695f3..a52e568fc 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ These crates are provided by the community. | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | [actix-web-lab] | [![crates.io](https://img.shields.io/crates/v/actix-web-lab?label=latest)][actix-web-lab] [![dependency status](https://deps.rs/crate/actix-web-lab/latest/status.svg)](https://deps.rs/crate/actix-web-lab) | Experimental extractors, middleware, and other extras for possible inclusion in Actix Web. | | [actix-multipart-extract] | [![crates.io](https://img.shields.io/crates/v/actix-multipart-extract?label=latest)][actix-multipart-extract] [![dependency status](https://deps.rs/crate/actix-multipart-extract/latest/status.svg)](https://deps.rs/crate/actix-multipart-extract) | Better multipart form support for Actix Web. | -| [actix-form-data] | [![crates.io](https://img.shields.io/crates/v/actix-form-data?label=latest)][actix-form-data] [![dependency status](https://deps.rs/crate/actix-form-data/0.7.latest/status.svg)](https://deps.rs/crate/actix-form-data) | Multipart form data from actix multipart streams | +| [actix-form-data] | [![crates.io](https://img.shields.io/crates/v/actix-form-data?label=latest)][actix-form-data] [![dependency status](https://deps.rs/crate/actix-form-data/latest/status.svg)](https://deps.rs/crate/actix-form-data) | Multipart form data from actix multipart streams | | [actix-governor] | [![crates.io](https://img.shields.io/crates/v/actix-governor?label=latest)][actix-governor] [![dependency status](https://deps.rs/crate/actix-governor/latest/status.svg)](https://deps.rs/crate/actix-governor) | Rate-limiting backed by governor. | | [actix-casbin] | [![crates.io](https://img.shields.io/crates/v/actix-casbin?label=latest)][actix-casbin] [![dependency status](https://deps.rs/crate/actix-casbin/latest/status.svg)](https://deps.rs/crate/actix-casbin) | Authorization library that supports access control models like ACL, RBAC & ABAC. | | [actix-ip-filter] | [![crates.io](https://img.shields.io/crates/v/actix-ip-filter?label=latest)][actix-ip-filter] [![dependency status](https://deps.rs/crate/actix-ip-filter/latest/status.svg)](https://deps.rs/crate/actix-ip-filter) | IP address filter. Supports glob patterns. | From 6d0ab96dfd79e31e1c5dc1e58a9352db415383df Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 3 Nov 2023 22:49:18 +0000 Subject: [PATCH 14/15] adopt actix-ws crate (#361) --- Cargo.toml | 1 + LICENSE-APACHE | 3 +- LICENSE-MIT | 3 +- README.md | 4 +- actix-web-httpauth/Cargo.toml | 8 +- actix-ws/CHANGELOG.md | 10 ++ actix-ws/Cargo.toml | 31 +++++ actix-ws/LICENSE-APACHE | 1 + actix-ws/LICENSE-MIT | 1 + actix-ws/README.md | 74 ++++++++++++ actix-ws/examples/chat.rs | 208 ++++++++++++++++++++++++++++++++++ actix-ws/src/fut.rs | 183 ++++++++++++++++++++++++++++++ actix-ws/src/lib.rs | 84 ++++++++++++++ actix-ws/src/session.rs | 143 +++++++++++++++++++++++ 14 files changed, 744 insertions(+), 10 deletions(-) create mode 100644 actix-ws/CHANGELOG.md create mode 100644 actix-ws/Cargo.toml create mode 120000 actix-ws/LICENSE-APACHE create mode 120000 actix-ws/LICENSE-MIT create mode 100644 actix-ws/README.md create mode 100644 actix-ws/examples/chat.rs create mode 100644 actix-ws/src/fut.rs create mode 100644 actix-ws/src/lib.rs create mode 100644 actix-ws/src/session.rs diff --git a/Cargo.toml b/Cargo.toml index 645d4f39d..4793d4ee6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "actix-session", "actix-settings", "actix-web-httpauth", + "actix-ws", ] [workspace.package] diff --git a/LICENSE-APACHE b/LICENSE-APACHE index d0eb30d70..fb96878c0 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,8 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2017-NOW Nikolay Kim - Copyright 2017-NOW svartalf and Actix team + Copyright 2017-NOW Actix team Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index e57de3745..255963b91 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,5 +1,4 @@ -Copyright (c) 2017 Nikolay Kim -Copyright (c) 2017 svartalf and Actix team +Copyright (c) 2023 Actix team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index a52e568fc..a6d55decd 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ | [actix-session] | [![crates.io](https://img.shields.io/crates/v/actix-session?label=latest)](https://crates.io/crates/actix-session) [![dependency status](https://deps.rs/crate/actix-session/latest/status.svg)](https://deps.rs/crate/actix-session) | Session management. | | [actix-settings] | [![crates.io](https://img.shields.io/crates/v/actix-settings?label=latest)](https://crates.io/crates/actix-settings) [![dependency status](https://deps.rs/crate/actix-settings/latest/status.svg)](https://deps.rs/crate/actix-settings) | Easily manage Actix Web's settings from a TOML file and environment variables. | | [actix-web-httpauth] | [![crates.io](https://img.shields.io/crates/v/actix-web-httpauth?label=latest)](https://crates.io/crates/actix-web-httpauth) [![dependency status](https://deps.rs/crate/actix-web-httpauth/latest/status.svg)](https://deps.rs/crate/actix-web-httpauth) | HTTP authentication schemes. | +| [actix-ws] | [![crates.io](https://img.shields.io/crates/v/actix-ws?label=latest)][actix-ws] [![dependency status](https://deps.rs/crate/actix-ws/latest/status.svg)](https://deps.rs/crate/actix-ws) | WebSockets for Actix Web, without actors. | --- @@ -30,7 +31,7 @@ These crates are provided by the community. | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | [actix-web-lab] | [![crates.io](https://img.shields.io/crates/v/actix-web-lab?label=latest)][actix-web-lab] [![dependency status](https://deps.rs/crate/actix-web-lab/latest/status.svg)](https://deps.rs/crate/actix-web-lab) | Experimental extractors, middleware, and other extras for possible inclusion in Actix Web. | | [actix-multipart-extract] | [![crates.io](https://img.shields.io/crates/v/actix-multipart-extract?label=latest)][actix-multipart-extract] [![dependency status](https://deps.rs/crate/actix-multipart-extract/latest/status.svg)](https://deps.rs/crate/actix-multipart-extract) | Better multipart form support for Actix Web. | -| [actix-form-data] | [![crates.io](https://img.shields.io/crates/v/actix-form-data?label=latest)][actix-form-data] [![dependency status](https://deps.rs/crate/actix-form-data/latest/status.svg)](https://deps.rs/crate/actix-form-data) | Multipart form data from actix multipart streams | +| [actix-form-data] | [![crates.io](https://img.shields.io/crates/v/actix-form-data?label=latest)][actix-form-data] [![dependency status](https://deps.rs/crate/actix-form-data/latest/status.svg)](https://deps.rs/crate/actix-form-data) | Multipart form data from actix multipart streams | | [actix-governor] | [![crates.io](https://img.shields.io/crates/v/actix-governor?label=latest)][actix-governor] [![dependency status](https://deps.rs/crate/actix-governor/latest/status.svg)](https://deps.rs/crate/actix-governor) | Rate-limiting backed by governor. | | [actix-casbin] | [![crates.io](https://img.shields.io/crates/v/actix-casbin?label=latest)][actix-casbin] [![dependency status](https://deps.rs/crate/actix-casbin/latest/status.svg)](https://deps.rs/crate/actix-casbin) | Authorization library that supports access control models like ACL, RBAC & ABAC. | | [actix-ip-filter] | [![crates.io](https://img.shields.io/crates/v/actix-ip-filter?label=latest)][actix-ip-filter] [![dependency status](https://deps.rs/crate/actix-ip-filter/latest/status.svg)](https://deps.rs/crate/actix-ip-filter) | IP address filter. Supports glob patterns. | @@ -40,7 +41,6 @@ These crates are provided by the community. | [actix-web-flash-messages] | [![crates.io](https://img.shields.io/crates/v/actix-web-flash-messages?label=latest)][actix-web-flash-messages] [![dependency status](https://deps.rs/crate/actix-web-flash-messages/latest/status.svg)](https://deps.rs/crate/actix-web-flash-messages) | Support for flash messages/one-time notifications in `actix-web`. | | [awmp] | [![crates.io](https://img.shields.io/crates/v/awmp?label=latest)][awmp] [![dependency status](https://deps.rs/crate/awmp/latest/status.svg)](https://deps.rs/crate/awmp) | An easy to use wrapper around multipart fields for Actix Web. | | [tracing-actix-web] | [![crates.io](https://img.shields.io/crates/v/tracing-actix-web?label=latest)][tracing-actix-web] [![dependency status](https://deps.rs/crate/tracing-actix-web/latest/status.svg)](https://deps.rs/crate/tracing-actix-web) | A middleware to collect telemetry data from applications built on top of the Actix Web framework. | -| [actix-ws] | [![crates.io](https://img.shields.io/crates/v/actix-ws?label=latest)][actix-ws] [![dependency status](https://deps.rs/crate/actix-ws/latest/status.svg)](https://deps.rs/crate/actix-ws) | Actor-less WebSockets for the Actix Runtime. | | [actix-hash] | [![crates.io](https://img.shields.io/crates/v/actix-hash?label=latest)][actix-hash] [![dependency status](https://deps.rs/crate/actix-hash/latest/status.svg)](https://deps.rs/crate/actix-hash) | Hashing utilities for Actix Web. | | [actix-bincode] | ![crates.io](https://img.shields.io/crates/v/actix-bincode?label=latest) [![dependency status](https://deps.rs/crate/actix-bincode/latest/status.svg)](https://deps.rs/crate/actix-bincode) | Bincode payload extractor for Actix Web | | [sentinel-actix] | ![crates.io](https://img.shields.io/crates/v/sentinel-actix?label=latest) [![dependency status](https://deps.rs/crate/sentinel-actix/latest/status.svg)](https://deps.rs/crate/sentinel-actix) | General and flexible protection for Actix Web | diff --git a/actix-web-httpauth/Cargo.toml b/actix-web-httpauth/Cargo.toml index f666b6238..f054cdbc8 100644 --- a/actix-web-httpauth/Cargo.toml +++ b/actix-web-httpauth/Cargo.toml @@ -1,15 +1,15 @@ [package] name = "actix-web-httpauth" version = "0.8.1" +description = "HTTP authentication schemes for Actix Web" +categories = ["web-programming"] +keywords = ["http", "web", "framework", "authentication", "security"] authors = [ "svartalf ", "Yuki Okushi ", ] -description = "HTTP authentication schemes for Actix Web" -keywords = ["http", "web", "framework", "authentication", "security"] homepage = "https://actix.rs" -repository = "https://github.com/actix/actix-extras.git" -categories = ["web-programming::http-server"] +repository = "https://github.com/actix/actix-extras" license.workspace = true edition.workspace = true rust-version.workspace = true diff --git a/actix-ws/CHANGELOG.md b/actix-ws/CHANGELOG.md new file mode 100644 index 000000000..985050ec9 --- /dev/null +++ b/actix-ws/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## Unreleased + +- Remove type parameters from `Session::{text, binary}()` methods, replacing with equivalent `impl Trait` parameters. +- `Session::text()` now receives an `impl Into`, making broadcasting text messages more efficient. + +## 0.2.5 + +- Adopted into @actix org from . diff --git a/actix-ws/Cargo.toml b/actix-ws/Cargo.toml new file mode 100644 index 000000000..a59415cff --- /dev/null +++ b/actix-ws/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "actix-ws" +version = "0.2.0" +description = "WebSockets for Actix Web, without actors" +categories = ["web-programming::websocket"] +keywords = ["actix", "web", "websocket", "websockets", "http"] +authors = [ + "asonix ", + "Rob Ede ", +] +repository = "https://github.com/actix/actix-extras" +license.workspace = true +edition.workspace = true +rust-version.workspace = true + +[dependencies] +actix-codec = "0.5" +actix-http = { version = "3", default-features = false, features = ["ws"] } +actix-web = { version = "4", default-features = false } +bytestring = "1" +futures-core = "0.3.17" +tokio = { version = "1", features = ["sync"] } + +[dev-dependencies] +actix-rt = "2.6" +actix-web = "4.0.1" +anyhow = "1.0" +futures = "0.3" +log = "0.4" +pretty_env_logger = "0.5" +tokio = { version = "1", features = ["sync"] } diff --git a/actix-ws/LICENSE-APACHE b/actix-ws/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/actix-ws/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/actix-ws/LICENSE-MIT b/actix-ws/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/actix-ws/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/actix-ws/README.md b/actix-ws/README.md new file mode 100644 index 000000000..6117d53a9 --- /dev/null +++ b/actix-ws/README.md @@ -0,0 +1,74 @@ +# Actix WS (Next Gen) + +> WebSockets for Actix Web, without actors. + +[![crates.io](https://img.shields.io/crates/v/actix-ws?label=latest)](https://crates.io/crates/actix-ws) +[![Documentation](https://docs.rs/actix-ws/badge.svg?version=0.2.0)](https://docs.rs/actix-ws/0.2.0) +![Apache 2.0 or MIT licensed](https://img.shields.io/crates/l/actix-ws) +[![Dependency Status](https://deps.rs/crate/actix-ws/0.2.0/status.svg)](https://deps.rs/crate/actix-ws/0.2.0) + +## Documentation & Resources + +- [API Documentation](https://docs.rs/actix-ws) +- [Example Projects](https://github.com/actix/examples/tree/master/websockets) +- Minimum Supported Rust Version (MSRV): 1.68 + +## Usage + +```toml +# Cargo.toml +anyhow = "1" +actix-web = "4" +actix-ws-ng = "0.3" +``` + +```rust +// main.rs +use actix_web::{middleware::Logger, web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use actix_ws::Message; + +async fn ws(req: HttpRequest, body: web::Payload) -> Result { + let (response, mut session, mut msg_stream) = actix_ws::handle(&req, body)?; + + actix_rt::spawn(async move { + while let Some(Ok(msg)) = msg_stream.next().await { + match msg { + Message::Ping(bytes) => { + if session.pong(&bytes).await.is_err() { + return; + } + } + Message::Text(s) => println!("Got text, {}", s), + _ => break, + } + } + + let _ = session.close(None).await; + }); + + Ok(response) +} + +#[actix_web::main] +async fn main() -> Result<(), anyhow::Error> { + HttpServer::new(move || { + App::new() + .wrap(Logger::default()) + .route("/ws", web::get().to(ws)) + }) + .bind("127.0.0.1:8080")? + .run() + .await?; + + Ok(()) +} +``` + +## License + +This project is licensed under either of + +- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT) + +at your option. diff --git a/actix-ws/examples/chat.rs b/actix-ws/examples/chat.rs new file mode 100644 index 000000000..035ce7a49 --- /dev/null +++ b/actix-ws/examples/chat.rs @@ -0,0 +1,208 @@ +use std::{ + sync::Arc, + time::{Duration, Instant}, +}; + +use actix_web::{middleware::Logger, web, App, HttpRequest, HttpResponse, HttpServer}; +use actix_ws::{Message, Session}; +use futures::stream::{FuturesUnordered, StreamExt as _}; +use log::info; +use tokio::sync::Mutex; + +#[derive(Clone)] +struct Chat { + inner: Arc>, +} + +struct ChatInner { + sessions: Vec, +} + +impl Chat { + fn new() -> Self { + Chat { + inner: Arc::new(Mutex::new(ChatInner { + sessions: Vec::new(), + })), + } + } + + async fn insert(&self, session: Session) { + self.inner.lock().await.sessions.push(session); + } + + async fn send(&self, msg: String) { + let mut inner = self.inner.lock().await; + let mut unordered = FuturesUnordered::new(); + + for mut session in inner.sessions.drain(..) { + let msg = msg.clone(); + unordered.push(async move { + let res = session.text(msg).await; + res.map(|_| session).map_err(|_| info!("Dropping session")) + }); + } + + while let Some(res) = unordered.next().await { + if let Ok(session) = res { + inner.sessions.push(session); + } + } + } +} + +async fn ws( + req: HttpRequest, + body: web::Payload, + chat: web::Data, +) -> Result { + let (response, mut session, mut stream) = actix_ws::handle(&req, body)?; + + chat.insert(session.clone()).await; + info!("Inserted session"); + + let alive = Arc::new(Mutex::new(Instant::now())); + + let mut session2 = session.clone(); + let alive2 = alive.clone(); + actix_rt::spawn(async move { + let mut interval = actix_rt::time::interval(Duration::from_secs(5)); + loop { + interval.tick().await; + if session2.ping(b"").await.is_err() { + break; + } + + if Instant::now().duration_since(*alive2.lock().await) > Duration::from_secs(10) { + let _ = session2.close(None).await; + break; + } + } + }); + + actix_rt::spawn(async move { + while let Some(Ok(msg)) = stream.next().await { + match msg { + Message::Ping(bytes) => { + if session.pong(&bytes).await.is_err() { + return; + } + } + Message::Text(s) => { + info!("Relaying text, {}", s); + let s: &str = s.as_ref(); + chat.send(s.into()).await; + } + Message::Close(reason) => { + let _ = session.close(reason).await; + info!("Got close, bailing"); + return; + } + Message::Continuation(_) => { + let _ = session.close(None).await; + info!("Got continuation, bailing"); + return; + } + Message::Pong(_) => { + *alive.lock().await = Instant::now(); + } + _ => (), + }; + } + let _ = session.close(None).await; + }); + info!("Spawned"); + + Ok(response) +} + +async fn index() -> HttpResponse { + let s = r#" + + + + Chat + + + + +
    +
+ + + "#; + + HttpResponse::Ok().content_type("text/html").body(s) +} + +#[actix_rt::main] +async fn main() -> Result<(), anyhow::Error> { + std::env::set_var("RUST_LOG", "info"); + pretty_env_logger::init(); + let chat = Chat::new(); + + HttpServer::new(move || { + App::new() + .wrap(Logger::default()) + .app_data(web::Data::new(chat.clone())) + .route("/", web::get().to(index)) + .route("/ws", web::get().to(ws)) + }) + .bind("127.0.0.1:8080")? + .run() + .await?; + + Ok(()) +} diff --git a/actix-ws/src/fut.rs b/actix-ws/src/fut.rs new file mode 100644 index 000000000..92b762c36 --- /dev/null +++ b/actix-ws/src/fut.rs @@ -0,0 +1,183 @@ +use std::{ + collections::VecDeque, + future::poll_fn, + io, + pin::Pin, + task::{Context, Poll}, +}; + +use actix_codec::{Decoder, Encoder}; +use actix_http::{ + ws::{Codec, Frame, Message, ProtocolError}, + Payload, +}; +use actix_web::{ + web::{Bytes, BytesMut}, + Error, +}; +use futures_core::stream::Stream; +use tokio::sync::mpsc::Receiver; + +/// A response body for Websocket HTTP Requests +pub struct StreamingBody { + session_rx: Receiver, + + messages: VecDeque, + buf: BytesMut, + codec: Codec, + closing: bool, +} + +/// A stream of Messages from a websocket client +/// +/// Messages can be accessed via the stream's `.next()` method +pub struct MessageStream { + payload: Payload, + + messages: VecDeque, + buf: BytesMut, + codec: Codec, + closing: bool, +} + +impl StreamingBody { + pub(super) fn new(session_rx: Receiver) -> Self { + StreamingBody { + session_rx, + messages: VecDeque::new(), + buf: BytesMut::new(), + codec: Codec::new(), + closing: false, + } + } +} + +impl MessageStream { + pub(super) fn new(payload: Payload) -> Self { + MessageStream { + payload, + messages: VecDeque::new(), + buf: BytesMut::new(), + codec: Codec::new(), + closing: false, + } + } + + /// Wait for the next item from the message stream + /// + /// ```rust,ignore + /// while let Some(Ok(msg)) = stream.recv().await { + /// // handle message + /// } + /// ``` + pub async fn recv(&mut self) -> Option> { + poll_fn(|cx| Pin::new(&mut *self).poll_next(cx)).await + } +} + +impl Stream for StreamingBody { + type Item = Result; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.get_mut(); + + if this.closing { + return Poll::Ready(None); + } + + loop { + match Pin::new(&mut this.session_rx).poll_recv(cx) { + Poll::Ready(Some(msg)) => { + this.messages.push_back(msg); + } + Poll::Ready(None) => { + this.closing = true; + break; + } + Poll::Pending => break, + } + } + + while let Some(msg) = this.messages.pop_front() { + if let Err(e) = this.codec.encode(msg, &mut this.buf) { + return Poll::Ready(Some(Err(e.into()))); + } + } + + if !this.buf.is_empty() { + return Poll::Ready(Some(Ok(this.buf.split().freeze()))); + } + + Poll::Pending + } +} + +impl Stream for MessageStream { + type Item = Result; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.get_mut(); + + // Return the first message in the queue if one exists + // + // This is faster than polling and parsing + if let Some(msg) = this.messages.pop_front() { + return Poll::Ready(Some(Ok(msg))); + } + + if !this.closing { + // Read in bytes until there's nothing left to read + loop { + match Pin::new(&mut this.payload).poll_next(cx) { + Poll::Ready(Some(Ok(bytes))) => { + this.buf.extend_from_slice(&bytes); + } + Poll::Ready(Some(Err(e))) => { + return Poll::Ready(Some(Err(ProtocolError::Io(io::Error::new( + io::ErrorKind::Other, + e.to_string(), + ))))); + } + Poll::Ready(None) => { + this.closing = true; + break; + } + Poll::Pending => break, + } + } + } + + // Create messages until there's no more bytes left + while let Some(frame) = this.codec.decode(&mut this.buf)? { + let message = match frame { + Frame::Text(bytes) => { + let s = std::str::from_utf8(&bytes) + .map_err(|e| { + ProtocolError::Io(io::Error::new(io::ErrorKind::Other, e.to_string())) + })? + .to_string(); + Message::Text(s.into()) + } + Frame::Binary(bytes) => Message::Binary(bytes), + Frame::Ping(bytes) => Message::Ping(bytes), + Frame::Pong(bytes) => Message::Pong(bytes), + Frame::Close(reason) => Message::Close(reason), + Frame::Continuation(item) => Message::Continuation(item), + }; + + this.messages.push_back(message); + } + + // Return the first message in the queue + if let Some(msg) = this.messages.pop_front() { + return Poll::Ready(Some(Ok(msg))); + } + + // If we've exhausted our message queue and we're closing, close the stream + if this.closing { + return Poll::Ready(None); + } + + Poll::Pending + } +} diff --git a/actix-ws/src/lib.rs b/actix-ws/src/lib.rs new file mode 100644 index 000000000..20cc016a7 --- /dev/null +++ b/actix-ws/src/lib.rs @@ -0,0 +1,84 @@ +//! WebSockets for Actix Web, without actors. +//! +//! For usage, see documentation on [`handle()`]. + +#![deny(rust_2018_idioms, nonstandard_style, future_incompatible)] +#![warn(missing_docs)] +#![doc(html_logo_url = "https://actix.rs/img/logo.png")] +#![doc(html_favicon_url = "https://actix.rs/favicon.ico")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] + +pub use actix_http::ws::{CloseCode, CloseReason, Message, ProtocolError}; +use actix_http::{ + body::{BodyStream, MessageBody}, + ws::handshake, +}; +use actix_web::{web, HttpRequest, HttpResponse}; +use tokio::sync::mpsc::channel; + +mod fut; +mod session; + +pub use self::{ + fut::{MessageStream, StreamingBody}, + session::{Closed, Session}, +}; + +/// Begin handling websocket traffic +/// +/// ```no_run +/// use actix_web::{middleware::Logger, web, App, Error, HttpRequest, HttpResponse, HttpServer}; +/// use actix_ws::Message; +/// use futures::stream::StreamExt as _; +/// +/// async fn ws(req: HttpRequest, body: web::Payload) -> Result { +/// let (response, mut session, mut msg_stream) = actix_ws::handle(&req, body)?; +/// +/// actix_rt::spawn(async move { +/// while let Some(Ok(msg)) = msg_stream.next().await { +/// match msg { +/// Message::Ping(bytes) => { +/// if session.pong(&bytes).await.is_err() { +/// return; +/// } +/// } +/// Message::Text(s) => println!("Got text, {}", s), +/// _ => break, +/// } +/// } +/// +/// let _ = session.close(None).await; +/// }); +/// +/// Ok(response) +/// } +/// +/// #[actix_rt::main] +/// async fn main() -> Result<(), anyhow::Error> { +/// HttpServer::new(move || { +/// App::new() +/// .wrap(Logger::default()) +/// .route("/ws", web::get().to(ws)) +/// }) +/// .bind("127.0.0.1:8080")? +/// .run() +/// .await?; +/// +/// Ok(()) +/// } +/// ``` +pub fn handle( + req: &HttpRequest, + body: web::Payload, +) -> Result<(HttpResponse, Session, MessageStream), actix_web::Error> { + let mut response = handshake(req.head())?; + let (tx, rx) = channel(32); + + Ok(( + response + .message_body(BodyStream::new(StreamingBody::new(rx)).boxed())? + .into(), + Session::new(tx), + MessageStream::new(body.into_inner()), + )) +} diff --git a/actix-ws/src/session.rs b/actix-ws/src/session.rs new file mode 100644 index 000000000..c5bf64f8b --- /dev/null +++ b/actix-ws/src/session.rs @@ -0,0 +1,143 @@ +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; + +use actix_http::ws::{CloseReason, Message}; +use actix_web::web::Bytes; +use bytestring::ByteString; +use tokio::sync::mpsc::Sender; + +/// A handle into the websocket session. +/// +/// This type can be used to send messages into the websocket. +#[derive(Clone)] +pub struct Session { + inner: Option>, + closed: Arc, +} + +/// The error representing a closed websocket session +#[derive(Debug)] +pub struct Closed; + +impl std::fmt::Display for Closed { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Session is closed") + } +} + +impl std::error::Error for Closed {} + +impl Session { + pub(super) fn new(inner: Sender) -> Self { + Session { + inner: Some(inner), + closed: Arc::new(AtomicBool::new(false)), + } + } + + fn pre_check(&mut self) { + if self.closed.load(Ordering::Relaxed) { + self.inner.take(); + } + } + + /// Send text into the websocket + /// + /// ```rust,ignore + /// if session.text("Some text").await.is_err() { + /// // session closed + /// } + /// ``` + pub async fn text(&mut self, msg: impl Into) -> Result<(), Closed> { + self.pre_check(); + if let Some(inner) = self.inner.as_mut() { + inner + .send(Message::Text(msg.into())) + .await + .map_err(|_| Closed) + } else { + Err(Closed) + } + } + + /// Send raw bytes into the websocket + /// + /// ```rust,ignore + /// if session.binary(b"some bytes").await.is_err() { + /// // session closed + /// } + /// ``` + pub async fn binary(&mut self, msg: impl Into) -> Result<(), Closed> { + self.pre_check(); + if let Some(inner) = self.inner.as_mut() { + inner + .send(Message::Binary(msg.into())) + .await + .map_err(|_| Closed) + } else { + Err(Closed) + } + } + + /// Ping the client + /// + /// For many applications, it will be important to send regular pings to keep track of if the + /// client has disconnected + /// + /// ```rust,ignore + /// if session.ping(b"").await.is_err() { + /// // session is closed + /// } + /// ``` + pub async fn ping(&mut self, msg: &[u8]) -> Result<(), Closed> { + self.pre_check(); + if let Some(inner) = self.inner.as_mut() { + inner + .send(Message::Ping(Bytes::copy_from_slice(msg))) + .await + .map_err(|_| Closed) + } else { + Err(Closed) + } + } + + /// Pong the client + /// + /// ```rust,ignore + /// match msg { + /// Message::Ping(bytes) => { + /// let _ = session.pong(&bytes).await; + /// } + /// _ => (), + /// } + pub async fn pong(&mut self, msg: &[u8]) -> Result<(), Closed> { + self.pre_check(); + if let Some(inner) = self.inner.as_mut() { + inner + .send(Message::Pong(Bytes::copy_from_slice(msg))) + .await + .map_err(|_| Closed) + } else { + Err(Closed) + } + } + + /// Send a close message, and consume the session + /// + /// All clones will return `Err(Closed)` if used after this call + /// + /// ```rust,ignore + /// session.close(None).await + /// ``` + pub async fn close(mut self, reason: Option) -> Result<(), Closed> { + self.pre_check(); + if let Some(inner) = self.inner.take() { + self.closed.store(true, Ordering::Relaxed); + inner.send(Message::Close(reason)).await.map_err(|_| Closed) + } else { + Err(Closed) + } + } +} From a48c2926f906d19e20b5749b6c19e302f0f96028 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 18:31:30 +0000 Subject: [PATCH 15/15] Bump taiki-e/install-action from 2.21.3 to 2.21.7 (#362) Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.21.3 to 2.21.7. - [Release notes](https://github.com/taiki-e/install-action/releases) - [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/install-action/compare/v2.21.3...v2.21.7) --- updated-dependencies: - dependency-name: taiki-e/install-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-post-merge.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-post-merge.yml b/.github/workflows/ci-post-merge.yml index 6fa7d7db6..45a5f5c60 100644 --- a/.github/workflows/ci-post-merge.yml +++ b/.github/workflows/ci-post-merge.yml @@ -35,7 +35,7 @@ jobs: with: toolchain: nightly - - uses: taiki-e/install-action@v2.21.3 + - uses: taiki-e/install-action@v2.21.7 with: tool: cargo-hack @@ -77,7 +77,7 @@ jobs: with: toolchain: nightly - - uses: taiki-e/install-action@v2.21.3 + - uses: taiki-e/install-action@v2.21.7 with: tool: cargo-hack diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cbf6d55b..e1b74a31f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: toolchain: ${{ matrix.version.version }} - name: Install cargo-hack - uses: taiki-e/install-action@v2.21.3 + uses: taiki-e/install-action@v2.21.7 with: tool: cargo-hack @@ -100,7 +100,7 @@ jobs: toolchain: ${{ matrix.version.version }} - name: Install cargo-hack - uses: taiki-e/install-action@v2.21.3 + uses: taiki-e/install-action@v2.21.7 with: tool: cargo-hack