Skip to content

Commit

Permalink
Merge branch 'master' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
sunli829 committed Jul 27, 2024
2 parents c3c6e20 + 9d32cec commit a901b91
Show file tree
Hide file tree
Showing 19 changed files with 167 additions and 40 deletions.
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ repository = "https://github.com/poem-web/poem"
rust-version = "1.75"

[workspace.dependencies]
poem = { path = "poem", version = "3.0.2", default-features = false }
poem-derive = { path = "poem-derive", version = "3.0.2" }
poem = { path = "poem", version = "3.0.4", default-features = false }
poem-derive = { path = "poem-derive", version = "3.0.4" }
poem-openapi-derive = { path = "poem-openapi-derive", version = "5.0.3" }
poem-grpc-build = { path = "poem-grpc-build", version = "0.4.0" }
poem-grpc-build = { path = "poem-grpc-build", version = "0.4.2" }

proc-macro-crate = "3.0.0"
proc-macro2 = "1.0.29"
quote = "1.0.9"
syn = { version = "2.0" }
tokio = "1.17.0"
tokio = "1.39.1"
serde_json = "1.0.68"
serde = { version = "1.0.130", features = ["derive"] }
thiserror = "1.0.30"
Expand All @@ -41,7 +41,7 @@ bytes = "1.1.0"
futures-util = "0.3.17"
tokio-stream = "0.1.8"
serde_yaml = "0.9"
quick-xml = { version = "0.32.0", features = ["serialize"] }
quick-xml = { version = "0.36.1", features = ["serialize"] }
base64 = "0.22.0"
serde_urlencoded = "0.7.1"
indexmap = "2.0.0"
Expand Down
6 changes: 5 additions & 1 deletion examples/poem/redis-session/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ publish.workspace = true
poem = { workspace = true, features = ["redis-session"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
tracing-subscriber.workspace = true
redis = { version = "0.25.2", features = ["aio", "tokio-comp", "connection-manager"] }
redis = { version = "0.26.0", features = [
"aio",
"tokio-comp",
"connection-manager",
] }
2 changes: 1 addition & 1 deletion poem-derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "poem-derive"
version = "3.0.2"
version = "3.0.4"
authors.workspace = true
edition.workspace = true
license.workspace = true
Expand Down
23 changes: 18 additions & 5 deletions poem-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fn generate_handler(internal: bool, input: TokenStream) -> Result<TokenStream> {
};

let def_struct = if !item_fn.sig.generics.params.is_empty() {
let members = item_fn
let iter = item_fn
.sig
.generics
.params
Expand All @@ -70,13 +70,26 @@ fn generate_handler(internal: bool, input: TokenStream) -> Result<TokenStream> {
})
.enumerate()
.map(|(idx, ty)| {
let ty_ident = &ty.ident;
let ident = format_ident!("_mark{}", idx);
quote! { #ident: ::std::marker::PhantomData<#ty_ident> }
let ty_ident = &ty.ident;
(ident, ty_ident)
});

let struct_members = iter.clone().map(|(ident, ty_ident)| {
quote! { #ident: ::std::marker::PhantomData<#ty_ident> }
});

let default_members = iter.clone().map(|(ident, _ty_ident)| {
quote! { #ident: ::std::marker::PhantomData }
});

quote! {
#[derive(Default)]
#vis struct #ident #type_generics { #(#members),*}
#vis struct #ident #type_generics { #(#struct_members),*}
impl #type_generics ::std::default::Default for #ident #type_generics {
fn default() -> Self {
Self { #(#default_members),* }
}
}
}
} else {
quote! { #vis struct #ident; }
Expand Down
2 changes: 1 addition & 1 deletion poem-grpc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "poem-grpc"
version = "0.4.2"
version = "0.4.3"
authors.workspace = true
edition.workspace = true
license.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion poem-lambda/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "poem-lambda"
version = "5.0.0"
version = "5.0.1"
authors.workspace = true
edition.workspace = true
license.workspace = true
Expand Down
4 changes: 4 additions & 0 deletions poem-openapi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

# [5.0.3] 2024-07-27

- Added derivations for Type, ParseFromJSON and ToJSON for sqlx types [#833](https://github.com/poem-web/poem/pull/833)

# [5.0.1] 2024-05-18

- Add enum_items to discriminated union [#741](https://github.com/poem-web/poem/pull/741)
Expand Down
8 changes: 7 additions & 1 deletion poem-openapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ hostname-validator = { version = "1.1.0", optional = true }
chrono = { workspace = true, optional = true, default-features = false, features = [
"clock",
] }
time = { version = "0.3.9", optional = true, features = [
time = { version = "0.3.36", optional = true, features = [
"parsing",
"formatting",
] }
Expand All @@ -72,6 +72,12 @@ ipnet = { version = "2.7.1", optional = true }
prost-wkt-types = { version = "0.5.0", optional = true }
geo-types = { version = "0.7.12", optional = true }
geojson = { version = "0.24.1", features = ["geo-types"], optional = true }
sqlx = { version = "0.7.4", features = [
"json",
"postgres",
"sqlite",
"mysql",
], optional = true }

[dev-dependencies]
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
Expand Down
2 changes: 2 additions & 0 deletions poem-openapi/src/types/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ mod optional;
mod prost_wkt_types;
mod regex;
mod slice;
#[cfg(feature = "sqlx")]
mod sqlx;
mod string;
#[cfg(feature = "time")]
mod time;
Expand Down
48 changes: 48 additions & 0 deletions poem-openapi/src/types/external/sqlx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::borrow::Cow;

use serde_json::Value;

use crate::{
registry::MetaSchemaRef,
types::{ParseError, ParseFromJSON, ParseResult, ToJSON, Type},
};

impl<T: Type> Type for sqlx::types::Json<T> {
const IS_REQUIRED: bool = Self::RawValueType::IS_REQUIRED;

type RawValueType = T;

type RawElementValueType = T::RawElementValueType;

fn name() -> Cow<'static, str> {
Self::RawValueType::name()
}

fn schema_ref() -> MetaSchemaRef {
Self::RawValueType::schema_ref()
}

fn as_raw_value(&self) -> Option<&Self::RawValueType> {
Some(&self.0)
}

fn raw_element_iter<'a>(
&'a self,
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
self.0.raw_element_iter()
}
}

impl<T: ParseFromJSON> ParseFromJSON for sqlx::types::Json<T> {
fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
Self::RawValueType::parse_from_json(value)
.map(sqlx::types::Json)
.map_err(ParseError::propagate)
}
}

impl<T: ToJSON> ToJSON for sqlx::types::Json<T> {
fn to_json(&self) -> Option<Value> {
self.0.to_json()
}
}
4 changes: 2 additions & 2 deletions poem-openapi/src/types/multipart/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
use poem::web::Field as PoemField;
use tokio::{
fs::File,
io::{AsyncRead, AsyncReadExt, Error as IoError, ErrorKind},
io::{AsyncRead, AsyncReadExt, AsyncSeek, Error as IoError, ErrorKind},
};

use crate::{
Expand Down Expand Up @@ -74,7 +74,7 @@ impl Upload {
}

/// Consumes this body object to return a reader.
pub fn into_async_read(self) -> impl AsyncRead + Unpin + Send + 'static {
pub fn into_async_read(self) -> impl AsyncRead + AsyncSeek + Unpin + Send + 'static {
self.file
}

Expand Down
29 changes: 29 additions & 0 deletions poem-openapi/tests/multipart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use poem_openapi::{
},
Enum, Multipart, Object,
};
use tokio::io::{AsyncReadExt, AsyncSeekExt};

fn create_multipart_payload(parts: &[(&str, Option<&str>, &[u8])]) -> Vec<u8> {
let mut data = Vec::new();
Expand Down Expand Up @@ -237,6 +238,34 @@ async fn upload() {
assert_eq!(a.file.content_type(), None);
assert_eq!(a.file.size(), 3);
assert_eq!(a.file.into_vec().await.unwrap(), vec![1, 2, 3]);

let data =
create_multipart_payload(&[("name", None, b"abc"), ("file", Some("1.txt"), &[1, 2, 3])]);
let a = A::from_request(
&Request::builder()
.header("content-type", "multipart/form-data; boundary=X-BOUNDARY")
.finish(),
&mut RequestBody::new(data.into()),
)
.await
.unwrap();
assert_eq!(a.name, "abc".to_string());

assert_eq!(a.file.file_name(), Some("1.txt"));
assert_eq!(a.file.content_type(), None);
assert_eq!(a.file.size(), 3);

let mut reader = a.file.into_async_read();
let mut buffer = [0; 3];
let n = reader.read_exact(&mut buffer[..]).await.unwrap();
assert_eq!(n, 3);
assert_eq!(buffer[..n], vec![1, 2, 3]);
let n = reader.read(&mut buffer[..]).await.unwrap();
assert_eq!(n, 0); // EOF
reader.seek(std::io::SeekFrom::Start(0)).await.unwrap();
let n = reader.read_exact(&mut buffer[..]).await.unwrap();
assert_eq!(n, 3);
assert_eq!(buffer[..n], vec![1, 2, 3]);
}

#[tokio::test]
Expand Down
3 changes: 2 additions & 1 deletion poem-openapi/tests/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use poem_openapi::{
Enum, NewType, Object, OpenApi,
};
use serde_json::json;
use time::OffsetDateTime;

fn get_meta<T: Type>() -> MetaSchema {
let mut registry = Registry::new();
Expand Down Expand Up @@ -390,8 +389,10 @@ fn read_only() {
);
}

#[cfg(feature = "time")]
#[test]
fn read_only_with_default() {
use time::OffsetDateTime;
fn default_offset_datetime() -> OffsetDateTime {
OffsetDateTime::from_unix_timestamp(1694045893).unwrap()
}
Expand Down
8 changes: 8 additions & 0 deletions poem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

# [3.0.4] 2024-07-27

- Add manual Default implementation for `#[handler]` [#848](https://github.com/poem-web/poem/pull/848)
- feat: add `AsyncSeek trait` to `Upload::into_async_read` return type [#853](https://github.com/poem-web/poem/pull/853)
- Fix `EmbeddedFilesEndpoint` not working for `index.html` in subdirectories [#825](https://github.com/poem-web/poem/pull/825)
- chore: Bump `redis` to `0.26` [#856](https://github.com/poem-web/poem/pull/856)
- chore: bump `tokio-tungstenite`, `quick-xml`, `tokio`, `openssl` [#857](https://github.com/poem-web/poem/pull/857)

# [3.0.3] 2024-07-20

- bump `opentelemetry` from `0.23` to `0.24`
Expand Down
10 changes: 5 additions & 5 deletions poem/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "poem"
version = "3.0.3"
version = "3.0.4"
authors.workspace = true
edition.workspace = true
license.workspace = true
Expand Down Expand Up @@ -97,7 +97,7 @@ sync_wrapper = { version = "1.0.0", features = ["futures"] }

# Non-feature optional dependencies
multer = { version = "3.0.0", features = ["tokio"], optional = true }
tokio-tungstenite = { version = "0.21.0", optional = true }
tokio-tungstenite = { version = "0.23.1", optional = true }
tokio-rustls = { workspace = true, optional = true }
rustls-pemfile = { version = "2.0.0", optional = true }
async-compression = { version = "0.4.0", optional = true, features = [
Expand All @@ -116,7 +116,7 @@ chrono = { workspace = true, optional = true, default-features = false, features
time = { version = "0.3", optional = true }
mime_guess = { version = "2.0.3", optional = true }
rand = { version = "0.8.4", optional = true }
redis = { version = "0.25.2", optional = true, features = [
redis = { version = "0.26.0", optional = true, features = [
"aio",
"tokio-comp",
"connection-manager",
Expand All @@ -139,7 +139,7 @@ libtempfile = { package = "tempfile", version = "3.2.0", optional = true }
priority-queue = { version = "2.0.2", optional = true }
tokio-native-tls = { version = "0.3.0", optional = true }
tokio-openssl = { version = "0.6.3", optional = true }
openssl = { version = "0.10.56", optional = true }
openssl = { version = "0.10.66", optional = true }
base64 = { workspace = true, optional = true }
libcsrf = { package = "csrf", version = "0.4.1", optional = true }
httpdate = { version = "1.0.2", optional = true }
Expand Down Expand Up @@ -168,7 +168,7 @@ uuid = { version = "1.8.0", optional = true, default-features = false, features
] }

[target.'cfg(unix)'.dependencies]
nix = { version = "0.28.0", features = ["fs", "user"] }
nix = { version = "0.29.0", features = ["fs", "user"] }

[dev-dependencies]
async-stream = "0.3.2"
Expand Down
33 changes: 23 additions & 10 deletions poem/src/endpoint/embed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,29 @@ impl<E: RustEmbed + Send + Sync> Endpoint for EmbeddedFilesEndpoint<E> {
type Output = Response;

async fn call(&self, req: Request) -> Result<Self::Output, Error> {
let mut path = req
.uri()
.path()
.trim_start_matches('/')
.trim_end_matches('/')
.to_string();
if path.is_empty() {
path = "index.html".to_string();
let path = req.uri().path().trim_start_matches('/');
let original_path = req.original_uri().path();
let original_end_with_slash = original_path.ends_with('/');

use header::LOCATION;

if path.is_empty() && !original_end_with_slash {
Ok(Response::builder()
.status(StatusCode::FOUND)
.header(LOCATION, format!("{}/", original_path))
.finish())
} else if original_end_with_slash {
let path = format!("{}index.html", path);
EmbeddedFileEndpoint::<E>::new(&path).call(req).await
} else if E::get(path).is_some() {
EmbeddedFileEndpoint::<E>::new(path).call(req).await
} else if E::get(&format!("{}/index.html", path)).is_some() {
Ok(Response::builder()
.status(StatusCode::FOUND)
.header(LOCATION, format!("{}/", original_path))
.finish())
} else {
EmbeddedFileEndpoint::<E>::new(path).call(req).await
}
let path = path.as_ref();
EmbeddedFileEndpoint::<E>::new(path).call(req).await
}
}
8 changes: 4 additions & 4 deletions poem/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1176,11 +1176,11 @@ mod tests {
assert_eq!(err.into_response().status(), StatusCode::BAD_GATEWAY);
}

#[cfg(feature = "eyre6")]
#[cfg(feature = "eyre06")]
#[test]
fn test_eyre6_error() {
let eyre6_err: eyre6::Error = IoError::new(ErrorKind::AlreadyExists, "aaa").into();
let err: Error = Error::from((StatusCode::BAD_GATEWAY, eyre6_err));
fn test_eyre06_error() {
let eyre06_err: eyre06::Error = IoError::new(ErrorKind::AlreadyExists, "aaa").into();
let err: Error = Error::from((StatusCode::BAD_GATEWAY, eyre06_err));
assert!(err.is::<IoError>());
assert_eq!(
err.downcast_ref::<IoError>().unwrap().kind(),
Expand Down
Loading

0 comments on commit a901b91

Please sign in to comment.