Changes to support axum 0.8 (#3820)

* changes to support axum 0.8

* fixing ci/cd failures. I would like advice on the change to cli/server

* putting back in something I took out because I am retarded

* update server function revision

* remove playwright test results

* clippy

---------

Co-authored-by: Evan Almloff <evanalmloff@gmail.com>
Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
authored and GitHub committed 2025-04-15 13:13:58 -07:00
1 parent 66e284ce42
commit 1379de7cc7
14 files changed
+296 -314

No files matched your search

Generated
+222 -161
View File
File diff suppressed because it is too large. Load diff
+4 -3
View File
@@ -208,7 +208,7 @@ tauri-utils = { version = "=2.1.1" }
tauri-bundler = { version = "=2.2.3" }
lru = "0.12.2"
async-trait = "0.1.77"
axum = { version = "0.7.0", default-features = false }
axum = "0.8.1"
axum-server = { version = "0.7.1", default-features = false }
tower = "0.4.13"
http = "1.0.0"
@@ -222,8 +222,9 @@ serde = "1.0.61"
syn = "2.0"
quote = "1.0"
proc-macro2 = "1.0"
axum_session = "0.12.1"
axum_session_auth = "0.12.1"
axum_session = "0.16.0"
axum_session_auth = "0.16.0"
axum_session_sqlx = "0.5.0"
axum-extra = "0.9.2"
reqwest = "0.12.5"
owo-colors = "4.0.0"
+7 -3
View File
@@ -16,7 +16,7 @@ axum = { workspace = true, optional = true }
tokio = { workspace = true, features = ["full"], optional = true }
tower-http = { workspace = true, features = ["auth"], optional = true }
async-trait = { version = "0.1.71", optional = true }
sqlx = { version = "0.7.0", features = [
sqlx = { version = "0.8.2", features = [
"macros",
"migrate",
"postgres",
@@ -34,12 +34,15 @@ anyhow = { workspace = true }
[dependencies.axum_session]
workspace = true
features = ["sqlite-rustls"]
optional = true
[dependencies.axum_session_auth]
workspace = true
features = ["sqlite-rustls"]
optional = true
[dependencies.axum_session_sqlx]
workspace = true
features = ["sqlite"]
optional = true
[features]
@@ -54,6 +57,7 @@ server = [
"sqlx",
"axum_session",
"axum_session_auth",
"axum_session_sqlx",
"http",
"tower",
]
+4 -7
View File
@@ -5,8 +5,9 @@ use axum::{
routing::get,
Router,
};
use axum_session::{SessionConfig, SessionLayer, SessionSqlitePool, SessionStore};
use axum_session::{SessionConfig, SessionLayer, SessionStore};
use axum_session_auth::*;
use axum_session_sqlx::SessionSqlitePool;
use core::pin::Pin;
use dioxus_fullstack::prelude::*;
use serde::{Deserialize, Serialize};
@@ -192,12 +193,8 @@ pub async fn connect_to_database() -> SqlitePool {
.unwrap()
}
pub type Session = axum_session_auth::AuthSession<
crate::auth::User,
i64,
axum_session_auth::SessionSqlitePool,
sqlx::SqlitePool,
>;
pub type Session =
axum_session_auth::AuthSession<crate::auth::User, i64, SessionSqlitePool, sqlx::SqlitePool>;
pub async fn get_session() -> Result<Session, ServerFnError> {
extract::<Session, _>()
+2 -2
View File
@@ -22,7 +22,7 @@ fn main() {
use axum_session::SessionConfig;
use axum_session::SessionStore;
use axum_session_auth::AuthConfig;
use axum_session_auth::SessionSqlitePool;
use axum_session_sqlx::SessionSqlitePool;
tokio::runtime::Runtime::new()
.unwrap()
.block_on(async move {
@@ -49,7 +49,7 @@ fn main() {
axum_session_auth::AuthSessionLayer::<
crate::auth::User,
i64,
axum_session_auth::SessionSqlitePool,
SessionSqlitePool,
sqlx::SqlitePool,
>::new(Some(pool))
.with_config(auth_config),
+2 -2
View File
@@ -73,7 +73,7 @@ pub(crate) fn add_proxy(mut router: Router, proxy: &WebProxyConfig) -> Result<Ro
// api/*path
router = router.route(
&format!("/{}/*path", trimmed_path.trim_end_matches('/')),
&format!("/{}/{{*path}}", trimmed_path.trim_end_matches('/')),
method_router.clone(),
);
@@ -190,7 +190,7 @@ mod test {
async fn setup_servers(mut config: WebProxyConfig) -> String {
let backend_router =
Router::new().route(
"/*path",
"/{*path}",
any(|request: axum::extract::Request| async move {
format!("backend: {}", request.uri())
}),
+19 -8
View File
@@ -211,8 +211,8 @@ impl WebServer {
}
self.send_shutdown().await;
for socket in self.hot_reload_sockets.drain(..) {
_ = socket.close().await;
for mut socket in self.hot_reload_sockets.drain(..) {
_ = socket.send(Message::Close(None)).await;
}
}
@@ -302,7 +302,11 @@ impl WebServer {
let mut i = 0;
while i < self.hot_reload_sockets.len() {
let socket = &mut self.hot_reload_sockets[i];
if socket.send(Message::Text(msg.clone())).await.is_err() {
if socket
.send(Message::Text(msg.clone().into()))
.await
.is_err()
{
self.hot_reload_sockets.remove(i);
} else {
i += 1;
@@ -343,7 +347,7 @@ impl WebServer {
async fn send_devserver_message(&mut self, msg: DevserverMsg) {
for socket in self.hot_reload_sockets.iter_mut() {
_ = socket
.send(Message::Text(serde_json::to_string(&msg).unwrap()))
.send(Message::Text(serde_json::to_string(&msg).unwrap().into()))
.await;
}
}
@@ -393,7 +397,11 @@ async fn devserver_mainloop(
// If we're not using rustls, just use regular axum
if https_cfg.enabled != Some(true) {
axum::serve(listener.try_into().unwrap(), router.into_make_service()).await?;
axum::serve(
tokio::net::TcpListener::from_std(listener).unwrap(),
router.into_make_service(),
)
.await?;
return Ok(());
}
@@ -434,7 +442,7 @@ fn build_devserver_router(
// For fullstack, liveview, and server, forward all requests to the inner server
let address = fullstack_address.unwrap();
tracing::debug!("Proxying requests to fullstack server at {address}");
router = router.nest_service("/",super::proxy::proxy_to(
router = router.fallback_service(super::proxy::proxy_to(
format!("http://{address}").parse().unwrap(),
true,
|error| {
@@ -461,9 +469,12 @@ fn build_devserver_router(
.unwrap_or_default()
.trim_matches('/')
);
if base_path == "/" {
router = router.fallback_service(build_serve_dir(args, krate));
} else {
router = router.nest_service(&base_path, build_serve_dir(args, krate));
}
}
// Setup middleware to intercept html requests if the build status is "Building"
router = router.layer(middleware::from_fn_with_state(
@@ -755,6 +766,6 @@ impl SharedStatus {
async fn send_to(&self, socket: &mut WebSocket) -> Result<(), axum::Error> {
let msg = serde_json::to_string(&self.get()).unwrap();
socket.send(Message::Text(msg)).await
socket.send(Message::Text(msg.into())).await
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ resolver = "2"
[dependencies]
# server functions
server_fn = { version = "0.7.3", features = ["json", "url", "browser"], default-features = false }
server_fn = { version = "0.8.0-rc1", features = ["browser"], default-features = false }
dioxus_server_macro = { workspace = true }
# axum
-2
View File
@@ -160,8 +160,6 @@ async fn handle_server_fns_inner(
additional_context: ContextProviders,
req: Request<Body>,
) -> impl IntoResponse {
use server_fn::middleware::Service;
let path_string = path.to_string();
let (parts, body) = req.into_parts();
@@ -25,12 +25,12 @@ fn transform_rx(message: Result<Message, axum::Error>) -> Result<Vec<u8>, LiveVi
message
.map_err(|_| LiveViewError::SendingFailed)?
.into_text()
.map(|s| s.into_bytes())
.map(|s| s.as_str().into())
.map_err(|_| LiveViewError::SendingFailed)
}
async fn transform_tx(message: Vec<u8>) -> Result<Message, axum::Error> {
Ok(Message::Binary(message))
Ok(Message::Binary(message.into()))
}
impl LiveviewRouter for Router {
+19 -15
View File
@@ -9,22 +9,23 @@
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.42.1"
"@playwright/test": "^1.51.0"
}
},
"node_modules/@playwright/test": {
"version": "1.42.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz",
"integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==",
"version": "1.51.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.51.0.tgz",
"integrity": "sha512-dJ0dMbZeHhI+wb77+ljx/FeC8VBP6j/rj9OAojO08JI80wTZy6vRk9KvHKiDCUh4iMpEiseMgqRBIeW+eKX6RA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.42.1"
"playwright": "1.51.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=16"
"node": ">=18"
}
},
"node_modules/fsevents": {
@@ -33,6 +34,7 @@
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -42,33 +44,35 @@
}
},
"node_modules/playwright": {
"version": "1.42.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz",
"integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==",
"version": "1.51.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.51.0.tgz",
"integrity": "sha512-442pTfGM0xxfCYxuBa/Pu6B2OqxqqaYq39JS8QDMGThUvIOCd6s0ANDog3uwA0cHavVlnTQzGCN7Id2YekDSXA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.42.1"
"playwright-core": "1.51.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=16"
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.42.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz",
"integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==",
"version": "1.51.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.0.tgz",
"integrity": "sha512-x47yPE3Zwhlil7wlNU/iktF7t2r/URR3VLbH6EknJd/04Qc/PSJ0EY3CMXipmglLG+zyRxW6HNo2EGbKLHPWMg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=16"
"node": ">=18"
}
}
}
+1 -1
View File
@@ -12,6 +12,6 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.42.1"
"@playwright/test": "^1.51.0"
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ description = "Server function macros for Dioxus"
proc-macro2 = "^1.0.63"
quote = "^1.0.26"
syn = { workspace = true, features = ["full"] }
server_fn_macro = { version = "0.7.3" }
server_fn_macro = "0.8.0-rc1"
[dev-dependencies]
dioxus = { workspace = true, features = ["fullstack"] }
+12 -106
View File
@@ -6,12 +6,8 @@
//! See the [server_fn_macro] crate for more information.
use proc_macro::TokenStream;
use quote::quote;
use server_fn_macro::server_macro_impl;
use syn::{
__private::ToTokens,
parse::{Parse, ParseStream},
};
use server_fn_macro::ServerFnCall;
use syn::{__private::ToTokens, parse_quote};
/// Declares that a function is a [server function](https://docs.rs/server_fn/).
/// This means that its body will only run on the server, i.e., when the `ssr`
@@ -146,107 +142,17 @@ use syn::{
/// }
/// ```
#[proc_macro_attribute]
pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
pub fn server(args: proc_macro::TokenStream, body: TokenStream) -> TokenStream {
// If there is no input codec, use json as the default
let args = default_json_codec(args);
match server_macro_impl(
args.into(),
s.into(),
Some(syn::parse_quote!(server_fn)),
"/api",
None,
None,
) {
Err(e) => e.to_compile_error().into(),
Ok(s) => s.to_token_stream().into(),
}
}
fn default_json_codec(args: TokenStream) -> TokenStream {
// Try to parse the args
if let Err(err) = syn::parse::<ServerFnArgsMetadata>(args.clone()) {
return err.to_compile_error().into();
}
let Ok(args_metadata) = syn::parse::<ServerFnArgsMetadata>(args.clone()) else {
// If we fail to parse the args, forward them directly to the macro for diagnostics
return args;
};
let mut new_tokens = args;
// Make sure the args always end with a comma
if args_metadata.requires_trailing_comma {
let default_comma: TokenStream = quote! {,}.into();
new_tokens.extend(default_comma);
}
// If the user didn't override the input codec, default to Json
if !args_metadata.manual_input {
let default_input: TokenStream = quote! {
input = server_fn::codec::Json,
}
.into();
new_tokens.extend(default_input);
}
// If the user didn't override the output codec, default to Json
if !args_metadata.manual_output {
let default_output: TokenStream = quote! {
output = server_fn::codec::Json,
}
.into();
new_tokens.extend(default_output);
}
new_tokens
}
struct ServerFnArgsMetadata {
manual_input: bool,
manual_output: bool,
requires_trailing_comma: bool,
}
impl Parse for ServerFnArgsMetadata {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut manual_input = false;
let mut manual_output = false;
let mut requires_trailing_comma = false;
let mut take_comma = |input: &ParseStream| {
let comma: Option<syn::Token![,]> = input.parse().ok();
requires_trailing_comma = comma.is_none();
let parsed = match ServerFnCall::parse("/api", args.into(), body.into()) {
Ok(parsed) => parsed,
Err(e) => return e.to_compile_error().into(),
};
while !input.is_empty() {
// Ignore legacy ident and string args
if input.peek(syn::Ident) && !input.peek2(syn::Token![=]) {
input.parse::<syn::Ident>()?;
take_comma(&input);
continue;
}
if input.peek(syn::LitStr) && !input.peek2(syn::Token![=]) {
input.parse::<syn::LitStr>()?;
take_comma(&input);
continue;
}
let ident: syn::Ident = input.parse()?;
let _: syn::Token![=] = input.parse()?;
let _: syn::Expr = input.parse()?;
if ident == "input" {
manual_input = true;
} else if ident == "output" {
manual_output = true;
}
take_comma(&input);
}
Ok(Self {
manual_input,
manual_output,
requires_trailing_comma,
})
}
parsed
.default_input_encoding(Some(parse_quote!(server_fn::codec::Json)))
.default_output_encoding(Some(parse_quote!(server_fn::codec::Json)))
.default_server_fn_path(Some(parse_quote!(server_fn)))
.to_token_stream()
.into()
}