diff --git a/Cargo.lock b/Cargo.lock index 008342a11cd8e1..ff0b5ee1cb3c8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1591,7 +1591,7 @@ dependencies = [ "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tower 0.5.2", + "tower", "tracing", ] @@ -1729,20 +1729,20 @@ dependencies = [ [[package]] name = "axum" -version = "0.6.20" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" dependencies = [ - "async-trait", "axum-core", - "base64 0.21.7", - "bitflags 1.3.2", + "base64 0.22.1", "bytes 1.10.1", + "form_urlencoded", "futures-util", - "headers", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-util", "itoa", "matchit", "memchr", @@ -1755,50 +1755,58 @@ dependencies = [ "serde_path_to_error", "serde_urlencoded", "sha1", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.2", "tokio", - "tokio-tungstenite 0.20.1", - "tower 0.4.13", + "tokio-tungstenite 0.26.2", + "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] name = "axum-core" -version = "0.3.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" dependencies = [ - "async-trait", "bytes 1.10.1", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", "mime", + "pin-project-lite", "rustversion", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", + "tracing", ] [[package]] name = "axum-extra" -version = "0.4.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a320103719de37b7b4da4c8eb629d4573f6bcfd3dfe80d3208806895ccf81d" +checksum = "45bf463831f5131b7d3c756525b305d40f1185b688565648a92e1392ca35713d" dependencies = [ "axum", + "axum-core", "bytes 1.10.1", "futures-util", - "http 0.2.12", + "headers 0.4.0", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", "mime", "pin-project-lite", + "rustversion", "serde", "serde_json", - "tokio", - "tower 0.4.13", - "tower-http 0.3.5", + "tower", "tower-layer", "tower-service", + "typed-json", ] [[package]] @@ -3037,8 +3045,8 @@ dependencies = [ "time", "tokio", "toml 0.8.20", - "tower 0.4.13", - "tower-http 0.4.4", + "tower", + "tower-http", "tracing", "tracing-subscriber", "unindent", @@ -6451,13 +6459,28 @@ checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ "base64 0.21.7", "bytes 1.10.1", - "headers-core", + "headers-core 0.2.0", "http 0.2.12", "httpdate", "mime", "sha1", ] +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64 0.21.7", + "bytes 1.10.1", + "headers-core 0.3.0", + "http 1.3.1", + "httpdate", + "mime", + "sha1", +] + [[package]] name = "headers-core" version = "0.2.0" @@ -6467,6 +6490,15 @@ dependencies = [ "http 0.2.12", ] +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http 1.3.1", +] + [[package]] name = "heck" version = "0.3.3" @@ -6698,12 +6730,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range-header" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" - [[package]] name = "http-types" version = "2.12.0" @@ -6811,6 +6837,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -8632,9 +8659,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "maybe-owned" @@ -12047,7 +12074,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.2", "tokio", - "tower 0.5.2", + "tower", "tower-service", "url", "wasm-bindgen", @@ -12094,7 +12121,7 @@ dependencies = [ "tokio-rustls 0.26.2", "tokio-socks", "tokio-util", - "tower 0.5.2", + "tower", "tower-service", "url", "wasm-bindgen", @@ -15056,18 +15083,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.20.1", -] - [[package]] name = "tokio-tungstenite" version = "0.21.0" @@ -15174,22 +15189,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower" version = "0.5.2" @@ -15203,39 +15202,19 @@ dependencies = [ "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] name = "tower-http" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" -dependencies = [ - "bitflags 1.3.2", - "bytes 1.10.1", - "futures-core", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "http-range-header", - "pin-project-lite", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.4.4" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" dependencies = [ "bitflags 2.9.0", "bytes 1.10.1", - "futures-core", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "http-range-header", + "http 1.3.1", + "http-body 1.0.1", "pin-project-lite", "tower-layer", "tower-service", @@ -15602,25 +15581,6 @@ dependencies = [ "core_maths", ] -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes 1.10.1", - "data-encoding", - "http 0.2.12", - "httparse", - "log", - "rand 0.8.5", - "sha1", - "thiserror 1.0.69", - "url", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.21.0" @@ -15659,6 +15619,16 @@ dependencies = [ "utf-8", ] +[[package]] +name = "typed-json" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6024a8d0025400b3f6b189366e9aa92012cf9c4fe1cd2620848dd61425c49eed" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "typeid" version = "1.0.3" @@ -16210,7 +16180,7 @@ dependencies = [ "bytes 1.10.1", "futures-channel", "futures-util", - "headers", + "headers 0.3.9", "http 0.2.12", "hyper 0.14.32", "log", @@ -18195,7 +18165,7 @@ dependencies = [ "tokio-util", "toml_datetime", "toml_edit", - "tower 0.5.2", + "tower", "tracing", "tracing-core", "tungstenite 0.26.2", diff --git a/Cargo.toml b/Cargo.toml index d9fd6ae2a7dc38..9087dc674c6c89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -563,7 +563,7 @@ tiny_http = "0.8" tokio = { version = "1" } tokio-tungstenite = { version = "0.26", features = ["__rustls-tls"] } toml = "0.8" -tower-http = "0.4.4" +tower-http = "0.6.4" tree-sitter = { version = "0.25.3", features = ["wasm"] } tree-sitter-bash = "0.23" tree-sitter-c = "0.23" diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index d1b6cef806f2f2..af535b56ced01b 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -24,8 +24,8 @@ async-tungstenite.workspace = true aws-config = { version = "1.1.5" } aws-sdk-s3 = { version = "1.15.0" } aws-sdk-kinesis = "1.51.0" -axum = { version = "0.6", features = ["json", "headers", "ws"] } -axum-extra = { version = "0.4", features = ["erased-json"] } +axum = { version = "0.8", features = ["ws"] } +axum-extra = { version = "0.10", features = ["erased-json", "typed-header"] } base64.workspace = true chrono.workspace = true clock.workspace = true @@ -66,7 +66,7 @@ thiserror.workspace = true time.workspace = true tokio = { workspace = true, features = ["full"] } toml.workspace = true -tower = "0.4" +tower = "0.5.2" tower-http = { workspace = true, features = ["trace"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json", "registry", "tracing-log"] } # workaround for https://github.com/tokio-rs/tracing/issues/2927 diff --git a/crates/collab/src/api.rs b/crates/collab/src/api.rs index a911b586a114f6..7454918488adb9 100644 --- a/crates/collab/src/api.rs +++ b/crates/collab/src/api.rs @@ -13,15 +13,13 @@ use crate::{ use anyhow::anyhow; use axum::{ Extension, Json, Router, - body::Body, - extract::{Path, Query}, - headers::Header, - http::{self, HeaderName, Request, StatusCode}, + extract::{Path, Query, Request}, + http::{self, HeaderName, StatusCode}, middleware::{self, Next}, response::IntoResponse, routing::{get, post}, }; -use axum_extra::response::ErasedJson; +use axum_extra::{headers::Header, response::ErasedJson}; use serde::{Deserialize, Serialize}; use std::sync::{Arc, OnceLock}; use tower::ServiceBuilder; @@ -36,16 +34,16 @@ impl Header for CloudflareIpCountryHeader { CLOUDFLARE_IP_COUNTRY_HEADER.get_or_init(|| HeaderName::from_static("cf-ipcountry")) } - fn decode<'i, I>(values: &mut I) -> Result + fn decode<'i, I>(values: &mut I) -> Result where Self: Sized, I: Iterator, { let country_code = values .next() - .ok_or_else(axum::headers::Error::invalid)? + .ok_or_else(axum_extra::headers::Error::invalid)? .to_str() - .map_err(|_| axum::headers::Error::invalid())?; + .map_err(|_| axum_extra::headers::Error::invalid())?; Ok(Self(country_code.to_string())) } @@ -69,16 +67,16 @@ impl Header for SystemIdHeader { SYSTEM_ID_HEADER.get_or_init(|| HeaderName::from_static("x-zed-system-id")) } - fn decode<'i, I>(values: &mut I) -> Result + fn decode<'i, I>(values: &mut I) -> Result where Self: Sized, I: Iterator, { let system_id = values .next() - .ok_or_else(axum::headers::Error::invalid)? + .ok_or_else(axum_extra::headers::Error::invalid)? .to_str() - .map_err(|_| axum::headers::Error::invalid())?; + .map_err(|_| axum_extra::headers::Error::invalid())?; Ok(Self(system_id.to_string())) } @@ -94,7 +92,7 @@ impl std::fmt::Display for SystemIdHeader { } } -pub fn routes(rpc_server: Arc) -> Router<(), Body> { +pub fn routes(rpc_server: Arc) -> Router { Router::new() .route("/user", get(get_authenticated_user)) .route("/users/:id/access_tokens", post(create_access_token)) @@ -108,7 +106,7 @@ pub fn routes(rpc_server: Arc) -> Router<(), Body> { ) } -pub async fn validate_api_token(req: Request, next: Next) -> impl IntoResponse { +pub async fn validate_api_token(req: Request, next: Next) -> impl IntoResponse { let token = req .headers() .get(http::header::AUTHORIZATION) diff --git a/crates/collab/src/api/billing.rs b/crates/collab/src/api/billing.rs index 6a498dcf831276..07b91ac36007b9 100644 --- a/crates/collab/src/api/billing.rs +++ b/crates/collab/src/api/billing.rs @@ -2,11 +2,11 @@ use anyhow::{Context, anyhow, bail}; use axum::{ Extension, Json, Router, extract::{self, Query}, + http::StatusCode, routing::{get, post}, }; use chrono::{DateTime, SecondsFormat, Utc}; use collections::HashSet; -use reqwest::StatusCode; use sea_orm::ActiveValue; use serde::{Deserialize, Serialize}; use serde_json::json; diff --git a/crates/collab/src/api/events.rs b/crates/collab/src/api/events.rs index 6ccc86c5200829..f60890fea898ab 100644 --- a/crates/collab/src/api/events.rs +++ b/crates/collab/src/api/events.rs @@ -4,12 +4,12 @@ use crate::{AppState, Error, Result, api::slack}; use anyhow::anyhow; use aws_sdk_s3::primitives::ByteStream; use axum::{ - Extension, Router, TypedHeader, + Extension, Router, body::Bytes, - headers::Header, http::{HeaderMap, HeaderName, StatusCode}, routing::post, }; +use axum_extra::{TypedHeader, headers::Header}; use chrono::Duration; use semantic_version::SemanticVersion; use serde::{Deserialize, Serialize}; @@ -38,18 +38,18 @@ impl Header for ZedChecksumHeader { ZED_CHECKSUM_HEADER.get_or_init(|| HeaderName::from_static("x-zed-checksum")) } - fn decode<'i, I>(values: &mut I) -> Result + fn decode<'i, I>(values: &mut I) -> Result where Self: Sized, I: Iterator, { let checksum = values .next() - .ok_or_else(axum::headers::Error::invalid)? + .ok_or_else(axum_extra::headers::Error::invalid)? .to_str() - .map_err(|_| axum::headers::Error::invalid())?; + .map_err(|_| axum_extra::headers::Error::invalid())?; - let bytes = hex::decode(checksum).map_err(|_| axum::headers::Error::invalid())?; + let bytes = hex::decode(checksum).map_err(|_| axum_extra::headers::Error::invalid())?; Ok(Self(bytes)) } diff --git a/crates/collab/src/auth.rs b/crates/collab/src/auth.rs index ee411d855cf975..10fddb68d68e41 100644 --- a/crates/collab/src/auth.rs +++ b/crates/collab/src/auth.rs @@ -5,7 +5,8 @@ use crate::{ }; use anyhow::{Context as _, anyhow}; use axum::{ - http::{self, Request, StatusCode}, + extract::Request, + http::{self, StatusCode}, middleware::Next, response::IntoResponse, }; @@ -27,7 +28,7 @@ use subtle::ConstantTimeEq; /// can be an access_token attached to that user, or an access token of an admin /// or (in development) the string ADMIN:. /// Authorization: "dev-server-token" -pub async fn validate_header(mut req: Request, next: Next) -> impl IntoResponse { +pub async fn validate_header(mut req: Request, next: Next) -> impl IntoResponse { let mut auth_header = req .headers() .get(http::header::AUTHORIZATION) diff --git a/crates/collab/src/main.rs b/crates/collab/src/main.rs index e5240666c4b8a6..f08c35490bcafd 100644 --- a/crates/collab/src/main.rs +++ b/crates/collab/src/main.rs @@ -1,11 +1,11 @@ use anyhow::anyhow; -use axum::headers::HeaderMapExt; use axum::{ Extension, Router, extract::MatchedPath, http::{Request, Response}, routing::get, }; +use axum_extra::headers::HeaderMapExt; use collab::api::CloudflareIpCountryHeader; use collab::api::billing::sync_llm_request_usage_with_stripe_periodically; @@ -18,13 +18,8 @@ use collab::{ }; use collab::{ServiceMode, api::billing::poll_stripe_events_periodically}; use db::Database; -use std::{ - env::args, - net::{SocketAddr, TcpListener}, - path::Path, - sync::Arc, - time::Duration, -}; +use std::{env::args, net::SocketAddr, path::Path, sync::Arc, time::Duration}; +use tokio::net::TcpListener; #[cfg(unix)] use tokio::signal::unix::SignalKind; use tower_http::trace::TraceLayer; @@ -92,6 +87,7 @@ async fn main() -> Result<()> { .layer(Extension(mode)); let listener = TcpListener::bind(format!("0.0.0.0:{}", config.http_port)) + .await .expect("failed to bind TCP listener"); let mut on_shutdown = None; @@ -227,19 +223,20 @@ async fn main() -> Result<()> { futures::future::select(ctrl_break, ctrl_c).await; }; - axum::Server::from_tcp(listener) - .map_err(|e| anyhow!(e))? - .serve(app.into_make_service_with_connect_info::()) - .with_graceful_shutdown(async move { - signal.await; - tracing::info!("Received interrupt signal"); + axum::serve( + listener, + app.into_make_service_with_connect_info::(), + ) + .with_graceful_shutdown(async move { + signal.await; + tracing::info!("Received interrupt signal"); - if let Some(on_shutdown) = on_shutdown { - on_shutdown(); - } - }) - .await - .map_err(|e| anyhow!(e))?; + if let Some(on_shutdown) = on_shutdown { + on_shutdown(); + } + }) + .await + .map_err(|e| anyhow!(e))?; } _ => { Err(anyhow!( diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index 06b011f0f9f8ad..f5f9058c328a13 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -18,19 +18,20 @@ use anyhow::{Context as _, anyhow, bail}; use async_tungstenite::tungstenite::{ Message as TungsteniteMessage, protocol::CloseFrame as TungsteniteCloseFrame, }; +use axum::http::HeaderName; use axum::{ - Extension, Router, TypedHeader, - body::Body, + Extension, Router, extract::{ ConnectInfo, WebSocketUpgrade, ws::{CloseFrame as AxumCloseFrame, Message as AxumMessage}, }, - headers::{Header, HeaderName}, http::StatusCode, middleware, response::IntoResponse, routing::get, }; +use axum_extra::TypedHeader; +use axum_extra::headers::Header; use chrono::Utc; use collections::{HashMap, HashSet}; pub use connection_pool::{ConnectionPool, ZedVersion}; @@ -1022,18 +1023,18 @@ impl Header for ProtocolVersion { ZED_PROTOCOL_VERSION.get_or_init(|| HeaderName::from_static("x-zed-protocol-version")) } - fn decode<'i, I>(values: &mut I) -> Result + fn decode<'i, I>(values: &mut I) -> Result where Self: Sized, I: Iterator, { let version = values .next() - .ok_or_else(axum::headers::Error::invalid)? + .ok_or_else(axum_extra::headers::Error::invalid)? .to_str() - .map_err(|_| axum::headers::Error::invalid())? + .map_err(|_| axum_extra::headers::Error::invalid())? .parse() - .map_err(|_| axum::headers::Error::invalid())?; + .map_err(|_| axum_extra::headers::Error::invalid())?; Ok(Self(version)) } @@ -1049,18 +1050,18 @@ impl Header for AppVersionHeader { ZED_APP_VERSION.get_or_init(|| HeaderName::from_static("x-zed-app-version")) } - fn decode<'i, I>(values: &mut I) -> Result + fn decode<'i, I>(values: &mut I) -> Result where Self: Sized, I: Iterator, { let version = values .next() - .ok_or_else(axum::headers::Error::invalid)? + .ok_or_else(axum_extra::headers::Error::invalid)? .to_str() - .map_err(|_| axum::headers::Error::invalid())? + .map_err(|_| axum_extra::headers::Error::invalid())? .parse() - .map_err(|_| axum::headers::Error::invalid())?; + .map_err(|_| axum_extra::headers::Error::invalid())?; Ok(Self(version)) } @@ -1069,7 +1070,7 @@ impl Header for AppVersionHeader { } } -pub fn routes(server: Arc) -> Router<(), Body> { +pub fn routes(server: Arc) -> Router { Router::new() .route("/rpc", get(handle_websocket_request)) .layer( @@ -4042,13 +4043,13 @@ async fn get_llm_api_token( fn to_axum_message(message: TungsteniteMessage) -> anyhow::Result { let message = match message { - TungsteniteMessage::Text(payload) => AxumMessage::Text(payload.as_str().to_string()), - TungsteniteMessage::Binary(payload) => AxumMessage::Binary(payload.into()), - TungsteniteMessage::Ping(payload) => AxumMessage::Ping(payload.into()), - TungsteniteMessage::Pong(payload) => AxumMessage::Pong(payload.into()), + TungsteniteMessage::Text(payload) => AxumMessage::Text(payload.to_string().into()), + TungsteniteMessage::Binary(payload) => AxumMessage::Binary(payload), + TungsteniteMessage::Ping(payload) => AxumMessage::Ping(payload), + TungsteniteMessage::Pong(payload) => AxumMessage::Pong(payload), TungsteniteMessage::Close(frame) => AxumMessage::Close(frame.map(|frame| AxumCloseFrame { code: frame.code.into(), - reason: frame.reason.as_str().to_owned().into(), + reason: frame.reason.to_string().into(), })), // We should never receive a frame while reading the message, according // to the `tungstenite` maintainers: @@ -4068,14 +4069,14 @@ fn to_axum_message(message: TungsteniteMessage) -> anyhow::Result { fn to_tungstenite_message(message: AxumMessage) -> TungsteniteMessage { match message { - AxumMessage::Text(payload) => TungsteniteMessage::Text(payload.into()), - AxumMessage::Binary(payload) => TungsteniteMessage::Binary(payload.into()), - AxumMessage::Ping(payload) => TungsteniteMessage::Ping(payload.into()), - AxumMessage::Pong(payload) => TungsteniteMessage::Pong(payload.into()), + AxumMessage::Text(payload) => TungsteniteMessage::Text(payload.to_string().into()), + AxumMessage::Binary(payload) => TungsteniteMessage::Binary(payload), + AxumMessage::Ping(payload) => TungsteniteMessage::Ping(payload), + AxumMessage::Pong(payload) => TungsteniteMessage::Pong(payload), AxumMessage::Close(frame) => { TungsteniteMessage::Close(frame.map(|frame| TungsteniteCloseFrame { code: frame.code.into(), - reason: frame.reason.as_ref().into(), + reason: frame.reason.to_string().into(), })) } }