From 4c3ca68897e4a44143f0fed8382f8066edb67d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?19=E5=B9=B4=E6=A2=A6=E9=86=92?= <3949379+getong@users.noreply.github.com> Date: Mon, 13 Jan 2025 00:36:09 +0800 Subject: [PATCH 1/2] update axum to 0.8 --- crates/tuono_lib/Cargo.toml | 9 ++++----- crates/tuono_lib/src/vite_websocket_proxy.rs | 9 +++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/tuono_lib/Cargo.toml b/crates/tuono_lib/Cargo.toml index 70569e81..01f074a3 100644 --- a/crates/tuono_lib/Cargo.toml +++ b/crates/tuono_lib/Cargo.toml @@ -18,8 +18,8 @@ include = [ [dependencies] ssr_rs = "0.8.0" -axum = {version = "0.7.5", features = ["json", "ws"]} -axum-extra = {version = "0.9.6", features = ["cookie"]} +axum = {version = "0.8", features = ["json", "ws"]} +axum-extra = {version = "0.10", features = ["cookie"]} tokio = { version = "1.37.0", features = ["full"] } serde = { version = "1.0.202", features = ["derive"] } erased-serde = "0.4.5" @@ -34,10 +34,9 @@ colored = "2.1.0" tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.17.0"} # Match the same version used by axum -tokio-tungstenite = "0.24.0" +tokio-tungstenite = "0.26" futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] } -tungstenite = "0.24.0" +tungstenite = "0.26" http = "1.1.0" pin-project = "1.1.7" tower = "0.5.1" - diff --git a/crates/tuono_lib/src/vite_websocket_proxy.rs b/crates/tuono_lib/src/vite_websocket_proxy.rs index 0dce599f..5f9f5b16 100644 --- a/crates/tuono_lib/src/vite_websocket_proxy.rs +++ b/crates/tuono_lib/src/vite_websocket_proxy.rs @@ -1,10 +1,11 @@ -use axum::extract::ws::{self, WebSocket, WebSocketUpgrade}; +use axum::extract::ws::{self, Utf8Bytes as AxumUtf8Bytes, WebSocket, WebSocketUpgrade}; use axum::response::IntoResponse; use futures_util::{SinkExt, StreamExt}; use tokio_tungstenite::connect_async; use tokio_tungstenite::tungstenite::{Error, Message}; use tungstenite::client::IntoClientRequest; use tungstenite::ClientRequestBuilder; +use tungstenite::protocol::frame::Utf8Bytes; const VITE_WS: &str = "ws://localhost:3001/vite-server/"; const VITE_WS_PROTOCOL: &str = "vite-hmr"; @@ -54,7 +55,7 @@ async fn handle_socket(mut tuono_socket: WebSocket) { while let Some(msg) = tuono_receiver.next().await { if let Ok(msg) = msg { let msg_to_vite = match msg.clone() { - ws::Message::Text(str) => Message::Text(str), + ws::Message::Text(str) => Message::Text(Utf8Bytes::from_static(str.as_str())), ws::Message::Pong(payload) => Message::Pong(payload), ws::Message::Ping(payload) => Message::Ping(payload), ws::Message::Binary(payload) => Message::Binary(payload), @@ -81,7 +82,7 @@ async fn handle_socket(mut tuono_socket: WebSocket) { tokio::spawn(async move { while let Some(Ok(msg)) = vite_receiver.next().await { let msg_to_browser = match msg { - Message::Text(str) => ws::Message::Text(str), + Message::Text(str) => ws::Message::Text(AxumUtf8Bytes::from_static(str.as_str())), Message::Ping(payload) => ws::Message::Ping(payload), Message::Pong(payload) => ws::Message::Pong(payload), Message::Binary(payload) => ws::Message::Binary(payload), @@ -90,7 +91,7 @@ async fn handle_socket(mut tuono_socket: WebSocket) { Message::Close(_) => ws::Message::Close(None), _ => { eprintln!("Unexpected message from the vite WebSocket to the browser: {msg:?}"); - ws::Message::Text("Unhandled".to_string()) + ws::Message::Text("Unhandled".to_string().into()) } }; From f1aff6488de0a1bdaca7fb9c7e99790ab315bd19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?19=E5=B9=B4=E6=A2=A6=E9=86=92?= <3949379+getong@users.noreply.github.com> Date: Wed, 15 Jan 2025 23:15:17 +0800 Subject: [PATCH 2/2] change the axum router name, and rewrite the test code --- crates/tuono/src/app.rs | 2 +- crates/tuono/src/route.rs | 19 ++++++++++++++----- crates/tuono/tests/cli_tests.rs | 11 ++++------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/crates/tuono/src/app.rs b/crates/tuono/src/app.rs index 1f1bef0b..6993aa63 100644 --- a/crates/tuono/src/app.rs +++ b/crates/tuono/src/app.rs @@ -290,7 +290,7 @@ mod tests { ("/about", "/about"), ("/posts/index", "/posts"), ("/posts/any-post", "/posts/any-post"), - ("/posts/[post]", "/posts/:post"), + ("/posts/[post]", "/posts/{post}"), ]; results.into_iter().for_each(|(path, expected_path)| { diff --git a/crates/tuono/src/route.rs b/crates/tuono/src/route.rs index 5255dbfd..ea7594bf 100644 --- a/crates/tuono/src/route.rs +++ b/crates/tuono/src/route.rs @@ -45,6 +45,18 @@ impl AxumInfo { } if route.is_dynamic { + // axum 0.7, react [single] maps to :single, [...many] maps to *many, + // axum 0.8, the path parameter syntax from /:single and /*many to /{single} and /{*many} + // so axum 0.8, react [single] maps to {single}, [...many] maps to {*many} + let dyn_re = Regex::new(r"\[(.*?)\]").expect("Failed to create dyn regex"); + let catch_all_re = + Regex::new(r"\[\.\.\.(.*?)\]").expect("Failed to create catch all regex"); + let dyn_result = dyn_re.replace_all(&axum_route, |caps: ®ex::Captures| { + format!("{{{}}}", &caps[1]) + }); + let axum_route = catch_all_re.replace_all(&dyn_result, |caps: ®ex::Captures| { + format!("{{*{}}}", &caps[1]) + }); return AxumInfo { module_import: module .as_str() @@ -54,10 +66,7 @@ impl AxumInfo { .replace('[', "dyn_") .replace("...", "catch_all_") .replace(']', ""), - axum_route: axum_route - .replace("[...", "*") - .replace('[', ":") - .replace(']', ""), + axum_route: axum_route.to_string(), }; } @@ -239,7 +248,7 @@ mod tests { let dyn_info = AxumInfo::new(&Route::new("/[posts]".to_string())); - assert_eq!(dyn_info.axum_route, "/:posts"); + assert_eq!(dyn_info.axum_route, "/{posts}"); assert_eq!(dyn_info.module_import, "dyn_posts"); } diff --git a/crates/tuono/tests/cli_tests.rs b/crates/tuono/tests/cli_tests.rs index 5bc194b1..8e84fe71 100644 --- a/crates/tuono/tests/cli_tests.rs +++ b/crates/tuono/tests/cli_tests.rs @@ -124,19 +124,16 @@ fn it_successfully_create_catch_all_routes() { assert!(temp_main_rs_content.contains(r#"#[path="../src/routes/[...all_routes].rs"]"#)); assert!(temp_main_rs_content.contains("mod dyn_catch_all_all_routes;")); + println!("temp_main_rs_content: {:?}", temp_main_rs_content); assert!(temp_main_rs_content.contains( - r#".route("/api/*all_apis", post(api_dyn_catch_all_all_apis::post__tuono_internal_api))"# + r#".route("/api/{*all_apis}", post(api_dyn_catch_all_all_apis::post__tuono_internal_api))"# )); assert!(temp_main_rs_content.contains( - r#".route("/*all_routes", get(dyn_catch_all_all_routes::tuono__internal__route))"# - )); - - assert!(temp_main_rs_content.contains( - r#".route("/*all_routes", get(dyn_catch_all_all_routes::tuono__internal__route))"# + r#".route("/{*all_routes}", get(dyn_catch_all_all_routes::tuono__internal__route))"# )); assert!(temp_main_rs_content - .contains(r#".route("/__tuono/data/*all_routes", get(dyn_catch_all_all_routes::tuono__internal__api))"#)); + .contains(r#".route("/__tuono/data/{*all_routes}", get(dyn_catch_all_all_routes::tuono__internal__api))"#)); }