mirror of
https://github.com/Noratrieb/101844-repro.git
synced 2026-01-16 15:15:00 +01:00
no build
This commit is contained in:
parent
f5f20836d4
commit
fa88e78ef7
6 changed files with 0 additions and 1477 deletions
|
|
@ -1,418 +0,0 @@
|
||||||
# Changelog
|
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
||||||
|
|
||||||
# Unreleased
|
|
||||||
|
|
||||||
- None.
|
|
||||||
|
|
||||||
# 0.4.13 (June 17, 2022)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- **load_shed**: Public constructor for `Overloaded` error ([#661])
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- **util**: Fix hang with `call_all` when the `Stream` of requests is pending
|
|
||||||
([#656])
|
|
||||||
- **ready_cache**: Ensure cancelation is observed by pending services ([#668],
|
|
||||||
fixes [#415])
|
|
||||||
- **docs**: Fix a missing section header due to a typo ([#646])
|
|
||||||
- **docs**: Fix broken links to `Service` trait ([#659])
|
|
||||||
|
|
||||||
|
|
||||||
[#661]: https://github.com/tower-rs/tower/pull/661
|
|
||||||
[#656]: https://github.com/tower-rs/tower/pull/656
|
|
||||||
[#668]: https://github.com/tower-rs/tower/pull/668
|
|
||||||
[#415]: https://github.com/tower-rs/tower/pull/415
|
|
||||||
[#646]: https://github.com/tower-rs/tower/pull/646
|
|
||||||
[#659]: https://github.com/tower-rs/tower/pull/659
|
|
||||||
|
|
||||||
# 0.4.12 (February 16, 2022)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- **hedge**, **load**, **retry**: Fix use of `Instant` operations that can panic
|
|
||||||
on platforms where `Instant` is not monotonic ([#633])
|
|
||||||
- Disable `attributes` feature on `tracing` dependency ([#623])
|
|
||||||
- Remove unused dependencies and dependency features with some feature
|
|
||||||
combinations ([#603], [#602])
|
|
||||||
- **docs**: Fix a typo in the RustDoc for `Buffer` ([#622])
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Updated minimum supported Rust version (MSRV) to 1.49.0.
|
|
||||||
- **hedge**: Updated `hdrhistogram` dependency to v7.0 ([#602])
|
|
||||||
- Updated `tokio-util` dependency to v0.7 ([#638])
|
|
||||||
|
|
||||||
[#633]: https://github.com/tower-rs/tower/pull/633
|
|
||||||
[#623]: https://github.com/tower-rs/tower/pull/623
|
|
||||||
[#603]: https://github.com/tower-rs/tower/pull/603
|
|
||||||
[#602]: https://github.com/tower-rs/tower/pull/602
|
|
||||||
[#622]: https://github.com/tower-rs/tower/pull/622
|
|
||||||
[#638]: https://github.com/tower-rs/tower/pull/638
|
|
||||||
|
|
||||||
# 0.4.11 (November 18, 2021)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- **util**: Add `BoxCloneService` which is a `Clone + Send` boxed `Service` ([#615])
|
|
||||||
- **util**: Add `ServiceExt::boxed` and `ServiceExt::boxed_clone` for applying the
|
|
||||||
`BoxService` and `BoxCloneService` middleware ([#616])
|
|
||||||
- **builder**: Add `ServiceBuilder::boxed` and `ServiceBuilder::boxed_clone` for
|
|
||||||
applying `BoxService` and `BoxCloneService` layers ([#616])
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- **util**: Remove redundant `F: Clone` bound from `ServiceExt::map_request` ([#607])
|
|
||||||
- **util**: Remove unnecessary `Debug` bounds from `impl Debug for BoxService` ([#617])
|
|
||||||
- **util**: Remove unnecessary `Debug` bounds from `impl Debug for UnsyncBoxService` ([#617])
|
|
||||||
- **balance**: Remove redundant `Req: Clone` bound from `Clone` impls
|
|
||||||
for `MakeBalance`, and `MakeBalanceLayer` ([#607])
|
|
||||||
- **balance**: Remove redundant `Req: Debug` bound from `Debug` impls
|
|
||||||
for `MakeBalance`, `MakeFuture`, `Balance`, and `Pool` ([#607])
|
|
||||||
- **ready-cache**: Remove redundant `Req: Debug` bound from `Debug` impl
|
|
||||||
for `ReadyCache` ([#607])
|
|
||||||
- **steer**: Remove redundant `Req: Debug` bound from `Debug` impl
|
|
||||||
for `Steer` ([#607])
|
|
||||||
- **docs**: Fix `doc(cfg(...))` attributes
|
|
||||||
of `PeakEwmaDiscover`, and `PendingRequestsDiscover` ([#610])
|
|
||||||
|
|
||||||
[#607]: https://github.com/tower-rs/tower/pull/607
|
|
||||||
[#610]: https://github.com/tower-rs/tower/pull/610
|
|
||||||
[#615]: https://github.com/tower-rs/tower/pull/615
|
|
||||||
[#616]: https://github.com/tower-rs/tower/pull/616
|
|
||||||
[#617]: https://github.com/tower-rs/tower/pull/617
|
|
||||||
|
|
||||||
# 0.4.10 (October 19, 2021)
|
|
||||||
|
|
||||||
- Fix accidental breaking change when using the
|
|
||||||
`rustdoc::broken_intra_doc_links` lint ([#605])
|
|
||||||
- Clarify that tower's minimum supported rust version is 1.46 ([#605])
|
|
||||||
|
|
||||||
[#605]: https://github.com/tower-rs/tower/pull/605
|
|
||||||
|
|
||||||
# 0.4.9 (October 13, 2021)
|
|
||||||
|
|
||||||
- Migrate to [pin-project-lite] ([#595])
|
|
||||||
- **builder**: Implement `Layer` for `ServiceBuilder` ([#600])
|
|
||||||
- **builder**: Add `ServiceBuilder::and_then` analogous to
|
|
||||||
`ServiceExt::and_then` ([#601])
|
|
||||||
|
|
||||||
[#600]: https://github.com/tower-rs/tower/pull/600
|
|
||||||
[#601]: https://github.com/tower-rs/tower/pull/601
|
|
||||||
[#595]: https://github.com/tower-rs/tower/pull/595
|
|
||||||
[pin-project-lite]: https://crates.io/crates/pin-project-lite
|
|
||||||
|
|
||||||
# 0.4.8 (May 28, 2021)
|
|
||||||
|
|
||||||
- **builder**: Add `ServiceBuilder::map_result` analogous to
|
|
||||||
`ServiceExt::map_result` ([#583])
|
|
||||||
- **limit**: Add `GlobalConcurrencyLimitLayer` to allow reusing a concurrency
|
|
||||||
limit across multiple services ([#574])
|
|
||||||
|
|
||||||
[#574]: https://github.com/tower-rs/tower/pull/574
|
|
||||||
[#583]: https://github.com/tower-rs/tower/pull/583
|
|
||||||
|
|
||||||
# 0.4.7 (April 27, 2021)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- **builder**: Add `ServiceBuilder::check_service` to check the request,
|
|
||||||
response, and error types of the output service. ([#576])
|
|
||||||
- **builder**: Add `ServiceBuilder::check_service_clone` to check the output
|
|
||||||
service can be cloned. ([#576])
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- **spawn_ready**: Abort spawned background tasks when the `SpawnReady` service
|
|
||||||
is dropped, fixing a potential task/resource leak (#[581])
|
|
||||||
- Fixed broken documentation links ([#578])
|
|
||||||
|
|
||||||
[#576]: https://github.com/tower-rs/tower/pull/576
|
|
||||||
[#578]: https://github.com/tower-rs/tower/pull/578
|
|
||||||
[#581]: https://github.com/tower-rs/tower/pull/581
|
|
||||||
|
|
||||||
# 0.4.6 (February 26, 2021)
|
|
||||||
|
|
||||||
### Deprecated
|
|
||||||
|
|
||||||
- **util**: Deprecated `ServiceExt::ready_and` (renamed to `ServiceExt::ready`).
|
|
||||||
([#567])
|
|
||||||
- **util**: Deprecated `ReadyAnd` future (renamed to `Ready`). ([#567])
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- **builder**: Add `ServiceBuilder::layer_fn` to add a layer built from a
|
|
||||||
function. ([#560])
|
|
||||||
- **builder**: Add `ServiceBuilder::map_future` for transforming the futures
|
|
||||||
produced by a service. ([#559])
|
|
||||||
- **builder**: Add `ServiceBuilder::service_fn` for applying `Layer`s to an
|
|
||||||
async function using `util::service_fn`. ([#564])
|
|
||||||
- **util**: Add example for `service_fn`. ([#563])
|
|
||||||
- **util**: Add `BoxLayer` for creating boxed `Layer` trait objects. ([#569])
|
|
||||||
|
|
||||||
[#567]: https://github.com/tower-rs/tower/pull/567
|
|
||||||
[#560]: https://github.com/tower-rs/tower/pull/560
|
|
||||||
[#559]: https://github.com/tower-rs/tower/pull/559
|
|
||||||
[#564]: https://github.com/tower-rs/tower/pull/564
|
|
||||||
[#563]: https://github.com/tower-rs/tower/pull/563
|
|
||||||
[#569]: https://github.com/tower-rs/tower/pull/569
|
|
||||||
|
|
||||||
# 0.4.5 (February 10, 2021)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- **util**: Add `ServiceExt::map_future`. ([#542])
|
|
||||||
- **builder**: Add `ServiceBuilder::option_layer` to optionally add a layer. ([#555])
|
|
||||||
- **make**: Add `Shared` which lets you implement `MakeService` by cloning a
|
|
||||||
service. ([#533])
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- **util**: Make combinators that contain closures implement `Debug`. They
|
|
||||||
previously wouldn't since closures never implement `Debug`. ([#552])
|
|
||||||
- **steer**: Implement `Clone` for `Steer`. ([#554])
|
|
||||||
- **spawn-ready**: SpawnReady now propagates the current `tracing` span to
|
|
||||||
spawned tasks ([#557])
|
|
||||||
- Only pull in `tracing` for the features that need it. ([#551])
|
|
||||||
|
|
||||||
[#542]: https://github.com/tower-rs/tower/pull/542
|
|
||||||
[#555]: https://github.com/tower-rs/tower/pull/555
|
|
||||||
[#557]: https://github.com/tower-rs/tower/pull/557
|
|
||||||
[#533]: https://github.com/tower-rs/tower/pull/533
|
|
||||||
[#551]: https://github.com/tower-rs/tower/pull/551
|
|
||||||
[#554]: https://github.com/tower-rs/tower/pull/554
|
|
||||||
[#552]: https://github.com/tower-rs/tower/pull/552
|
|
||||||
|
|
||||||
# 0.4.4 (January 20, 2021)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- **util**: Implement `Layer` for `Either<A, B>`. ([#531])
|
|
||||||
- **util**: Implement `Clone` for `FilterLayer`. ([#535])
|
|
||||||
- **timeout**: Implement `Clone` for `TimeoutLayer`. ([#535])
|
|
||||||
- **limit**: Implement `Clone` for `RateLimitLayer`. ([#535])
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Added "full" feature which turns on all other features. ([#532])
|
|
||||||
- **spawn-ready**: Avoid oneshot allocations. ([#538])
|
|
||||||
|
|
||||||
[#531]: https://github.com/tower-rs/tower/pull/531
|
|
||||||
[#532]: https://github.com/tower-rs/tower/pull/532
|
|
||||||
[#535]: https://github.com/tower-rs/tower/pull/535
|
|
||||||
[#538]: https://github.com/tower-rs/tower/pull/538
|
|
||||||
|
|
||||||
# 0.4.3 (January 13, 2021)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- **filter**: `Filter::check` and `AsyncFilter::check` methods which check a
|
|
||||||
request against the filter's `Predicate` ([#521])
|
|
||||||
- **filter**: Added `get_ref`, `get_mut`, and `into_inner` methods to `Filter`
|
|
||||||
and `AsyncFilter`, allowing access to the wrapped service ([#522])
|
|
||||||
- **util**: Added `layer` associated function to `AndThen`, `Then`,
|
|
||||||
`MapRequest`, `MapResponse`, and `MapResult` types. These return a `Layer`
|
|
||||||
that produces middleware of that type, as a convenience to avoid having to
|
|
||||||
import the `Layer` type separately. ([#524])
|
|
||||||
- **util**: Added missing `Clone` impls to `AndThenLayer`, `MapRequestLayer`,
|
|
||||||
and `MapErrLayer`, when the mapped function implements `Clone` ([#525])
|
|
||||||
- **util**: Added `FutureService::new` constructor, with less restrictive bounds
|
|
||||||
than the `future_service` free function ([#523])
|
|
||||||
|
|
||||||
[#521]: https://github.com/tower-rs/tower/pull/521
|
|
||||||
[#522]: https://github.com/tower-rs/tower/pull/522
|
|
||||||
[#523]: https://github.com/tower-rs/tower/pull/523
|
|
||||||
[#524]: https://github.com/tower-rs/tower/pull/524
|
|
||||||
[#525]: https://github.com/tower-rs/tower/pull/525
|
|
||||||
|
|
||||||
# 0.4.2 (January 11, 2021)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- Export `layer_fn` and `LayerFn` from the `tower::layer` module. ([#516])
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fix missing `Sync` implementation for `Buffer` and `ConcurrencyLimit` ([#518])
|
|
||||||
|
|
||||||
[#518]: https://github.com/tower-rs/tower/pull/518
|
|
||||||
[#516]: https://github.com/tower-rs/tower/pull/516
|
|
||||||
|
|
||||||
# 0.4.1 (January 7, 2021)
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Updated `tower-layer` to 0.3.1 to fix broken re-exports.
|
|
||||||
|
|
||||||
# 0.4.0 (January 7, 2021)
|
|
||||||
|
|
||||||
This is a major breaking release including a large number of changes. In
|
|
||||||
particular, this release updates `tower` to depend on Tokio 1.0, and moves all
|
|
||||||
middleware into the `tower` crate. In addition, Tower 0.4 reworks several
|
|
||||||
middleware APIs, as well as introducing new ones.
|
|
||||||
|
|
||||||
This release does *not* change the core `Service` or `Layer` traits, so `tower`
|
|
||||||
0.4 still depends on `tower-service` 0.3 and `tower-layer` 0.3. This means that
|
|
||||||
`tower` 0.4 is still compatible with libraries that depend on those crates.
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- **make**: Added `MakeService::into_service` and `MakeService::as_service` for
|
|
||||||
converting `MakeService`s into `Service`s ([#492])
|
|
||||||
- **steer**: Added `steer` middleware for routing requests to one of a set of
|
|
||||||
services ([#426])
|
|
||||||
- **util**: Added `MapRequest` middleware and `ServiceExt::map_request`, for
|
|
||||||
applying a function to a request before passing it to the inner service
|
|
||||||
([#435])
|
|
||||||
- **util**: Added `MapResponse` middleware and `ServiceExt::map_response`, for
|
|
||||||
applying a function to the `Response` type of an inner service after its
|
|
||||||
future completes ([#435])
|
|
||||||
- **util**: Added `MapErr` middleware and `ServiceExt::map_err`, for
|
|
||||||
applying a function to the `Error` returned by an inner service if it fails
|
|
||||||
([#396])
|
|
||||||
- **util**: Added `MapResult` middleware and `ServiceExt::map_result`, for
|
|
||||||
applying a function to the `Result` returned by an inner service's future
|
|
||||||
regardless of whether it succeeds or fails ([#499])
|
|
||||||
- **util**: Added `Then` middleware and `ServiceExt::then`, for chaining another
|
|
||||||
future after an inner service's future completes (with a `Response` or an
|
|
||||||
`Error`) ([#500])
|
|
||||||
- **util**: Added `AndThen` middleware and `ServiceExt::and_then`, for
|
|
||||||
chaining another future after an inner service's future completes successfully
|
|
||||||
([#485])
|
|
||||||
- **util**: Added `layer_fn`, for constructing a `Layer` from a function taking
|
|
||||||
a `Service` and returning a different `Service` ([#491])
|
|
||||||
- **util**: Added `FutureService`, which implements `Service` for a
|
|
||||||
`Future` whose `Output` type is a `Service` ([#496])
|
|
||||||
- **util**: Added `BoxService::layer` and `UnsyncBoxService::layer`, to make
|
|
||||||
constructing layers more ergonomic ([#503])
|
|
||||||
- **layer**: Added `Layer` impl for `&Layer` ([#446])
|
|
||||||
- **retry**: Added `Retry::get_ref`, `Retry::get_mut`, and `Retry::into_inner`
|
|
||||||
to access the inner service ([#463])
|
|
||||||
- **timeout**: Added `Timeout::get_ref`, `Timeout::get_mut`, and
|
|
||||||
`Timeout::into_inner` to access the inner service ([#463])
|
|
||||||
- **buffer**: Added `Clone` and `Copy` impls for `BufferLayer` (#[493])
|
|
||||||
- Several documentation improvements ([#442], [#444], [#445], [#449], [#487],
|
|
||||||
[#490], [#506]])
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- All middleware `tower-*` crates were merged into `tower` and placed
|
|
||||||
behind feature flags ([#432])
|
|
||||||
- Updated Tokio dependency to 1.0 ([#489])
|
|
||||||
- **builder**: Make `ServiceBuilder::service` take `self` by reference rather
|
|
||||||
than by value ([#504])
|
|
||||||
- **reconnect**: Return errors from `MakeService` in the response future, rather than
|
|
||||||
in `poll_ready`, allowing the reconnect service to be reused when a reconnect
|
|
||||||
fails ([#386], [#437])
|
|
||||||
- **discover**: Changed `Discover` to be a sealed trait alias for a
|
|
||||||
`TryStream<Item = Change>`. `Discover` implementations are now written by
|
|
||||||
implementing `Stream`. ([#443])
|
|
||||||
- **load**: Renamed the `Instrument` trait to `TrackCompletion` ([#445])
|
|
||||||
- **load**: Renamed `NoInstrument` to `CompleteOnResponse` ([#445])
|
|
||||||
- **balance**: Renamed `BalanceLayer` to `MakeBalanceLayer` ([#449])
|
|
||||||
- **balance**: Renamed `BalanceMake` to `MakeBalance` ([#449])
|
|
||||||
- **ready-cache**: Changed `ready_cache::error::Failed`'s `fmt::Debug` impl to
|
|
||||||
require the key type to also implement `fmt::Debug` ([#467])
|
|
||||||
- **filter**: Changed `Filter` and `Predicate` to use a synchronous function as
|
|
||||||
a predicate ([#508])
|
|
||||||
- **filter**: Renamed the previous `Filter` and `Predicate` (where `Predicate`s
|
|
||||||
returned a `Future`) to `AsyncFilter` and `AsyncPredicate` ([#508])
|
|
||||||
- **filter**: `Predicate`s now take a `Request` type by value and may return a
|
|
||||||
new request, potentially of a different type ([#508])
|
|
||||||
- **filter**: `Predicate`s may now return an error of any type ([#508])
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- **limit**: Fixed an issue where `RateLimit` services do not reset the remaining
|
|
||||||
count when rate limiting ([#438], [#439])
|
|
||||||
- **util**: Fixed a bug where `oneshot` futures panic if the service does not
|
|
||||||
immediately become ready ([#447])
|
|
||||||
- **ready-cache**: Fixed `ready_cache::error::Failed` not returning inner error types
|
|
||||||
via `Error::source` ([#467])
|
|
||||||
- **hedge**: Fixed an interaction with `buffer` where `buffer` slots were
|
|
||||||
eagerly reserved for hedge requests even if they were not sent ([#472])
|
|
||||||
- **hedge**: Fixed the use of a fixed 10 second bound on the hedge latency
|
|
||||||
histogram resulting on errors with longer-lived requests. The latency
|
|
||||||
histogram now automatically resizes ([#484])
|
|
||||||
- **buffer**: Fixed an issue where tasks waiting for buffer capacity were not
|
|
||||||
woken when a buffer is dropped, potentially resulting in a task leak ([#480])
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
|
|
||||||
- Remove `ServiceExt::ready`.
|
|
||||||
- **discover**: Removed `discover::stream` module, since `Discover` is now an
|
|
||||||
alias for `Stream` ([#443])
|
|
||||||
- **buffer**: Removed `MakeBalance::from_rng`, which caused all balancers to use
|
|
||||||
the same RNG ([#497])
|
|
||||||
|
|
||||||
[#432]: https://github.com/tower-rs/tower/pull/432
|
|
||||||
[#426]: https://github.com/tower-rs/tower/pull/426
|
|
||||||
[#435]: https://github.com/tower-rs/tower/pull/435
|
|
||||||
[#499]: https://github.com/tower-rs/tower/pull/499
|
|
||||||
[#386]: https://github.com/tower-rs/tower/pull/386
|
|
||||||
[#437]: https://github.com/tower-rs/tower/pull/487
|
|
||||||
[#438]: https://github.com/tower-rs/tower/pull/438
|
|
||||||
[#437]: https://github.com/tower-rs/tower/pull/439
|
|
||||||
[#443]: https://github.com/tower-rs/tower/pull/443
|
|
||||||
[#442]: https://github.com/tower-rs/tower/pull/442
|
|
||||||
[#444]: https://github.com/tower-rs/tower/pull/444
|
|
||||||
[#445]: https://github.com/tower-rs/tower/pull/445
|
|
||||||
[#446]: https://github.com/tower-rs/tower/pull/446
|
|
||||||
[#447]: https://github.com/tower-rs/tower/pull/447
|
|
||||||
[#449]: https://github.com/tower-rs/tower/pull/449
|
|
||||||
[#463]: https://github.com/tower-rs/tower/pull/463
|
|
||||||
[#396]: https://github.com/tower-rs/tower/pull/396
|
|
||||||
[#467]: https://github.com/tower-rs/tower/pull/467
|
|
||||||
[#472]: https://github.com/tower-rs/tower/pull/472
|
|
||||||
[#480]: https://github.com/tower-rs/tower/pull/480
|
|
||||||
[#484]: https://github.com/tower-rs/tower/pull/484
|
|
||||||
[#489]: https://github.com/tower-rs/tower/pull/489
|
|
||||||
[#497]: https://github.com/tower-rs/tower/pull/497
|
|
||||||
[#487]: https://github.com/tower-rs/tower/pull/487
|
|
||||||
[#493]: https://github.com/tower-rs/tower/pull/493
|
|
||||||
[#491]: https://github.com/tower-rs/tower/pull/491
|
|
||||||
[#495]: https://github.com/tower-rs/tower/pull/495
|
|
||||||
[#503]: https://github.com/tower-rs/tower/pull/503
|
|
||||||
[#504]: https://github.com/tower-rs/tower/pull/504
|
|
||||||
[#492]: https://github.com/tower-rs/tower/pull/492
|
|
||||||
[#500]: https://github.com/tower-rs/tower/pull/500
|
|
||||||
[#490]: https://github.com/tower-rs/tower/pull/490
|
|
||||||
[#506]: https://github.com/tower-rs/tower/pull/506
|
|
||||||
[#508]: https://github.com/tower-rs/tower/pull/508
|
|
||||||
[#485]: https://github.com/tower-rs/tower/pull/485
|
|
||||||
|
|
||||||
# 0.3.1 (January 17, 2020)
|
|
||||||
|
|
||||||
- Allow opting out of tracing/log (#410).
|
|
||||||
|
|
||||||
# 0.3.0 (December 19, 2019)
|
|
||||||
|
|
||||||
- Update all tower based crates to `0.3`.
|
|
||||||
- Update to `tokio 0.2`
|
|
||||||
- Update to `futures 0.3`
|
|
||||||
|
|
||||||
# 0.3.0-alpha.2 (September 30, 2019)
|
|
||||||
|
|
||||||
- Move to `futures-*-preview 0.3.0-alpha.19`
|
|
||||||
- Move to `pin-project 0.4`
|
|
||||||
|
|
||||||
# 0.3.0-alpha.1a (September 13, 2019)
|
|
||||||
|
|
||||||
- Update `tower-buffer` to `0.3.0-alpha.1b`
|
|
||||||
|
|
||||||
# 0.3.0-alpha.1 (September 11, 2019)
|
|
||||||
|
|
||||||
- Move to `std::future`
|
|
||||||
|
|
||||||
# 0.1.1 (July 19, 2019)
|
|
||||||
|
|
||||||
- Add `ServiceBuilder::into_inner`
|
|
||||||
|
|
||||||
# 0.1.0 (April 26, 2019)
|
|
||||||
|
|
||||||
- Initial release
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
Copyright (c) 2019 Tower Contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
|
||||||
person obtaining a copy of this software and associated
|
|
||||||
documentation files (the "Software"), to deal in the
|
|
||||||
Software without restriction, including without
|
|
||||||
limitation the rights to use, copy, modify, merge,
|
|
||||||
publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software
|
|
||||||
is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice
|
|
||||||
shall be included in all copies or substantial portions
|
|
||||||
of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
||||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
||||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
||||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
||||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
@ -1,190 +0,0 @@
|
||||||
# Tower
|
|
||||||
|
|
||||||
Tower is a library of modular and reusable components for building robust
|
|
||||||
networking clients and servers.
|
|
||||||
|
|
||||||
[![Crates.io][crates-badge]][crates-url]
|
|
||||||
[![Documentation][docs-badge]][docs-url]
|
|
||||||
[![Documentation (master)][docs-master-badge]][docs-master-url]
|
|
||||||
[![MIT licensed][mit-badge]][mit-url]
|
|
||||||
[![Build Status][actions-badge]][actions-url]
|
|
||||||
[![Discord chat][discord-badge]][discord-url]
|
|
||||||
|
|
||||||
[crates-badge]: https://img.shields.io/crates/v/tower.svg
|
|
||||||
[crates-url]: https://crates.io/crates/tower
|
|
||||||
[docs-badge]: https://docs.rs/tower/badge.svg
|
|
||||||
[docs-url]: https://docs.rs/tower
|
|
||||||
[docs-master-badge]: https://img.shields.io/badge/docs-master-blue
|
|
||||||
[docs-master-url]: https://tower-rs.github.io/tower/tower
|
|
||||||
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
|
|
||||||
[mit-url]: LICENSE
|
|
||||||
[actions-badge]: https://github.com/tower-rs/tower/workflows/CI/badge.svg
|
|
||||||
[actions-url]:https://github.com/tower-rs/tower/actions?query=workflow%3ACI
|
|
||||||
[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white
|
|
||||||
[discord-url]: https://discord.gg/EeF3cQw
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Tower aims to make it as easy as possible to build robust networking clients and
|
|
||||||
servers. It is protocol agnostic, but is designed around a request / response
|
|
||||||
pattern. If your protocol is entirely stream based, Tower may not be a good fit.
|
|
||||||
|
|
||||||
Tower provides a simple core abstraction, the [`Service`] trait, which
|
|
||||||
represents an asynchronous function taking a request and returning either a
|
|
||||||
response or an error. This abstraction can be used to model both clients and
|
|
||||||
servers.
|
|
||||||
|
|
||||||
Generic components, like [timeouts], [rate limiting], and [load balancing],
|
|
||||||
can be modeled as [`Service`]s that wrap some inner service and apply
|
|
||||||
additional behavior before or after the inner service is called. This allows
|
|
||||||
implementing these components in a protocol-agnostic, composable way. Typically,
|
|
||||||
such services are referred to as _middleware_.
|
|
||||||
|
|
||||||
An additional abstraction, the [`Layer`] trait, is used to compose
|
|
||||||
middleware with [`Service`]s. If a [`Service`] can be thought of as an
|
|
||||||
asynchronous function from a request type to a response type, a [`Layer`] is
|
|
||||||
a function taking a [`Service`] of one type and returning a [`Service`] of a
|
|
||||||
different type. The [`ServiceBuilder`] type is used to add middleware to a
|
|
||||||
service by composing it with multiple multiple [`Layer`]s.
|
|
||||||
|
|
||||||
### The Tower Ecosystem
|
|
||||||
|
|
||||||
Tower is made up of the following crates:
|
|
||||||
|
|
||||||
* [`tower`] (this crate)
|
|
||||||
* [`tower-service`]
|
|
||||||
* [`tower-layer`]
|
|
||||||
* [`tower-test`]
|
|
||||||
|
|
||||||
Since the [`Service`] and [`Layer`] traits are important integration points
|
|
||||||
for all libraries using Tower, they are kept as stable as possible, and
|
|
||||||
breaking changes are made rarely. Therefore, they are defined in separate
|
|
||||||
crates, [`tower-service`] and [`tower-layer`]. This crate contains
|
|
||||||
re-exports of those core traits, implementations of commonly-used
|
|
||||||
middleware, and [utilities] for working with [`Service`]s and [`Layer`]s.
|
|
||||||
Finally, the [`tower-test`] crate provides tools for testing programs using
|
|
||||||
Tower.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Tower provides an abstraction layer, and generic implementations of various
|
|
||||||
middleware. This means that the `tower` crate on its own does *not* provide
|
|
||||||
a working implementation of a network client or server. Instead, Tower's
|
|
||||||
[`Service` trait][`Service`] provides an integration point between
|
|
||||||
application code, libraries providing middleware implementations, and
|
|
||||||
libraries that implement servers and/or clients for various network
|
|
||||||
protocols.
|
|
||||||
|
|
||||||
Depending on your particular use case, you might use Tower in several ways:
|
|
||||||
|
|
||||||
* **Implementing application logic** for a networked program. You might
|
|
||||||
use the [`Service`] trait to model your application's behavior, and use
|
|
||||||
the middleware [provided by this crate][all_layers] and by other libraries
|
|
||||||
to add functionality to clients and servers provided by one or more
|
|
||||||
protocol implementations.
|
|
||||||
* **Implementing middleware** to add custom behavior to network clients and
|
|
||||||
servers in a reusable manner. This might be general-purpose middleware
|
|
||||||
(and if it is, please consider releasing your middleware as a library for
|
|
||||||
other Tower users!) or application-specific behavior that needs to be
|
|
||||||
shared between multiple clients or servers.
|
|
||||||
* **Implementing a network protocol**. Libraries that implement network
|
|
||||||
protocols (such as HTTP) can depend on `tower-service` to use the
|
|
||||||
[`Service`] trait as an integration point between the protocol and user
|
|
||||||
code. For example, a client for some protocol might implement [`Service`],
|
|
||||||
allowing users to add arbitrary Tower middleware to those clients.
|
|
||||||
Similarly, a server might be created from a user-provided [`Service`].
|
|
||||||
|
|
||||||
Additionally, when a network protocol requires functionality already
|
|
||||||
provided by existing Tower middleware, a protocol implementation might use
|
|
||||||
Tower middleware internally, as well as as an integration point.
|
|
||||||
|
|
||||||
### Library Support
|
|
||||||
|
|
||||||
A number of third-party libraries support Tower and the [`Service`] trait.
|
|
||||||
The following is an incomplete list of such libraries:
|
|
||||||
|
|
||||||
* [`hyper`]: A fast and correct low-level HTTP implementation.
|
|
||||||
* [`tonic`]: A [gRPC-over-HTTP/2][grpc] implementation built on top of
|
|
||||||
[`hyper`]. See [here][tonic-examples] for examples of using [`tonic`] with
|
|
||||||
Tower.
|
|
||||||
* [`warp`]: A lightweight, composable web framework. See
|
|
||||||
[here][warp-service] for details on using [`warp`] with Tower.
|
|
||||||
* [`tower-lsp`] and its fork, [`lspower`]: implementations of the [Language
|
|
||||||
Server Protocol][lsp] based on Tower.
|
|
||||||
* [`kube`]: Kubernetes client and futures controller runtime. [`kube::Client`]
|
|
||||||
makes use of the Tower ecosystem: [`tower`], [`tower-http`], and
|
|
||||||
[`tower-test`]. See [here][kube-example-minimal] and
|
|
||||||
[here][kube-example-trace] for examples of using [`kube`] with Tower.
|
|
||||||
|
|
||||||
[`hyper`]: https://crates.io/crates/hyper
|
|
||||||
[`tonic`]: https://crates.io/crates/tonic
|
|
||||||
[tonic-examples]: https://github.com/hyperium/tonic/tree/master/examples/src/tower
|
|
||||||
[grpc]: https://grpc.io
|
|
||||||
[`warp`]: https://crates.io/crates/warp
|
|
||||||
[warp-service]: https://docs.rs/warp/0.2.5/warp/fn.service.html
|
|
||||||
[`tower-lsp`]: https://crates.io/crates/tower-lsp
|
|
||||||
[`lspower`]: https://crates.io/crates/lspower
|
|
||||||
[lsp]: https://microsoft.github.io/language-server-protocol/
|
|
||||||
[`kube`]: https://crates.io/crates/kube
|
|
||||||
[`kube::Client`]: https://docs.rs/kube/latest/kube/struct.Client.html
|
|
||||||
[kube-example-minimal]: https://github.com/clux/kube-rs/blob/master/examples/custom_client.rs
|
|
||||||
[kube-example-trace]: https://github.com/clux/kube-rs/blob/master/examples/custom_client_trace.rs
|
|
||||||
[`tower-http`]: https://crates.io/crates/tower-http
|
|
||||||
|
|
||||||
If you're the maintainer of a crate that supports Tower, we'd love to add
|
|
||||||
your crate to this list! Please [open a PR] adding a brief description of
|
|
||||||
your library!
|
|
||||||
|
|
||||||
### Getting Started
|
|
||||||
|
|
||||||
The various middleware implementations provided by this crate are feature
|
|
||||||
flagged, so that users can only compile the parts of Tower they need. By
|
|
||||||
default, all the optional middleware are disabled.
|
|
||||||
|
|
||||||
To get started using all of Tower's optional middleware, add this to your
|
|
||||||
`Cargo.toml`:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
tower = { version = "0.4", features = ["full"] }
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, you can only enable some features. For example, to enable
|
|
||||||
only the [`retry`] and [`timeout`][timeouts] middleware, write:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
tower = { version = "0.4", features = ["retry", "timeout"] }
|
|
||||||
```
|
|
||||||
|
|
||||||
See [here][all_layers] for a complete list of all middleware provided by
|
|
||||||
Tower.
|
|
||||||
|
|
||||||
[`Service`]: https://docs.rs/tower/latest/tower/trait.Service.html
|
|
||||||
[`Layer`]: https://docs.rs/tower/latest/tower/trait.Layer.html
|
|
||||||
[all_layers]: https://docs.rs/tower/latest/tower/#modules
|
|
||||||
[timeouts]: https://docs.rs/tower/latest/tower/timeout/
|
|
||||||
[rate limiting]: https://docs.rs/tower/latest/tower/limit/rate
|
|
||||||
[load balancing]: https://docs.rs/tower/latest/tower/balance/
|
|
||||||
[`ServiceBuilder`]: https://docs.rs/tower/latest/tower/struct.ServiceBuilder.html
|
|
||||||
[utilities]: https://docs.rs/tower/latest/tower/trait.ServiceExt.html
|
|
||||||
[`tower`]: https://crates.io/crates/tower
|
|
||||||
[`tower-service`]: https://crates.io/crates/tower-service
|
|
||||||
[`tower-layer`]: https://crates.io/crates/tower-layer
|
|
||||||
[`tower-test`]: https://crates.io/crates/tower-test
|
|
||||||
[`retry`]: https://docs.rs/tower/latest/tower/retry
|
|
||||||
[open a PR]: https://github.com/tower-rs/tower/compare
|
|
||||||
|
|
||||||
|
|
||||||
## Supported Rust Versions
|
|
||||||
|
|
||||||
Tower will keep a rolling MSRV (minimum supported Rust version) policy of **at
|
|
||||||
least** 6 months. When increasing the MSRV, the new Rust version must have been
|
|
||||||
released at least six months ago. The current MSRV is 1.49.0.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is licensed under the [MIT license](LICENSE).
|
|
||||||
|
|
||||||
### Contribution
|
|
||||||
|
|
||||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
|
||||||
for inclusion in Tower by you, shall be licensed as MIT, without any additional
|
|
||||||
terms or conditions.
|
|
||||||
|
|
@ -1,828 +0,0 @@
|
||||||
//! Builder types to compose layers and services
|
|
||||||
|
|
||||||
use tower_layer::{Identity, Layer, Stack};
|
|
||||||
use tower_service::Service;
|
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
/// Declaratively construct [`Service`] values.
|
|
||||||
///
|
|
||||||
/// [`ServiceBuilder`] provides a [builder-like interface][builder] for composing
|
|
||||||
/// layers to be applied to a [`Service`].
|
|
||||||
///
|
|
||||||
/// # Service
|
|
||||||
///
|
|
||||||
/// A [`Service`] is a trait representing an asynchronous function of a request
|
|
||||||
/// to a response. It is similar to `async fn(Request) -> Result<Response, Error>`.
|
|
||||||
///
|
|
||||||
/// A [`Service`] is typically bound to a single transport, such as a TCP
|
|
||||||
/// connection. It defines how _all_ inbound or outbound requests are handled
|
|
||||||
/// by that connection.
|
|
||||||
///
|
|
||||||
/// [builder]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html
|
|
||||||
///
|
|
||||||
/// # Order
|
|
||||||
///
|
|
||||||
/// The order in which layers are added impacts how requests are handled. Layers
|
|
||||||
/// that are added first will be called with the request first. The argument to
|
|
||||||
/// `service` will be last to see the request.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # // this (and other) doctest is ignored because we don't have a way
|
|
||||||
/// # // to say that it should only be run with cfg(feature = "...")
|
|
||||||
/// # use tower::Service;
|
|
||||||
/// # use tower::builder::ServiceBuilder;
|
|
||||||
/// # #[cfg(all(feature = "buffer", feature = "limit"))]
|
|
||||||
/// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send {
|
|
||||||
/// ServiceBuilder::new()
|
|
||||||
/// .buffer(100)
|
|
||||||
/// .concurrency_limit(10)
|
|
||||||
/// .service(svc)
|
|
||||||
/// # ;
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// In the above example, the buffer layer receives the request first followed
|
|
||||||
/// by `concurrency_limit`. `buffer` enables up to 100 request to be in-flight
|
|
||||||
/// **on top of** the requests that have already been forwarded to the next
|
|
||||||
/// layer. Combined with `concurrency_limit`, this allows up to 110 requests to be
|
|
||||||
/// in-flight.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tower::Service;
|
|
||||||
/// # use tower::builder::ServiceBuilder;
|
|
||||||
/// # #[cfg(all(feature = "buffer", feature = "limit"))]
|
|
||||||
/// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send {
|
|
||||||
/// ServiceBuilder::new()
|
|
||||||
/// .concurrency_limit(10)
|
|
||||||
/// .buffer(100)
|
|
||||||
/// .service(svc)
|
|
||||||
/// # ;
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// The above example is similar, but the order of layers is reversed. Now,
|
|
||||||
/// `concurrency_limit` applies first and only allows 10 requests to be in-flight
|
|
||||||
/// total.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// A [`Service`] stack with a single layer:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tower::Service;
|
|
||||||
/// # use tower::builder::ServiceBuilder;
|
|
||||||
/// # #[cfg(feature = "limit")]
|
|
||||||
/// # use tower::limit::concurrency::ConcurrencyLimitLayer;
|
|
||||||
/// # #[cfg(feature = "limit")]
|
|
||||||
/// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send {
|
|
||||||
/// ServiceBuilder::new()
|
|
||||||
/// .concurrency_limit(5)
|
|
||||||
/// .service(svc);
|
|
||||||
/// # ;
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// A [`Service`] stack with _multiple_ layers that contain rate limiting,
|
|
||||||
/// in-flight request limits, and a channel-backed, clonable [`Service`]:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tower::Service;
|
|
||||||
/// # use tower::builder::ServiceBuilder;
|
|
||||||
/// # use std::time::Duration;
|
|
||||||
/// # #[cfg(all(feature = "buffer", feature = "limit"))]
|
|
||||||
/// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send {
|
|
||||||
/// ServiceBuilder::new()
|
|
||||||
/// .buffer(5)
|
|
||||||
/// .concurrency_limit(5)
|
|
||||||
/// .rate_limit(5, Duration::from_secs(1))
|
|
||||||
/// .service(svc);
|
|
||||||
/// # ;
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Service`]: crate::Service
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ServiceBuilder<L> {
|
|
||||||
layer: L,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ServiceBuilder<Identity> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ServiceBuilder<Identity> {
|
|
||||||
/// Create a new [`ServiceBuilder`].
|
|
||||||
pub fn new() -> Self {
|
|
||||||
ServiceBuilder {
|
|
||||||
layer: Identity::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<L> ServiceBuilder<L> {
|
|
||||||
/// Add a new layer `T` into the [`ServiceBuilder`].
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with the service provided by a user-defined
|
|
||||||
/// [`Layer`]. The provided layer must implement the [`Layer`] trait.
|
|
||||||
///
|
|
||||||
/// [`Layer`]: crate::Layer
|
|
||||||
pub fn layer<T>(self, layer: T) -> ServiceBuilder<Stack<T, L>> {
|
|
||||||
ServiceBuilder {
|
|
||||||
layer: Stack::new(layer, self.layer),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Optionally add a new layer `T` into the [`ServiceBuilder`].
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use std::time::Duration;
|
|
||||||
/// # use tower::Service;
|
|
||||||
/// # use tower::builder::ServiceBuilder;
|
|
||||||
/// # use tower::timeout::TimeoutLayer;
|
|
||||||
/// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send {
|
|
||||||
/// # let timeout = Some(Duration::new(10, 0));
|
|
||||||
/// // Apply a timeout if configured
|
|
||||||
/// ServiceBuilder::new()
|
|
||||||
/// .option_layer(timeout.map(TimeoutLayer::new))
|
|
||||||
/// .service(svc)
|
|
||||||
/// # ;
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn option_layer<T>(
|
|
||||||
self,
|
|
||||||
layer: Option<T>,
|
|
||||||
) -> ServiceBuilder<Stack<crate::util::Either<T, Identity>, L>> {
|
|
||||||
self.layer(crate::util::option_layer(layer))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a [`Layer`] built from a function that accepts a service and returns another service.
|
|
||||||
///
|
|
||||||
/// See the documentation for [`layer_fn`] for more details.
|
|
||||||
///
|
|
||||||
/// [`layer_fn`]: crate::layer::layer_fn
|
|
||||||
pub fn layer_fn<F>(self, f: F) -> ServiceBuilder<Stack<crate::layer::LayerFn<F>, L>> {
|
|
||||||
self.layer(crate::layer::layer_fn(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Buffer requests when the next layer is not ready.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`Buffer`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// [`Buffer`]: crate::buffer
|
|
||||||
#[cfg(feature = "buffer")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "buffer")))]
|
|
||||||
pub fn buffer<Request>(
|
|
||||||
self,
|
|
||||||
bound: usize,
|
|
||||||
) -> ServiceBuilder<Stack<crate::buffer::BufferLayer<Request>, L>> {
|
|
||||||
self.layer(crate::buffer::BufferLayer::new(bound))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Limit the max number of in-flight requests.
|
|
||||||
///
|
|
||||||
/// A request is in-flight from the time the request is received until the
|
|
||||||
/// response future completes. This includes the time spent in the next
|
|
||||||
/// layers.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the
|
|
||||||
/// [`ConcurrencyLimit`] middleware.
|
|
||||||
///
|
|
||||||
/// [`ConcurrencyLimit`]: crate::limit::concurrency
|
|
||||||
#[cfg(feature = "limit")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "limit")))]
|
|
||||||
pub fn concurrency_limit(
|
|
||||||
self,
|
|
||||||
max: usize,
|
|
||||||
) -> ServiceBuilder<Stack<crate::limit::ConcurrencyLimitLayer, L>> {
|
|
||||||
self.layer(crate::limit::ConcurrencyLimitLayer::new(max))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Drop requests when the next layer is unable to respond to requests.
|
|
||||||
///
|
|
||||||
/// Usually, when a service or middleware does not have capacity to process a
|
|
||||||
/// request (i.e., [`poll_ready`] returns [`Pending`]), the caller waits until
|
|
||||||
/// capacity becomes available.
|
|
||||||
///
|
|
||||||
/// [`LoadShed`] immediately responds with an error when the next layer is
|
|
||||||
/// out of capacity.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`LoadShed`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// [`LoadShed`]: crate::load_shed
|
|
||||||
/// [`poll_ready`]: crate::Service::poll_ready
|
|
||||||
/// [`Pending`]: std::task::Poll::Pending
|
|
||||||
#[cfg(feature = "load-shed")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "load-shed")))]
|
|
||||||
pub fn load_shed(self) -> ServiceBuilder<Stack<crate::load_shed::LoadShedLayer, L>> {
|
|
||||||
self.layer(crate::load_shed::LoadShedLayer::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Limit requests to at most `num` per the given duration.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`RateLimit`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// [`RateLimit`]: crate::limit::rate
|
|
||||||
#[cfg(feature = "limit")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "limit")))]
|
|
||||||
pub fn rate_limit(
|
|
||||||
self,
|
|
||||||
num: u64,
|
|
||||||
per: std::time::Duration,
|
|
||||||
) -> ServiceBuilder<Stack<crate::limit::RateLimitLayer, L>> {
|
|
||||||
self.layer(crate::limit::RateLimitLayer::new(num, per))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retry failed requests according to the given [retry policy][policy].
|
|
||||||
///
|
|
||||||
/// `policy` determines which failed requests will be retried. It must
|
|
||||||
/// implement the [`retry::Policy`][policy] trait.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`Retry`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// [`Retry`]: crate::retry
|
|
||||||
/// [policy]: crate::retry::Policy
|
|
||||||
#[cfg(feature = "retry")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "retry")))]
|
|
||||||
pub fn retry<P>(self, policy: P) -> ServiceBuilder<Stack<crate::retry::RetryLayer<P>, L>> {
|
|
||||||
self.layer(crate::retry::RetryLayer::new(policy))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fail requests that take longer than `timeout`.
|
|
||||||
///
|
|
||||||
/// If the next layer takes more than `timeout` to respond to a request,
|
|
||||||
/// processing is terminated and an error is returned.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`timeout`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// [`timeout`]: crate::timeout
|
|
||||||
#[cfg(feature = "timeout")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "timeout")))]
|
|
||||||
pub fn timeout(
|
|
||||||
self,
|
|
||||||
timeout: std::time::Duration,
|
|
||||||
) -> ServiceBuilder<Stack<crate::timeout::TimeoutLayer, L>> {
|
|
||||||
self.layer(crate::timeout::TimeoutLayer::new(timeout))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Conditionally reject requests based on `predicate`.
|
|
||||||
///
|
|
||||||
/// `predicate` must implement the [`Predicate`] trait.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`Filter`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// [`Filter`]: crate::filter
|
|
||||||
/// [`Predicate`]: crate::filter::Predicate
|
|
||||||
#[cfg(feature = "filter")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "filter")))]
|
|
||||||
pub fn filter<P>(
|
|
||||||
self,
|
|
||||||
predicate: P,
|
|
||||||
) -> ServiceBuilder<Stack<crate::filter::FilterLayer<P>, L>> {
|
|
||||||
self.layer(crate::filter::FilterLayer::new(predicate))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Conditionally reject requests based on an asynchronous `predicate`.
|
|
||||||
///
|
|
||||||
/// `predicate` must implement the [`AsyncPredicate`] trait.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`AsyncFilter`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// [`AsyncFilter`]: crate::filter::AsyncFilter
|
|
||||||
/// [`AsyncPredicate`]: crate::filter::AsyncPredicate
|
|
||||||
#[cfg(feature = "filter")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "filter")))]
|
|
||||||
pub fn filter_async<P>(
|
|
||||||
self,
|
|
||||||
predicate: P,
|
|
||||||
) -> ServiceBuilder<Stack<crate::filter::AsyncFilterLayer<P>, L>> {
|
|
||||||
self.layer(crate::filter::AsyncFilterLayer::new(predicate))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map one request type to another.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`MapRequest`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Changing the type of a request:
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use tower::ServiceBuilder;
|
|
||||||
/// use tower::ServiceExt;
|
|
||||||
///
|
|
||||||
/// # #[tokio::main]
|
|
||||||
/// # async fn main() -> Result<(), ()> {
|
|
||||||
/// // Suppose we have some `Service` whose request type is `String`:
|
|
||||||
/// let string_svc = tower::service_fn(|request: String| async move {
|
|
||||||
/// println!("request: {}", request);
|
|
||||||
/// Ok(())
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// // ...but we want to call that service with a `usize`. What do we do?
|
|
||||||
///
|
|
||||||
/// let usize_svc = ServiceBuilder::new()
|
|
||||||
/// // Add a middlware that converts the request type to a `String`:
|
|
||||||
/// .map_request(|request: usize| format!("{}", request))
|
|
||||||
/// // ...and wrap the string service with that middleware:
|
|
||||||
/// .service(string_svc);
|
|
||||||
///
|
|
||||||
/// // Now, we can call that service with a `usize`:
|
|
||||||
/// usize_svc.oneshot(42).await?;
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Modifying the request value:
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use tower::ServiceBuilder;
|
|
||||||
/// use tower::ServiceExt;
|
|
||||||
///
|
|
||||||
/// # #[tokio::main]
|
|
||||||
/// # async fn main() -> Result<(), ()> {
|
|
||||||
/// // A service that takes a number and returns it:
|
|
||||||
/// let svc = tower::service_fn(|request: usize| async move {
|
|
||||||
/// Ok(request)
|
|
||||||
/// });
|
|
||||||
///
|
|
||||||
/// let svc = ServiceBuilder::new()
|
|
||||||
/// // Add a middleware that adds 1 to each request
|
|
||||||
/// .map_request(|request: usize| request + 1)
|
|
||||||
/// .service(svc);
|
|
||||||
///
|
|
||||||
/// let response = svc.oneshot(1).await?;
|
|
||||||
/// assert_eq!(response, 2);
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`MapRequest`]: crate::util::MapRequest
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn map_request<F, R1, R2>(
|
|
||||||
self,
|
|
||||||
f: F,
|
|
||||||
) -> ServiceBuilder<Stack<crate::util::MapRequestLayer<F>, L>>
|
|
||||||
where
|
|
||||||
F: FnMut(R1) -> R2 + Clone,
|
|
||||||
{
|
|
||||||
self.layer(crate::util::MapRequestLayer::new(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map one response type to another.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`MapResponse`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// See the documentation for the [`map_response` combinator] for details.
|
|
||||||
///
|
|
||||||
/// [`MapResponse`]: crate::util::MapResponse
|
|
||||||
/// [`map_response` combinator]: crate::util::ServiceExt::map_response
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn map_response<F>(
|
|
||||||
self,
|
|
||||||
f: F,
|
|
||||||
) -> ServiceBuilder<Stack<crate::util::MapResponseLayer<F>, L>> {
|
|
||||||
self.layer(crate::util::MapResponseLayer::new(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Map one error type to another.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`MapErr`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// See the documentation for the [`map_err` combinator] for details.
|
|
||||||
///
|
|
||||||
/// [`MapErr`]: crate::util::MapErr
|
|
||||||
/// [`map_err` combinator]: crate::util::ServiceExt::map_err
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn map_err<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::MapErrLayer<F>, L>> {
|
|
||||||
self.layer(crate::util::MapErrLayer::new(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Composes a function that transforms futures produced by the service.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`MapFutureLayer`] middleware.
|
|
||||||
///
|
|
||||||
/// See the documentation for the [`map_future`] combinator for details.
|
|
||||||
///
|
|
||||||
/// [`MapFutureLayer`]: crate::util::MapFutureLayer
|
|
||||||
/// [`map_future`]: crate::util::ServiceExt::map_future
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn map_future<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::MapFutureLayer<F>, L>> {
|
|
||||||
self.layer(crate::util::MapFutureLayer::new(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Apply an asynchronous function after the service, regardless of whether the future
|
|
||||||
/// succeeds or fails.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`Then`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// This is similar to the [`map_response`] and [`map_err`] functions,
|
|
||||||
/// except that the *same* function is invoked when the service's future
|
|
||||||
/// completes, whether it completes successfully or fails. This function
|
|
||||||
/// takes the [`Result`] returned by the service's future, and returns a
|
|
||||||
/// [`Result`].
|
|
||||||
///
|
|
||||||
/// See the documentation for the [`then` combinator] for details.
|
|
||||||
///
|
|
||||||
/// [`Then`]: crate::util::Then
|
|
||||||
/// [`then` combinator]: crate::util::ServiceExt::then
|
|
||||||
/// [`map_response`]: ServiceBuilder::map_response
|
|
||||||
/// [`map_err`]: ServiceBuilder::map_err
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn then<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::ThenLayer<F>, L>> {
|
|
||||||
self.layer(crate::util::ThenLayer::new(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Executes a new future after this service's future resolves. This does
|
|
||||||
/// not alter the behaviour of the [`poll_ready`] method.
|
|
||||||
///
|
|
||||||
/// This method can be used to change the [`Response`] type of the service
|
|
||||||
/// into a different type. You can use this method to chain along a computation once the
|
|
||||||
/// service's response has been resolved.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`AndThen`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// See the documentation for the [`and_then` combinator] for details.
|
|
||||||
///
|
|
||||||
/// [`Response`]: crate::Service::Response
|
|
||||||
/// [`poll_ready`]: crate::Service::poll_ready
|
|
||||||
/// [`and_then` combinator]: crate::util::ServiceExt::and_then
|
|
||||||
/// [`AndThen`]: crate::util::AndThen
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn and_then<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::AndThenLayer<F>, L>> {
|
|
||||||
self.layer(crate::util::AndThenLayer::new(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Maps this service's result type (`Result<Self::Response, Self::Error>`)
|
|
||||||
/// to a different value, regardless of whether the future succeeds or
|
|
||||||
/// fails.
|
|
||||||
///
|
|
||||||
/// This wraps the inner service with an instance of the [`MapResult`]
|
|
||||||
/// middleware.
|
|
||||||
///
|
|
||||||
/// See the documentation for the [`map_result` combinator] for details.
|
|
||||||
///
|
|
||||||
/// [`map_result` combinator]: crate::util::ServiceExt::map_result
|
|
||||||
/// [`MapResult`]: crate::util::MapResult
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn map_result<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::MapResultLayer<F>, L>> {
|
|
||||||
self.layer(crate::util::MapResultLayer::new(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the underlying `Layer` implementation.
|
|
||||||
pub fn into_inner(self) -> L {
|
|
||||||
self.layer
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrap the service `S` with the middleware provided by this
|
|
||||||
/// [`ServiceBuilder`]'s [`Layer`]'s, returning a new [`Service`].
|
|
||||||
///
|
|
||||||
/// [`Layer`]: crate::Layer
|
|
||||||
/// [`Service`]: crate::Service
|
|
||||||
pub fn service<S>(&self, service: S) -> L::Service
|
|
||||||
where
|
|
||||||
L: Layer<S>,
|
|
||||||
{
|
|
||||||
self.layer.layer(service)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrap the async function `F` with the middleware provided by this [`ServiceBuilder`]'s
|
|
||||||
/// [`Layer`]s, returning a new [`Service`].
|
|
||||||
///
|
|
||||||
/// This is a convenience method which is equivalent to calling
|
|
||||||
/// [`ServiceBuilder::service`] with a [`service_fn`], like this:
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use tower::{ServiceBuilder, service_fn};
|
|
||||||
/// # async fn handler_fn(_: ()) -> Result<(), ()> { Ok(()) }
|
|
||||||
/// # let _ = {
|
|
||||||
/// ServiceBuilder::new()
|
|
||||||
/// // ...
|
|
||||||
/// .service(service_fn(handler_fn))
|
|
||||||
/// # };
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use std::time::Duration;
|
|
||||||
/// use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn};
|
|
||||||
///
|
|
||||||
/// # #[tokio::main]
|
|
||||||
/// # async fn main() -> Result<(), BoxError> {
|
|
||||||
/// async fn handle(request: &'static str) -> Result<&'static str, BoxError> {
|
|
||||||
/// Ok(request)
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let svc = ServiceBuilder::new()
|
|
||||||
/// .buffer(1024)
|
|
||||||
/// .timeout(Duration::from_secs(10))
|
|
||||||
/// .service_fn(handle);
|
|
||||||
///
|
|
||||||
/// let response = svc.oneshot("foo").await?;
|
|
||||||
///
|
|
||||||
/// assert_eq!(response, "foo");
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`Layer`]: crate::Layer
|
|
||||||
/// [`Service`]: crate::Service
|
|
||||||
/// [`service_fn`]: crate::service_fn
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn service_fn<F>(self, f: F) -> L::Service
|
|
||||||
where
|
|
||||||
L: Layer<crate::util::ServiceFn<F>>,
|
|
||||||
{
|
|
||||||
self.service(crate::util::service_fn(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that the builder implements `Clone`.
|
|
||||||
///
|
|
||||||
/// This can be useful when debugging type errors in `ServiceBuilder`s with lots of layers.
|
|
||||||
///
|
|
||||||
/// Doesn't actually change the builder but serves as a type check.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use tower::ServiceBuilder;
|
|
||||||
///
|
|
||||||
/// let builder = ServiceBuilder::new()
|
|
||||||
/// // Do something before processing the request
|
|
||||||
/// .map_request(|request: String| {
|
|
||||||
/// println!("got request!");
|
|
||||||
/// request
|
|
||||||
/// })
|
|
||||||
/// // Ensure our `ServiceBuilder` can be cloned
|
|
||||||
/// .check_clone()
|
|
||||||
/// // Do something after processing the request
|
|
||||||
/// .map_response(|response: String| {
|
|
||||||
/// println!("got response!");
|
|
||||||
/// response
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn check_clone(self) -> Self
|
|
||||||
where
|
|
||||||
Self: Clone,
|
|
||||||
{
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that the builder when given a service of type `S` produces a service that implements
|
|
||||||
/// `Clone`.
|
|
||||||
///
|
|
||||||
/// This can be useful when debugging type errors in `ServiceBuilder`s with lots of layers.
|
|
||||||
///
|
|
||||||
/// Doesn't actually change the builder but serves as a type check.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use tower::ServiceBuilder;
|
|
||||||
///
|
|
||||||
/// # #[derive(Clone)]
|
|
||||||
/// # struct MyService;
|
|
||||||
/// #
|
|
||||||
/// let builder = ServiceBuilder::new()
|
|
||||||
/// // Do something before processing the request
|
|
||||||
/// .map_request(|request: String| {
|
|
||||||
/// println!("got request!");
|
|
||||||
/// request
|
|
||||||
/// })
|
|
||||||
/// // Ensure that the service produced when given a `MyService` implements
|
|
||||||
/// .check_service_clone::<MyService>()
|
|
||||||
/// // Do something after processing the request
|
|
||||||
/// .map_response(|response: String| {
|
|
||||||
/// println!("got response!");
|
|
||||||
/// response
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn check_service_clone<S>(self) -> Self
|
|
||||||
where
|
|
||||||
L: Layer<S>,
|
|
||||||
L::Service: Clone,
|
|
||||||
{
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that the builder when given a service of type `S` produces a service with the given
|
|
||||||
/// request, response, and error types.
|
|
||||||
///
|
|
||||||
/// This can be useful when debugging type errors in `ServiceBuilder`s with lots of layers.
|
|
||||||
///
|
|
||||||
/// Doesn't actually change the builder but serves as a type check.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// use tower::ServiceBuilder;
|
|
||||||
/// use std::task::{Poll, Context};
|
|
||||||
/// use tower::{Service, ServiceExt};
|
|
||||||
///
|
|
||||||
/// // An example service
|
|
||||||
/// struct MyService;
|
|
||||||
///
|
|
||||||
/// impl Service<Request> for MyService {
|
|
||||||
/// type Response = Response;
|
|
||||||
/// type Error = Error;
|
|
||||||
/// type Future = futures_util::future::Ready<Result<Response, Error>>;
|
|
||||||
///
|
|
||||||
/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
/// // ...
|
|
||||||
/// # todo!()
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn call(&mut self, request: Request) -> Self::Future {
|
|
||||||
/// // ...
|
|
||||||
/// # todo!()
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// struct Request;
|
|
||||||
/// struct Response;
|
|
||||||
/// struct Error;
|
|
||||||
///
|
|
||||||
/// struct WrappedResponse(Response);
|
|
||||||
///
|
|
||||||
/// let builder = ServiceBuilder::new()
|
|
||||||
/// // At this point in the builder if given a `MyService` it produces a service that
|
|
||||||
/// // accepts `Request`s, produces `Response`s, and fails with `Error`s
|
|
||||||
/// .check_service::<MyService, Request, Response, Error>()
|
|
||||||
/// // Wrap responses in `WrappedResponse`
|
|
||||||
/// .map_response(|response: Response| WrappedResponse(response))
|
|
||||||
/// // Now the response type will be `WrappedResponse`
|
|
||||||
/// .check_service::<MyService, _, WrappedResponse, _>();
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn check_service<S, T, U, E>(self) -> Self
|
|
||||||
where
|
|
||||||
L: Layer<S>,
|
|
||||||
L::Service: Service<T, Response = U, Error = E>,
|
|
||||||
{
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This wraps the inner service with the [`Layer`] returned by [`BoxService::layer()`].
|
|
||||||
///
|
|
||||||
/// See that method for more details.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use tower::{Service, ServiceBuilder, BoxError, util::BoxService};
|
|
||||||
/// use std::time::Duration;
|
|
||||||
/// #
|
|
||||||
/// # struct Request;
|
|
||||||
/// # struct Response;
|
|
||||||
/// # impl Response {
|
|
||||||
/// # fn new() -> Self { Self }
|
|
||||||
/// # }
|
|
||||||
///
|
|
||||||
/// let service: BoxService<Request, Response, BoxError> = ServiceBuilder::new()
|
|
||||||
/// .boxed()
|
|
||||||
/// .load_shed()
|
|
||||||
/// .concurrency_limit(64)
|
|
||||||
/// .timeout(Duration::from_secs(10))
|
|
||||||
/// .service_fn(|req: Request| async {
|
|
||||||
/// Ok::<_, BoxError>(Response::new())
|
|
||||||
/// });
|
|
||||||
/// # let service = assert_service(service);
|
|
||||||
/// # fn assert_service<S, R>(svc: S) -> S
|
|
||||||
/// # where S: Service<R> { svc }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`BoxService::layer()`]: crate::util::BoxService::layer()
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn boxed<S, R>(
|
|
||||||
self,
|
|
||||||
) -> ServiceBuilder<
|
|
||||||
Stack<
|
|
||||||
tower_layer::LayerFn<
|
|
||||||
fn(
|
|
||||||
L::Service,
|
|
||||||
) -> crate::util::BoxService<
|
|
||||||
R,
|
|
||||||
<L::Service as Service<R>>::Response,
|
|
||||||
<L::Service as Service<R>>::Error,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
L,
|
|
||||||
>,
|
|
||||||
>
|
|
||||||
where
|
|
||||||
L: Layer<S>,
|
|
||||||
L::Service: Service<R> + Send + 'static,
|
|
||||||
<L::Service as Service<R>>::Future: Send + 'static,
|
|
||||||
{
|
|
||||||
self.layer(crate::util::BoxService::layer())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This wraps the inner service with the [`Layer`] returned by [`BoxCloneService::layer()`].
|
|
||||||
///
|
|
||||||
/// This is similar to the [`boxed`] method, but it requires that `Self` implement
|
|
||||||
/// [`Clone`], and the returned boxed service implements [`Clone`].
|
|
||||||
///
|
|
||||||
/// See [`BoxCloneService`] for more details.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use tower::{Service, ServiceBuilder, BoxError, util::BoxCloneService};
|
|
||||||
/// use std::time::Duration;
|
|
||||||
/// #
|
|
||||||
/// # struct Request;
|
|
||||||
/// # struct Response;
|
|
||||||
/// # impl Response {
|
|
||||||
/// # fn new() -> Self { Self }
|
|
||||||
/// # }
|
|
||||||
///
|
|
||||||
/// let service: BoxCloneService<Request, Response, BoxError> = ServiceBuilder::new()
|
|
||||||
/// .boxed_clone()
|
|
||||||
/// .load_shed()
|
|
||||||
/// .concurrency_limit(64)
|
|
||||||
/// .timeout(Duration::from_secs(10))
|
|
||||||
/// .service_fn(|req: Request| async {
|
|
||||||
/// Ok::<_, BoxError>(Response::new())
|
|
||||||
/// });
|
|
||||||
/// # let service = assert_service(service);
|
|
||||||
///
|
|
||||||
/// // The boxed service can still be cloned.
|
|
||||||
/// service.clone();
|
|
||||||
/// # fn assert_service<S, R>(svc: S) -> S
|
|
||||||
/// # where S: Service<R> { svc }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// [`BoxCloneService::layer()`]: crate::util::BoxCloneService::layer()
|
|
||||||
/// [`BoxCloneService`]: crate::util::BoxCloneService
|
|
||||||
/// [`boxed`]: Self::boxed
|
|
||||||
#[cfg(feature = "util")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "util")))]
|
|
||||||
pub fn boxed_clone<S, R>(
|
|
||||||
self,
|
|
||||||
) -> ServiceBuilder<
|
|
||||||
Stack<
|
|
||||||
tower_layer::LayerFn<
|
|
||||||
fn(
|
|
||||||
L::Service,
|
|
||||||
) -> crate::util::BoxCloneService<
|
|
||||||
R,
|
|
||||||
<L::Service as Service<R>>::Response,
|
|
||||||
<L::Service as Service<R>>::Error,
|
|
||||||
>,
|
|
||||||
>,
|
|
||||||
L,
|
|
||||||
>,
|
|
||||||
>
|
|
||||||
where
|
|
||||||
L: Layer<S>,
|
|
||||||
L::Service: Service<R> + Clone + Send + 'static,
|
|
||||||
<L::Service as Service<R>>::Future: Send + 'static,
|
|
||||||
{
|
|
||||||
self.layer(crate::util::BoxCloneService::layer())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<L: fmt::Debug> fmt::Debug for ServiceBuilder<L> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_tuple("ServiceBuilder").field(&self.layer).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S, L> Layer<S> for ServiceBuilder<L>
|
|
||||||
where
|
|
||||||
L: Layer<S>,
|
|
||||||
{
|
|
||||||
type Service = L::Service;
|
|
||||||
|
|
||||||
fn layer(&self, inner: S) -> Self::Service {
|
|
||||||
self.layer.layer(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
//! A collection of [`Layer`] based tower services
|
|
||||||
//!
|
|
||||||
//! [`Layer`]: crate::Layer
|
|
||||||
|
|
||||||
pub use tower_layer::{layer_fn, Layer, LayerFn};
|
|
||||||
|
|
||||||
/// Utilities for combining layers
|
|
||||||
///
|
|
||||||
/// [`Identity`]: crate::layer::util::Identity
|
|
||||||
/// [`Layer`]: crate::Layer
|
|
||||||
/// [`Stack`]: crate::layer::util::Stack
|
|
||||||
pub mod util {
|
|
||||||
pub use tower_layer::{Identity, Stack};
|
|
||||||
}
|
|
||||||
|
|
@ -8,8 +8,6 @@ pub mod discover;
|
||||||
|
|
||||||
pub mod make;
|
pub mod make;
|
||||||
|
|
||||||
pub mod builder;
|
|
||||||
pub mod layer;
|
|
||||||
|
|
||||||
#[allow(unreachable_pub)]
|
#[allow(unreachable_pub)]
|
||||||
mod sealed {
|
mod sealed {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue