mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-08 00:00:24 +02:00
Update to tower-http 0.4 (#1783)
This commit is contained in:
@@ -29,7 +29,7 @@ axum = { path = "../axum", version = "0.6.0", features = ["headers"] }
|
|||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
hyper = "0.14"
|
hyper = "0.14"
|
||||||
tokio = { version = "1.0", features = ["macros"] }
|
tokio = { version = "1.0", features = ["macros"] }
|
||||||
tower-http = { version = "0.3.4", features = ["limit"] }
|
tower-http = { version = "0.4", features = ["limit"] }
|
||||||
|
|
||||||
[package.metadata.cargo-public-api-crates]
|
[package.metadata.cargo-public-api-crates]
|
||||||
allowed = [
|
allowed = [
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ and this project adheres to [Semantic Versioning].
|
|||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- **breaking:** `SpaRouter::handle_error` has been removed ([#1783])
|
||||||
- **breaking:** Change casing of `ProtoBuf` to `Protobuf` ([#1595])
|
- **breaking:** Change casing of `ProtoBuf` to `Protobuf` ([#1595])
|
||||||
|
|
||||||
|
[#1783]: https://github.com/tokio-rs/axum/pull/1783
|
||||||
[#1595]: https://github.com/tokio-rs/axum/pull/1595
|
[#1595]: https://github.com/tokio-rs/axum/pull/1595
|
||||||
|
|
||||||
# 0.5.0 (12. February, 2022)
|
# 0.5.0 (12. February, 2022)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ mime = "0.3"
|
|||||||
pin-project-lite = "0.2"
|
pin-project-lite = "0.2"
|
||||||
tokio = "1.19"
|
tokio = "1.19"
|
||||||
tower = { version = "0.4", default_features = false, features = ["util"] }
|
tower = { version = "0.4", default_features = false, features = ["util"] }
|
||||||
tower-http = { version = "0.3", features = ["map-response-body"] }
|
tower-http = { version = "0.4", features = ["map-response-body"] }
|
||||||
tower-layer = "0.3"
|
tower-layer = "0.3"
|
||||||
tower-service = "0.3"
|
tower-service = "0.3"
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
serde_json = "1.0.71"
|
serde_json = "1.0.71"
|
||||||
tokio = { version = "1.14", features = ["full"] }
|
tokio = { version = "1.14", features = ["full"] }
|
||||||
tower = { version = "0.4", features = ["util"] }
|
tower = { version = "0.4", features = ["util"] }
|
||||||
tower-http = { version = "0.3", features = ["map-response-body", "timeout"] }
|
tower-http = { version = "0.4", features = ["map-response-body", "timeout"] }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
|||||||
@@ -1,23 +1,15 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
body::{Body, HttpBody},
|
body::{Body, HttpBody},
|
||||||
error_handling::HandleError,
|
|
||||||
response::IntoResponse,
|
|
||||||
routing::{get_service, Route},
|
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use http::{Request, StatusCode};
|
|
||||||
use std::{
|
use std::{
|
||||||
any::type_name,
|
any::type_name,
|
||||||
convert::Infallible,
|
|
||||||
fmt,
|
fmt,
|
||||||
future::{ready, Ready},
|
|
||||||
io,
|
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use tower_http::services::{ServeDir, ServeFile};
|
use tower_http::services::{ServeDir, ServeFile};
|
||||||
use tower_service::Service;
|
|
||||||
|
|
||||||
/// Router for single page applications.
|
/// Router for single page applications.
|
||||||
///
|
///
|
||||||
@@ -50,10 +42,9 @@ use tower_service::Service;
|
|||||||
/// - `GET /some/other/path` will serve `index.html` since there isn't another
|
/// - `GET /some/other/path` will serve `index.html` since there isn't another
|
||||||
/// route for it
|
/// route for it
|
||||||
/// - `GET /api/foo` will serve the `api_foo` handler function
|
/// - `GET /api/foo` will serve the `api_foo` handler function
|
||||||
pub struct SpaRouter<S = (), B = Body, T = (), F = fn(io::Error) -> Ready<StatusCode>> {
|
pub struct SpaRouter<S = (), B = Body> {
|
||||||
paths: Arc<Paths>,
|
paths: Arc<Paths>,
|
||||||
handle_error: F,
|
_marker: PhantomData<fn() -> (S, B)>,
|
||||||
_marker: PhantomData<fn() -> (S, B, T)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -63,7 +54,7 @@ struct Paths {
|
|||||||
index_file: PathBuf,
|
index_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> SpaRouter<S, B, (), fn(io::Error) -> Ready<StatusCode>> {
|
impl<S, B> SpaRouter<S, B> {
|
||||||
/// Create a new `SpaRouter`.
|
/// Create a new `SpaRouter`.
|
||||||
///
|
///
|
||||||
/// Assets will be served at `GET /{serve_assets_at}` from the directory at `assets_dir`.
|
/// Assets will be served at `GET /{serve_assets_at}` from the directory at `assets_dir`.
|
||||||
@@ -80,13 +71,12 @@ impl<S, B> SpaRouter<S, B, (), fn(io::Error) -> Ready<StatusCode>> {
|
|||||||
assets_dir: path.to_owned(),
|
assets_dir: path.to_owned(),
|
||||||
index_file: path.join("index.html"),
|
index_file: path.join("index.html"),
|
||||||
}),
|
}),
|
||||||
handle_error: |_| ready(StatusCode::INTERNAL_SERVER_ERROR),
|
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, T, F> SpaRouter<S, B, T, F> {
|
impl<S, B> SpaRouter<S, B> {
|
||||||
/// Set the path to the index file.
|
/// Set the path to the index file.
|
||||||
///
|
///
|
||||||
/// `path` must be relative to `assets_dir` passed to [`SpaRouter::new`].
|
/// `path` must be relative to `assets_dir` passed to [`SpaRouter::new`].
|
||||||
@@ -114,72 +104,27 @@ impl<S, B, T, F> SpaRouter<S, B, T, F> {
|
|||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the function used to handle unknown IO errors.
|
|
||||||
///
|
|
||||||
/// `SpaRouter` automatically maps missing files and permission denied to
|
|
||||||
/// `404 Not Found`. The callback given here will be used for other IO errors.
|
|
||||||
///
|
|
||||||
/// See [`axum::error_handling::HandleErrorLayer`] for more details.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use std::io;
|
|
||||||
/// use axum_extra::routing::SpaRouter;
|
|
||||||
/// use axum::{Router, http::{Method, Uri}};
|
|
||||||
///
|
|
||||||
/// let spa = SpaRouter::new("/assets", "dist").handle_error(handle_error);
|
|
||||||
///
|
|
||||||
/// async fn handle_error(method: Method, uri: Uri, err: io::Error) -> String {
|
|
||||||
/// format!("{} {} failed with {}", method, uri, err)
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let app = Router::new().merge(spa);
|
|
||||||
/// # let _: Router = app;
|
|
||||||
/// ```
|
|
||||||
pub fn handle_error<T2, F2>(self, f: F2) -> SpaRouter<S, B, T2, F2> {
|
|
||||||
SpaRouter {
|
|
||||||
paths: self.paths,
|
|
||||||
handle_error: f,
|
|
||||||
_marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, F, T> From<SpaRouter<S, B, T, F>> for Router<S, B>
|
impl<S, B> From<SpaRouter<S, B>> for Router<S, B>
|
||||||
where
|
where
|
||||||
F: Clone + Send + Sync + 'static,
|
|
||||||
HandleError<Route<B, io::Error>, F, T>: Service<Request<B>, Error = Infallible>,
|
|
||||||
<HandleError<Route<B, io::Error>, F, T> as Service<Request<B>>>::Response: IntoResponse + Send,
|
|
||||||
<HandleError<Route<B, io::Error>, F, T> as Service<Request<B>>>::Future: Send,
|
|
||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Send + 'static,
|
||||||
T: 'static,
|
|
||||||
S: Clone + Send + Sync + 'static,
|
S: Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
fn from(spa: SpaRouter<S, B, T, F>) -> Router<S, B> {
|
fn from(spa: SpaRouter<S, B>) -> Router<S, B> {
|
||||||
let assets_service = get_service(ServeDir::new(&spa.paths.assets_dir))
|
let assets_service = ServeDir::new(&spa.paths.assets_dir);
|
||||||
.handle_error(spa.handle_error.clone());
|
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.nest_service(&spa.paths.assets_path, assets_service)
|
.nest_service(&spa.paths.assets_path, assets_service)
|
||||||
.fallback_service(
|
.fallback_service(ServeFile::new(&spa.paths.index_file))
|
||||||
get_service(ServeFile::new(&spa.paths.index_file)).handle_error(spa.handle_error),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, T, F> fmt::Debug for SpaRouter<B, T, F> {
|
impl<B, T> fmt::Debug for SpaRouter<B, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let Self {
|
let Self { paths, _marker } = self;
|
||||||
paths,
|
|
||||||
handle_error: _,
|
|
||||||
_marker,
|
|
||||||
} = self;
|
|
||||||
|
|
||||||
f.debug_struct("SpaRouter")
|
f.debug_struct("SpaRouter")
|
||||||
.field("paths", &paths)
|
.field("paths", &paths)
|
||||||
.field("handle_error", &format_args!("{}", type_name::<F>()))
|
|
||||||
.field("request_body_type", &format_args!("{}", type_name::<B>()))
|
.field("request_body_type", &format_args!("{}", type_name::<B>()))
|
||||||
.field(
|
.field(
|
||||||
"extractor_input_type",
|
"extractor_input_type",
|
||||||
@@ -189,14 +134,10 @@ impl<B, T, F> fmt::Debug for SpaRouter<B, T, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, T, F> Clone for SpaRouter<B, T, F>
|
impl<B, T> Clone for SpaRouter<B, T> {
|
||||||
where
|
|
||||||
F: Clone,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
paths: self.paths.clone(),
|
paths: self.paths.clone(),
|
||||||
handle_error: self.handle_error,
|
|
||||||
_marker: self._marker,
|
_marker: self._marker,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,10 +147,8 @@ where
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_helpers::*;
|
use crate::test_helpers::*;
|
||||||
use axum::{
|
use axum::routing::get;
|
||||||
http::{Method, Uri},
|
use http::StatusCode;
|
||||||
routing::get,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn basic() {
|
async fn basic() {
|
||||||
@@ -253,21 +192,6 @@ mod tests {
|
|||||||
assert_eq!(res.text().await, "<strong>Hello, World!</strong>\n");
|
assert_eq!(res.text().await, "<strong>Hello, World!</strong>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// this should just compile
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn setting_error_handler() {
|
|
||||||
async fn handle_error(method: Method, uri: Uri, err: io::Error) -> (StatusCode, String) {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("{} {} failed. Error: {}", method, uri, err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let spa = SpaRouter::new("/assets", "test_files").handle_error(handle_error);
|
|
||||||
|
|
||||||
Router::<(), Body>::new().merge(spa);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn works_with_router_with_state() {
|
fn works_with_router_with_state() {
|
||||||
let _: Router = Router::new()
|
let _: Router = Router::new()
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
- None.
|
- **changed:** Update to tower-http 0.4. axum is still compatible with tower-http 0.3
|
||||||
|
|
||||||
# 0.6.8 (24. February, 2023)
|
# 0.6.8 (24. February, 2023)
|
||||||
|
|
||||||
|
|||||||
+65
-4
@@ -27,7 +27,38 @@ tower-log = ["tower/log"]
|
|||||||
ws = ["tokio", "dep:tokio-tungstenite", "dep:sha1", "dep:base64"]
|
ws = ["tokio", "dep:tokio-tungstenite", "dep:sha1", "dep:base64"]
|
||||||
|
|
||||||
# Required for intra-doc links to resolve correctly
|
# Required for intra-doc links to resolve correctly
|
||||||
__private_docs = ["tower/full", "tower-http/full"]
|
__private_docs = [
|
||||||
|
"tower/full",
|
||||||
|
# all tower-http features except (de)?compression-zstd which doesn't
|
||||||
|
# build on `--target armv5te-unknown-linux-musleabi`
|
||||||
|
"tower-http/add-extension",
|
||||||
|
"tower-http/auth",
|
||||||
|
"tower-http/catch-panic",
|
||||||
|
"tower-http/compression-br",
|
||||||
|
"tower-http/compression-deflate",
|
||||||
|
"tower-http/compression-gzip",
|
||||||
|
"tower-http/cors",
|
||||||
|
"tower-http/decompression-br",
|
||||||
|
"tower-http/decompression-deflate",
|
||||||
|
"tower-http/decompression-gzip",
|
||||||
|
"tower-http/follow-redirect",
|
||||||
|
"tower-http/fs",
|
||||||
|
"tower-http/limit",
|
||||||
|
"tower-http/map-request-body",
|
||||||
|
"tower-http/map-response-body",
|
||||||
|
"tower-http/metrics",
|
||||||
|
"tower-http/normalize-path",
|
||||||
|
"tower-http/propagate-header",
|
||||||
|
"tower-http/redirect",
|
||||||
|
"tower-http/request-id",
|
||||||
|
"tower-http/sensitive-headers",
|
||||||
|
"tower-http/set-header",
|
||||||
|
"tower-http/set-status",
|
||||||
|
"tower-http/timeout",
|
||||||
|
"tower-http/trace",
|
||||||
|
"tower-http/util",
|
||||||
|
"tower-http/validate-request",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1.43"
|
async-trait = "0.1.43"
|
||||||
@@ -47,7 +78,7 @@ pin-project-lite = "0.2.7"
|
|||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
sync_wrapper = "0.1.1"
|
sync_wrapper = "0.1.1"
|
||||||
tower = { version = "0.4.13", default-features = false, features = ["util"] }
|
tower = { version = "0.4.13", default-features = false, features = ["util"] }
|
||||||
tower-http = { version = "0.3.0", features = ["util", "map-response-body"] }
|
tower-http = { version = "0.4", features = ["util", "map-response-body"] }
|
||||||
tower-layer = "0.3.2"
|
tower-layer = "0.3.2"
|
||||||
tower-service = "0.3"
|
tower-service = "0.3"
|
||||||
|
|
||||||
@@ -98,8 +129,38 @@ features = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dev-dependencies.tower-http]
|
[dev-dependencies.tower-http]
|
||||||
version = "0.3.4"
|
version = "0.4"
|
||||||
features = ["full"]
|
features = [
|
||||||
|
# all tower-http features except (de)?compression-zstd which doesn't
|
||||||
|
# build on `--target armv5te-unknown-linux-musleabi`
|
||||||
|
"add-extension",
|
||||||
|
"auth",
|
||||||
|
"catch-panic",
|
||||||
|
"compression-br",
|
||||||
|
"compression-deflate",
|
||||||
|
"compression-gzip",
|
||||||
|
"cors",
|
||||||
|
"decompression-br",
|
||||||
|
"decompression-deflate",
|
||||||
|
"decompression-gzip",
|
||||||
|
"follow-redirect",
|
||||||
|
"fs",
|
||||||
|
"limit",
|
||||||
|
"map-request-body",
|
||||||
|
"map-response-body",
|
||||||
|
"metrics",
|
||||||
|
"normalize-path",
|
||||||
|
"propagate-header",
|
||||||
|
"redirect",
|
||||||
|
"request-id",
|
||||||
|
"sensitive-headers",
|
||||||
|
"set-header",
|
||||||
|
"set-status",
|
||||||
|
"timeout",
|
||||||
|
"trace",
|
||||||
|
"util",
|
||||||
|
"validate-request",
|
||||||
|
]
|
||||||
|
|
||||||
[package.metadata.playground]
|
[package.metadata.playground]
|
||||||
features = [
|
features = [
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ use axum::{
|
|||||||
routing::get,
|
routing::get,
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use tower_http::auth::RequireAuthorizationLayer;
|
use tower_http::validate_request::ValidateRequestHeaderLayer;
|
||||||
|
|
||||||
let app = Router::new().route(
|
let app = Router::new().route(
|
||||||
"/foo",
|
"/foo",
|
||||||
get(|| async {})
|
get(|| async {})
|
||||||
.route_layer(RequireAuthorizationLayer::bearer("password"))
|
.route_layer(ValidateRequestHeaderLayer::bearer("password"))
|
||||||
);
|
);
|
||||||
|
|
||||||
// `GET /foo` with a valid token will receive `200 OK`
|
// `GET /foo` with a valid token will receive `200 OK`
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ use axum::{
|
|||||||
routing::get,
|
routing::get,
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use tower_http::auth::RequireAuthorizationLayer;
|
use tower_http::validate_request::ValidateRequestHeaderLayer;
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/foo", get(|| async {}))
|
.route("/foo", get(|| async {}))
|
||||||
.route_layer(RequireAuthorizationLayer::bearer("password"));
|
.route_layer(ValidateRequestHeaderLayer::bearer("password"));
|
||||||
|
|
||||||
// `GET /foo` with a valid token will receive `200 OK`
|
// `GET /foo` with a valid token will receive `200 OK`
|
||||||
// `GET /foo` with a invalid token will receive `401 Unauthorized`
|
// `GET /foo` with a invalid token will receive `401 Unauthorized`
|
||||||
|
|||||||
@@ -38,17 +38,10 @@ let app = Router::new()
|
|||||||
Ok::<_, Infallible>(res)
|
Ok::<_, Infallible>(res)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.route(
|
.route_service(
|
||||||
// GET `/static/Cargo.toml` goes to a service from tower-http
|
// GET `/static/Cargo.toml` goes to a service from tower-http
|
||||||
"/static/Cargo.toml",
|
"/static/Cargo.toml",
|
||||||
get_service(ServeFile::new("Cargo.toml"))
|
ServeFile::new("Cargo.toml"),
|
||||||
// though we must handle any potential errors
|
|
||||||
.handle_error(|error: io::Error| async move {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("Unhandled internal error: {}", error),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
# async {
|
# async {
|
||||||
# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
|||||||
@@ -1290,7 +1290,7 @@ mod tests {
|
|||||||
use http::{header::ALLOW, HeaderMap};
|
use http::{header::ALLOW, HeaderMap};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tower::{timeout::TimeoutLayer, Service, ServiceBuilder, ServiceExt};
|
use tower::{timeout::TimeoutLayer, Service, ServiceBuilder, ServiceExt};
|
||||||
use tower_http::{auth::RequireAuthorizationLayer, services::fs::ServeDir};
|
use tower_http::{services::fs::ServeDir, validate_request::ValidateRequestHeaderLayer};
|
||||||
|
|
||||||
#[crate::test]
|
#[crate::test]
|
||||||
async fn method_not_allowed_by_default() {
|
async fn method_not_allowed_by_default() {
|
||||||
@@ -1352,7 +1352,7 @@ mod tests {
|
|||||||
async fn layer() {
|
async fn layer() {
|
||||||
let mut svc = MethodRouter::new()
|
let mut svc = MethodRouter::new()
|
||||||
.get(|| async { std::future::pending::<()>().await })
|
.get(|| async { std::future::pending::<()>().await })
|
||||||
.layer(RequireAuthorizationLayer::bearer("password"));
|
.layer(ValidateRequestHeaderLayer::bearer("password"));
|
||||||
|
|
||||||
// method with route
|
// method with route
|
||||||
let (status, _, _) = call(Method::GET, &mut svc).await;
|
let (status, _, _) = call(Method::GET, &mut svc).await;
|
||||||
@@ -1367,7 +1367,7 @@ mod tests {
|
|||||||
async fn route_layer() {
|
async fn route_layer() {
|
||||||
let mut svc = MethodRouter::new()
|
let mut svc = MethodRouter::new()
|
||||||
.get(|| async { std::future::pending::<()>().await })
|
.get(|| async { std::future::pending::<()>().await })
|
||||||
.route_layer(RequireAuthorizationLayer::bearer("password"));
|
.route_layer(ValidateRequestHeaderLayer::bearer("password"));
|
||||||
|
|
||||||
// method with route
|
// method with route
|
||||||
let (status, _, _) = call(Method::GET, &mut svc).await;
|
let (status, _, _) = call(Method::GET, &mut svc).await;
|
||||||
@@ -1385,11 +1385,8 @@ mod tests {
|
|||||||
// use the all the things :bomb:
|
// use the all the things :bomb:
|
||||||
get(ok)
|
get(ok)
|
||||||
.post(ok)
|
.post(ok)
|
||||||
.route_layer(RequireAuthorizationLayer::bearer("password"))
|
.route_layer(ValidateRequestHeaderLayer::bearer("password"))
|
||||||
.merge(
|
.merge(delete_service(ServeDir::new(".")))
|
||||||
delete_service(ServeDir::new("."))
|
|
||||||
.handle_error(|_| async { StatusCode::NOT_FOUND }),
|
|
||||||
)
|
|
||||||
.fallback(|| async { StatusCode::NOT_FOUND })
|
.fallback(|| async { StatusCode::NOT_FOUND })
|
||||||
.put(ok)
|
.put(ok)
|
||||||
.layer(
|
.layer(
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ async fn nesting_and_seeing_the_right_uri_ors_with_multi_segment_uris() {
|
|||||||
async fn middleware_that_return_early() {
|
async fn middleware_that_return_early() {
|
||||||
let private = Router::new()
|
let private = Router::new()
|
||||||
.route("/", get(|| async {}))
|
.route("/", get(|| async {}))
|
||||||
.layer(RequireAuthorizationLayer::bearer("password"));
|
.layer(ValidateRequestHeaderLayer::bearer("password"));
|
||||||
|
|
||||||
let public = Router::new().route("/public", get(|| async {}));
|
let public = Router::new().route("/public", get(|| async {}));
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use tower::{service_fn, timeout::TimeoutLayer, util::MapResponseLayer, ServiceBuilder};
|
use tower::{service_fn, timeout::TimeoutLayer, util::MapResponseLayer, ServiceBuilder};
|
||||||
use tower_http::{auth::RequireAuthorizationLayer, limit::RequestBodyLimitLayer};
|
use tower_http::{limit::RequestBodyLimitLayer, validate_request::ValidateRequestHeaderLayer};
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
mod fallback;
|
mod fallback;
|
||||||
@@ -458,7 +458,7 @@ async fn routing_to_router_panics() {
|
|||||||
async fn route_layer() {
|
async fn route_layer() {
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/foo", get(|| async {}))
|
.route("/foo", get(|| async {}))
|
||||||
.route_layer(RequireAuthorizationLayer::bearer("password"));
|
.route_layer(ValidateRequestHeaderLayer::bearer("password"));
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -202,15 +202,7 @@ async fn nested_service_sees_stripped_uri() {
|
|||||||
|
|
||||||
#[crate::test]
|
#[crate::test]
|
||||||
async fn nest_static_file_server() {
|
async fn nest_static_file_server() {
|
||||||
let app = Router::new().nest_service(
|
let app = Router::new().nest_service("/static", ServeDir::new("."));
|
||||||
"/static",
|
|
||||||
get_service(ServeDir::new(".")).handle_error(|error| async move {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("Unhandled internal error: {error}"),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let client = TestClient::new(app);
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ axum = { path = "../../axum" }
|
|||||||
hyper = "0.14"
|
hyper = "0.14"
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tower = "0.4"
|
tower = "0.4"
|
||||||
tower-http = { version = "0.3", features = ["map-request-body", "util"] }
|
tower-http = { version = "0.4.0", features = ["map-request-body", "util"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ publish = false
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { path = "../../axum" }
|
axum = { path = "../../axum" }
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tower-http = { version = "0.3.0", features = ["cors"] }
|
tower-http = { version = "0.4.0", features = ["cors"] }
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ publish = false
|
|||||||
axum = { path = "../../axum" }
|
axum = { path = "../../axum" }
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tower = { version = "0.4", features = ["util", "timeout", "load-shed", "limit"] }
|
tower = { version = "0.4", features = ["util", "timeout", "load-shed", "limit"] }
|
||||||
tower-http = { version = "0.3.0", features = [
|
tower-http = { version = "0.4.0", features = [
|
||||||
"add-extension",
|
"add-extension",
|
||||||
"auth",
|
"auth",
|
||||||
"compression-full",
|
"compression-full",
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ use std::{
|
|||||||
};
|
};
|
||||||
use tower::{BoxError, ServiceBuilder};
|
use tower::{BoxError, ServiceBuilder};
|
||||||
use tower_http::{
|
use tower_http::{
|
||||||
auth::RequireAuthorizationLayer, compression::CompressionLayer, limit::RequestBodyLimitLayer,
|
compression::CompressionLayer, limit::RequestBodyLimitLayer, trace::TraceLayer,
|
||||||
trace::TraceLayer,
|
validate_request::ValidateRequestHeaderLayer,
|
||||||
};
|
};
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ fn admin_routes() -> Router<SharedState> {
|
|||||||
.route("/keys", delete(delete_all_keys))
|
.route("/keys", delete(delete_all_keys))
|
||||||
.route("/key/:key", delete(remove_key))
|
.route("/key/:key", delete(remove_key))
|
||||||
// Require bearer auth for all admin routes
|
// Require bearer auth for all admin routes
|
||||||
.layer(RequireAuthorizationLayer::bearer("secret-token"))
|
.layer(ValidateRequestHeaderLayer::bearer("secret-token"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_error(error: BoxError) -> impl IntoResponse {
|
async fn handle_error(error: BoxError) -> impl IntoResponse {
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ publish = false
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { path = "../../axum", features = ["multipart"] }
|
axum = { path = "../../axum", features = ["multipart"] }
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tower-http = { version = "0.3.0", features = ["limit", "trace"] }
|
tower-http = { version = "0.4.0", features = ["limit", "trace"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ futures = "0.3"
|
|||||||
headers = "0.3"
|
headers = "0.3"
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tokio-stream = "0.1"
|
tokio-stream = "0.1"
|
||||||
tower-http = { version = "0.3.0", features = ["fs", "trace"] }
|
tower-http = { version = "0.4.0", features = ["fs", "trace"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|||||||
@@ -6,9 +6,8 @@
|
|||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::TypedHeader,
|
extract::TypedHeader,
|
||||||
http::StatusCode,
|
|
||||||
response::sse::{Event, Sse},
|
response::sse::{Event, Sse},
|
||||||
routing::{get, get_service},
|
routing::get,
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use futures::stream::{self, Stream};
|
use futures::stream::{self, Stream};
|
||||||
@@ -29,15 +28,7 @@ async fn main() {
|
|||||||
|
|
||||||
let assets_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("assets");
|
let assets_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("assets");
|
||||||
|
|
||||||
let static_files_service = get_service(
|
let static_files_service = ServeDir::new(assets_dir).append_index_html_on_directories(true);
|
||||||
ServeDir::new(assets_dir).append_index_html_on_directories(true),
|
|
||||||
)
|
|
||||||
.handle_error(|error: std::io::Error| async move {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("Unhandled internal error: {}", error),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
// build our application with a route
|
// build our application with a route
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ axum = { path = "../../axum" }
|
|||||||
axum-extra = { path = "../../axum-extra", features = ["spa"] }
|
axum-extra = { path = "../../axum-extra", features = ["spa"] }
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tower = { version = "0.4", features = ["util"] }
|
tower = { version = "0.4", features = ["util"] }
|
||||||
tower-http = { version = "0.3.0", features = ["fs", "trace"] }
|
tower-http = { version = "0.4.0", features = ["fs", "trace"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|||||||
@@ -8,12 +8,11 @@ use axum::{
|
|||||||
body::Body,
|
body::Body,
|
||||||
handler::HandlerWithoutStateExt,
|
handler::HandlerWithoutStateExt,
|
||||||
http::{Request, StatusCode},
|
http::{Request, StatusCode},
|
||||||
response::IntoResponse,
|
routing::get,
|
||||||
routing::{get, get_service},
|
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use axum_extra::routing::SpaRouter;
|
use axum_extra::routing::SpaRouter;
|
||||||
use std::{io, net::SocketAddr};
|
use std::net::SocketAddr;
|
||||||
use tower::ServiceExt;
|
use tower::ServiceExt;
|
||||||
use tower_http::{
|
use tower_http::{
|
||||||
services::{ServeDir, ServeFile},
|
services::{ServeDir, ServeFile},
|
||||||
@@ -56,7 +55,7 @@ fn using_serve_dir() -> Router {
|
|||||||
// `SpaRouter` is just a convenient wrapper around `ServeDir`
|
// `SpaRouter` is just a convenient wrapper around `ServeDir`
|
||||||
//
|
//
|
||||||
// You can use `ServeDir` directly to further customize your setup
|
// You can use `ServeDir` directly to further customize your setup
|
||||||
let serve_dir = get_service(ServeDir::new("assets")).handle_error(handle_error);
|
let serve_dir = ServeDir::new("assets");
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/foo", get(|| async { "Hi from /foo" }))
|
.route("/foo", get(|| async { "Hi from /foo" }))
|
||||||
@@ -69,7 +68,6 @@ fn using_serve_dir_with_assets_fallback() -> Router {
|
|||||||
// so with this `GET /assets/doesnt-exist.jpg` will return `index.html`
|
// so with this `GET /assets/doesnt-exist.jpg` will return `index.html`
|
||||||
// rather than a 404
|
// rather than a 404
|
||||||
let serve_dir = ServeDir::new("assets").not_found_service(ServeFile::new("assets/index.html"));
|
let serve_dir = ServeDir::new("assets").not_found_service(ServeFile::new("assets/index.html"));
|
||||||
let serve_dir = get_service(serve_dir).handle_error(handle_error);
|
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/foo", get(|| async { "Hi from /foo" }))
|
.route("/foo", get(|| async { "Hi from /foo" }))
|
||||||
@@ -81,7 +79,6 @@ fn using_serve_dir_only_from_root_via_fallback() -> Router {
|
|||||||
// you can also serve the assets directly from the root (not nested under `/assets`)
|
// you can also serve the assets directly from the root (not nested under `/assets`)
|
||||||
// by only setting a `ServeDir` as the fallback
|
// by only setting a `ServeDir` as the fallback
|
||||||
let serve_dir = ServeDir::new("assets").not_found_service(ServeFile::new("assets/index.html"));
|
let serve_dir = ServeDir::new("assets").not_found_service(ServeFile::new("assets/index.html"));
|
||||||
let serve_dir = get_service(serve_dir).handle_error(handle_error);
|
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/foo", get(|| async { "Hi from /foo" }))
|
.route("/foo", get(|| async { "Hi from /foo" }))
|
||||||
@@ -93,13 +90,7 @@ fn using_serve_dir_with_handler_as_service() -> Router {
|
|||||||
(StatusCode::NOT_FOUND, "Not found")
|
(StatusCode::NOT_FOUND, "Not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// you can convert handler function to service
|
let serve_dir = ServeDir::new("assets").not_found_service(handle_404.into_service());
|
||||||
let service = handle_404
|
|
||||||
.into_service()
|
|
||||||
.map_err(|err| -> std::io::Error { match err {} });
|
|
||||||
|
|
||||||
let serve_dir = ServeDir::new("assets").not_found_service(service);
|
|
||||||
let serve_dir = get_service(serve_dir).handle_error(handle_error);
|
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/foo", get(|| async { "Hi from /foo" }))
|
.route("/foo", get(|| async { "Hi from /foo" }))
|
||||||
@@ -108,8 +99,8 @@ fn using_serve_dir_with_handler_as_service() -> Router {
|
|||||||
|
|
||||||
fn two_serve_dirs() -> Router {
|
fn two_serve_dirs() -> Router {
|
||||||
// you can also have two `ServeDir`s nested at different paths
|
// you can also have two `ServeDir`s nested at different paths
|
||||||
let serve_dir_from_assets = get_service(ServeDir::new("assets")).handle_error(handle_error);
|
let serve_dir_from_assets = ServeDir::new("assets");
|
||||||
let serve_dir_from_dist = get_service(ServeDir::new("dist")).handle_error(handle_error);
|
let serve_dir_from_dist = ServeDir::new("dist");
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.nest_service("/assets", serve_dir_from_assets)
|
.nest_service("/assets", serve_dir_from_assets)
|
||||||
@@ -123,17 +114,13 @@ fn calling_serve_dir_from_a_handler() -> Router {
|
|||||||
Router::new().nest_service(
|
Router::new().nest_service(
|
||||||
"/foo",
|
"/foo",
|
||||||
get(|request: Request<Body>| async {
|
get(|request: Request<Body>| async {
|
||||||
let service = get_service(ServeDir::new("assets")).handle_error(handle_error);
|
let service = ServeDir::new("assets");
|
||||||
let result = service.oneshot(request).await;
|
let result = service.oneshot(request).await;
|
||||||
result
|
result
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_error(_err: io::Error) -> impl IntoResponse {
|
|
||||||
(StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong...")
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn serve(app: Router, port: u16) {
|
async fn serve(app: Router, port: u16) {
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], port));
|
let addr = SocketAddr::from(([127, 0, 0, 1], port));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ hyper = { version = "0.14", features = ["full"] }
|
|||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tower-http = { version = "0.3.0", features = ["trace"] }
|
tower-http = { version = "0.4.0", features = ["trace"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ axum = { path = "../../axum" }
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tower = { version = "0.4", features = ["util", "timeout"] }
|
tower = { version = "0.4", features = ["util", "timeout"] }
|
||||||
tower-http = { version = "0.3.0", features = ["add-extension", "trace"] }
|
tower-http = { version = "0.4.0", features = ["add-extension", "trace"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
uuid = { version = "1.0", features = ["serde", "v4"] }
|
uuid = { version = "1.0", features = ["serde", "v4"] }
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ publish = false
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { path = "../../axum" }
|
axum = { path = "../../axum" }
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tower-http = { version = "0.3.0", features = ["trace"] }
|
tower-http = { version = "0.4.0", features = ["trace"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ headers = "0.3"
|
|||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tokio-tungstenite = "0.18.0"
|
tokio-tungstenite = "0.18.0"
|
||||||
tower = { version = "0.4", features = ["util"] }
|
tower = { version = "0.4", features = ["util"] }
|
||||||
tower-http = { version = "0.3.0", features = ["fs", "trace"] }
|
tower-http = { version = "0.4.0", features = ["fs", "trace"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use tokio_tungstenite::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const N_CLIENTS: usize = 2; //set to desired number
|
const N_CLIENTS: usize = 2; //set to desired number
|
||||||
const SERVER: &'static str = "ws://127.0.0.1:3000/ws";
|
const SERVER: &str = "ws://127.0.0.1:3000/ws";
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|||||||
@@ -21,9 +21,8 @@ use axum::{
|
|||||||
ws::{Message, WebSocket, WebSocketUpgrade},
|
ws::{Message, WebSocket, WebSocketUpgrade},
|
||||||
TypedHeader,
|
TypedHeader,
|
||||||
},
|
},
|
||||||
http::StatusCode,
|
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
routing::{get, get_service},
|
routing::get,
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -58,15 +57,7 @@ async fn main() {
|
|||||||
|
|
||||||
// build our application with some routes
|
// build our application with some routes
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.fallback_service(
|
.fallback_service(ServeDir::new(assets_dir).append_index_html_on_directories(true))
|
||||||
get_service(ServeDir::new(assets_dir).append_index_html_on_directories(true))
|
|
||||||
.handle_error(|error: std::io::Error| async move {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("Unhandled internal error: {}", error),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.route("/ws", get(ws_handler))
|
.route("/ws", get(ws_handler))
|
||||||
// logging so we can see whats going on
|
// logging so we can see whats going on
|
||||||
.layer(
|
.layer(
|
||||||
@@ -98,7 +89,7 @@ async fn ws_handler(
|
|||||||
} else {
|
} else {
|
||||||
String::from("Unknown browser")
|
String::from("Unknown browser")
|
||||||
};
|
};
|
||||||
println!("`{}` at {} connected.", user_agent, addr.to_string());
|
println!("`{user_agent}` at {addr} connected.");
|
||||||
// finalize the upgrade process by returning upgrade callback.
|
// finalize the upgrade process by returning upgrade callback.
|
||||||
// we can customize the callback by sending additional info such as address.
|
// we can customize the callback by sending additional info such as address.
|
||||||
ws.on_upgrade(move |socket| handle_socket(socket, addr))
|
ws.on_upgrade(move |socket| handle_socket(socket, addr))
|
||||||
@@ -107,7 +98,7 @@ async fn ws_handler(
|
|||||||
/// Actual websocket statemachine (one will be spawned per connection)
|
/// Actual websocket statemachine (one will be spawned per connection)
|
||||||
async fn handle_socket(mut socket: WebSocket, who: SocketAddr) {
|
async fn handle_socket(mut socket: WebSocket, who: SocketAddr) {
|
||||||
//send a ping (unsupported by some browsers) just to kick things off and get a response
|
//send a ping (unsupported by some browsers) just to kick things off and get a response
|
||||||
if let Ok(_) = socket.send(Message::Ping(vec![1, 2, 3])).await {
|
if socket.send(Message::Ping(vec![1, 2, 3])).await.is_ok() {
|
||||||
println!("Pinged {}...", who);
|
println!("Pinged {}...", who);
|
||||||
} else {
|
} else {
|
||||||
println!("Could not send ping {}!", who);
|
println!("Could not send ping {}!", who);
|
||||||
@@ -126,7 +117,7 @@ async fn handle_socket(mut socket: WebSocket, who: SocketAddr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("client {} abruptly disconnected", who);
|
println!("client {who} abruptly disconnected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,11 +128,11 @@ async fn handle_socket(mut socket: WebSocket, who: SocketAddr) {
|
|||||||
// connecting to server and receiving their greetings.
|
// connecting to server and receiving their greetings.
|
||||||
for i in 1..5 {
|
for i in 1..5 {
|
||||||
if socket
|
if socket
|
||||||
.send(Message::Text(String::from(format!("Hi {} times!", i))))
|
.send(Message::Text(format!("Hi {i} times!")))
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
println!("client {} abruptly disconnected", who);
|
println!("client {who} abruptly disconnected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||||
@@ -157,7 +148,7 @@ async fn handle_socket(mut socket: WebSocket, who: SocketAddr) {
|
|||||||
for i in 0..n_msg {
|
for i in 0..n_msg {
|
||||||
// In case of any websocket error, we exit.
|
// In case of any websocket error, we exit.
|
||||||
if sender
|
if sender
|
||||||
.send(Message::Text(format!("Server message {} ...", i)))
|
.send(Message::Text(format!("Server message {i} ...")))
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
@@ -167,7 +158,7 @@ async fn handle_socket(mut socket: WebSocket, who: SocketAddr) {
|
|||||||
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Sending close to {}...", who);
|
println!("Sending close to {who}...");
|
||||||
if let Err(e) = sender
|
if let Err(e) = sender
|
||||||
.send(Message::Close(Some(CloseFrame {
|
.send(Message::Close(Some(CloseFrame {
|
||||||
code: axum::extract::ws::close_code::NORMAL,
|
code: axum::extract::ws::close_code::NORMAL,
|
||||||
|
|||||||
Reference in New Issue
Block a user