From 649ce34b0128c074aa2b8ec00e2cb83add52f15e Mon Sep 17 00:00:00 2001 From: Noa Date: Wed, 2 Apr 2025 13:09:13 -0500 Subject: [PATCH] Update tungstenite to 0.26 (#2539) --- Cargo.lock | 130 ++++++++++++++++---- Cargo.toml | 2 +- crates/client-api/src/routes/subscribe.rs | 34 +++-- crates/core/src/client/client_connection.rs | 18 ++- crates/core/src/client/message_handlers.rs | 25 ++-- crates/sdk/src/websocket.rs | 10 +- 6 files changed, 162 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d4cd1bec4..0c3044147b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", ] @@ -55,10 +55,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -2001,10 +2001,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + [[package]] name = "gimli" version = "0.29.0" @@ -3121,7 +3133,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] @@ -3133,7 +3145,7 @@ checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi 0.3.9", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -3780,7 +3792,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -3862,7 +3874,7 @@ dependencies = [ "lazy_static", "num-traits", "rand 0.8.5", - "rand_chacha", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax 0.8.5", "rusty-fork", @@ -4012,6 +4024,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -4048,10 +4066,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", + "rand_chacha 0.3.1", "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.24", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -4062,6 +4091,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -4083,7 +4122,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.2", ] [[package]] @@ -4148,7 +4196,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", "thiserror 1.0.69", ] @@ -4330,7 +4378,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -4955,7 +5003,7 @@ version = "1.1.0" dependencies = [ "bytemuck", "derive_more", - "getrandom", + "getrandom 0.2.15", "insta", "log", "rand 0.8.5", @@ -6458,9 +6506,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.21.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" dependencies = [ "futures-util", "log", @@ -6721,21 +6769,19 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.21.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" dependencies = [ - "byteorder", "bytes", "data-encoding", "http 1.1.0", "httparse", "log", "native-tls", - "rand 0.8.5", + "rand 0.9.0", "sha1", - "thiserror 1.0.69", - "url", + "thiserror 2.0.11", "utf-8", ] @@ -6878,7 +6924,7 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -6959,6 +7005,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasite" version = "0.1.0" @@ -7713,6 +7768,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "wit-parser" version = "0.217.0" @@ -7821,7 +7885,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", ] [[package]] @@ -7835,6 +7908,17 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "zerofrom" version = "0.1.4" diff --git a/Cargo.toml b/Cargo.toml index ec985a98ed..7caaf837d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -249,7 +249,7 @@ thin-vec = "0.2.13" thiserror = "1.0.37" tokio = { version = "1.37", features = ["full"] } tokio-postgres = { version = "0.7.8", features = ["with-chrono-0_4"] } -tokio-tungstenite = { version = "0.21", features = ["native-tls"] } +tokio-tungstenite = { version = "0.26.2", features = ["native-tls"] } tokio-util = { version = "0.7.4", features = ["time"] } toml = "0.8" toml_edit = "0.22.22" diff --git a/crates/client-api/src/routes/subscribe.rs b/crates/client-api/src/routes/subscribe.rs index c23c32d8f8..51d51120ec 100644 --- a/crates/client-api/src/routes/subscribe.rs +++ b/crates/client-api/src/routes/subscribe.rs @@ -7,6 +7,8 @@ use axum::extract::{Path, Query, State}; use axum::response::IntoResponse; use axum::Extension; use axum_extra::TypedHeader; +use bytes::Bytes; +use bytestring::ByteString; use futures::future::MaybeDone; use futures::{Future, FutureExt, SinkExt, StreamExt}; use http::{HeaderValue, StatusCode}; @@ -22,6 +24,7 @@ use spacetimedb_client_api_messages::websocket::{self as ws_api, Compression}; use spacetimedb_lib::connection_id::{ConnectionId, ConnectionIdForUrl}; use std::time::Instant; use tokio::sync::mpsc; +use tokio_tungstenite::tungstenite::Utf8Bytes; use crate::auth::SpacetimeAuth; use crate::util::websocket::{ @@ -122,12 +125,10 @@ where name: ctx.client_actor_index().next_client_name(), }; - let ws_config = WebSocketConfig { - max_message_size: Some(0x2000000), - max_frame_size: None, - accept_unmasked_frames: false, - ..Default::default() - }; + let ws_config = WebSocketConfig::default() + .max_message_size(Some(0x2000000)) + .max_frame_size(None) + .accept_unmasked_frames(false); tokio::spawn(async move { let ws = match ws_upgrade.upgrade(ws_config).await { @@ -340,7 +341,7 @@ async fn ws_client_actor_inner( if mem::take(&mut got_pong) { // Send a ping message while continuing to poll the `handle_queue`, // to avoid deadlocks or delays due to enqueued futures holding resources. - if let Err(e) = also_poll(ws.send(WsMessage::Ping(Vec::new())), make_progress(&mut current_message)).await { + if let Err(e) = also_poll(ws.send(WsMessage::Ping(Bytes::new())), make_progress(&mut current_message)).await { log::warn!("error sending ping: {e:#}"); } continue; @@ -416,14 +417,14 @@ async fn ws_client_actor_inner( enum ClientMessage { Message(DataMessage), - Ping(Vec), - Pong(Vec), - Close(Option>), + Ping(Bytes), + Pong(Bytes), + Close(Option), } impl ClientMessage { fn from_message(msg: WsMessage) -> Self { match msg { - WsMessage::Text(s) => Self::Message(DataMessage::Text(s)), + WsMessage::Text(s) => Self::Message(DataMessage::Text(utf8bytes_to_bytestring(s))), WsMessage::Binary(b) => Self::Message(DataMessage::Binary(b)), WsMessage::Ping(b) => Self::Ping(b), WsMessage::Pong(b) => Self::Pong(b), @@ -436,7 +437,16 @@ impl ClientMessage { fn datamsg_to_wsmsg(msg: DataMessage) -> WsMessage { match msg { - DataMessage::Text(text) => WsMessage::Text(text), + DataMessage::Text(text) => WsMessage::Text(bytestring_to_utf8bytes(text)), DataMessage::Binary(bin) => WsMessage::Binary(bin), } } + +fn utf8bytes_to_bytestring(s: Utf8Bytes) -> ByteString { + // SAFETY: `Utf8Bytes` and `ByteString` have the same invariant of UTF-8 validity + unsafe { ByteString::from_bytes_unchecked(Bytes::from(s)) } +} +fn bytestring_to_utf8bytes(s: ByteString) -> Utf8Bytes { + // SAFETY: `Utf8Bytes` and `ByteString` have the same invariant of UTF-8 validity + unsafe { Utf8Bytes::from_bytes_unchecked(s.into_bytes()) } +} diff --git a/crates/core/src/client/client_connection.rs b/crates/core/src/client/client_connection.rs index 6346516d0a..072f983dea 100644 --- a/crates/core/src/client/client_connection.rs +++ b/crates/core/src/client/client_connection.rs @@ -11,6 +11,8 @@ use crate::host::{ModuleHost, NoSuchModule, ReducerArgs, ReducerCallError, Reduc use crate::messages::websocket::Subscribe; use crate::util::prometheus_handle::IntGaugeExt; use crate::worker_metrics::WORKER_METRICS; +use bytes::Bytes; +use bytestring::ByteString; use derive_more::From; use futures::prelude::*; use spacetimedb_client_api_messages::websocket::{ @@ -141,8 +143,20 @@ impl Deref for ClientConnection { #[derive(Debug, From)] pub enum DataMessage { - Text(String), - Binary(Vec), + Text(ByteString), + Binary(Bytes), +} + +impl From for DataMessage { + fn from(value: String) -> Self { + ByteString::from(value).into() + } +} + +impl From> for DataMessage { + fn from(value: Vec) -> Self { + Bytes::from(value).into() + } } impl DataMessage { diff --git a/crates/core/src/client/message_handlers.rs b/crates/core/src/client/message_handlers.rs index 1a3bd7f111..d6ce25acb4 100644 --- a/crates/core/src/client/message_handlers.rs +++ b/crates/core/src/client/message_handlers.rs @@ -7,11 +7,10 @@ use crate::host::{ReducerArgs, ReducerId}; use crate::identity::Identity; use crate::messages::websocket::{CallReducer, ClientMessage, OneOffQuery}; use crate::worker_metrics::WORKER_METRICS; -use bytes::Bytes; -use bytestring::ByteString; use spacetimedb_lib::de::serde::DeserializeWrapper; use spacetimedb_lib::identity::RequestId; use spacetimedb_lib::{bsatn, ConnectionId, Timestamp}; +use std::borrow::Cow; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -45,17 +44,19 @@ pub async fn handle(client: &ClientConnection, message: DataMessage, timer: Inst .inc(); let message = match message { - DataMessage::Text(message) => { - let message = ByteString::from(message); - // TODO: update json clients and use the ws version - serde_json::from_str::>>(&message)? - .0 - .map_args(ReducerArgs::Json) - } - DataMessage::Binary(message_buf) => { - let message_buf = Bytes::from(message_buf); - bsatn::from_slice::>(&message_buf)?.map_args(ReducerArgs::Bsatn) + DataMessage::Text(text) => { + // TODO(breaking): this should ideally be &serde_json::RawValue, not json-nested-in-string + let DeserializeWrapper(message) = + serde_json::from_str::>>>(&text)?; + message.map_args(|s| { + ReducerArgs::Json(match s { + Cow::Borrowed(s) => text.slice_ref(s), + Cow::Owned(string) => string.into(), + }) + }) } + DataMessage::Binary(message_buf) => bsatn::from_slice::>(&message_buf)? + .map_args(|b| ReducerArgs::Bsatn(message_buf.slice_ref(b))), }; let database_identity = client.module.info().database_identity; diff --git a/crates/sdk/src/websocket.rs b/crates/sdk/src/websocket.rs index 7a4119af07..436520d50d 100644 --- a/crates/sdk/src/websocket.rs +++ b/crates/sdk/src/websocket.rs @@ -218,11 +218,7 @@ impl WsConnection { // TODO(kim): In order to be able to replicate module WASM blobs, // `cloud-next` cannot have message / frame size limits. That's // obviously a bad default for all other clients, though. - Some(WebSocketConfig { - max_frame_size: None, - max_message_size: None, - ..WebSocketConfig::default() - }), + Some(WebSocketConfig::default().max_frame_size(None).max_message_size(None)), false, ) .await @@ -265,7 +261,7 @@ impl WsConnection { } pub(crate) fn encode_message(msg: ClientMessage) -> WebSocketMessage { - WebSocketMessage::Binary(bsatn::to_vec(&msg).unwrap()) + WebSocketMessage::Binary(bsatn::to_vec(&msg).unwrap().into()) } fn maybe_log_error(cause: &str, res: std::result::Result) { @@ -386,7 +382,7 @@ impl WsConnection { } log::trace!("sending client ping"); - let ping = WebSocketMessage::Ping(vec![]); + let ping = WebSocketMessage::Ping(Bytes::new()); if let Err(e) = self.sock.send(ping).await { log::warn!("Error sending ping: {e:?}"); break;