richerarc / saphir Goto Github PK
View Code? Open in Web Editor NEWFully async-await http server framework
License: MIT License
Fully async-await http server framework
License: MIT License
route positional paameters name are arbitrarly, so they could be changed to a prefered casing for the api generation.
For example, changing them to camelCase so that when you generate a typescript API for it with ng-openapi-gen, you would have parameters name in the same casing as the rest of your codebase.
Description of the feature
To improve performance, instead of using dynamic dispatch at runtime, in Server::build
we could create a fixed list pointers to all registered handlers, which could be iterated through without having to use any dyn_handle
.
Is your feature request related to a problem?
Not related to a problem, just a performance improvement
Description
The following simple code snippet fails on compilation when trying to use saphir 2.8.0 alongside with tokio 0.3.4
use saphir::server::Server;
use tokio::runtime::Runtime;
fn main() {
let server = Server::builder().build();
tokio::spawn(server.run());
}
[package]
name = "saphir-test"
version = "0.1.0"
edition = "2018"
[dependencies]
tokio = { version = "=0.3.4", features = [ "rt" ]}
saphir = "=2.8"
This code fails due to the following error:
error[E0277]: `(dyn Future<Output = ()> + Unpin + 'static)` cannot be sent between threads safely
--> src\main.rs:6:5
|
6 | tokio::spawn(server.run());
| ^^^^^^^^^^^^ `(dyn Future<Output = ()> + Unpin + 'static)` cannot be sent between threads safely
|
::: C:\Users\pacmancoder\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.3.4\src\task\spawn.rs:128:21
|
128 | T: Future + Send + 'static,
| ---- required by this bound in `tokio::spawn`
|
= help: the trait `Send` is not implemented for `(dyn Future<Output = ()> + Unpin + 'static)`
= note: required because of the requirements on the impl of `Send` for `Unique<(dyn Future<Output = ()> + Unpin + 'static)>`
= note: required because it appears within the type `Box<(dyn Future<Output = ()> + Unpin + 'static)>`
= note: required because it appears within the type `Pin<Box<(dyn Future<Output = ()> + Unpin + 'static)>>`
= note: required because it appears within the type `saphir::server::ServerShutdown`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25, 't26, 't27, 't28, 't29, 't30, 't31, 't32, 't33, 't34, 't35, 't36, 't37, 't38, 't39, 't40, 't41, 't42, 't43, 't44, 't45, 't46, 't47, 't48, 't49, 't50, 't51, 't52, 't53, 't54, 't55, 't56, 't57, 't58> {ResumeTy, saphir::server::Server, ListenerConfig, saphir::server::Stack, HeaderValue, Option<usize>, &'r saphir::server::Stack, saphir::hyper::server::conn::Http, &'s String, String, impl Future, (), tokio::net::tcp::listener::TcpListener, SocketAddr, tokio::net::tcp::incoming::Incoming<'t0>, saphir::server::ServerShutdown, Arc<saphir::server::SeverShutdownState>, Option<u64>, u64, futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t1>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#1}]>, saphir::server::ServerFuture<futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t17>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#1}]>, saphir::server::ServerShutdown>, futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t33>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#2}]>, saphir::server::ServerFuture<futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t46>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#2}]>, saphir::server::ServerShutdown>}`
= note: required because it appears within the type `[static generator@saphir::server::Server::run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25, 't26, 't27, 't28, 't29, 't30, 't31, 't32, 't33, 't34, 't35, 't36, 't37, 't38, 't39, 't40, 't41, 't42, 't43, 't44, 't45, 't46, 't47, 't48, 't49, 't50, 't51, 't52, 't53, 't54, 't55, 't56, 't57, 't58> {ResumeTy, saphir::server::Server, ListenerConfig, saphir::server::Stack, HeaderValue, Option<usize>, &'r saphir::server::Stack, saphir::hyper::server::conn::Http, &'s String, String, impl Future, (), tokio::net::tcp::listener::TcpListener, SocketAddr, tokio::net::tcp::incoming::Incoming<'t0>, saphir::server::ServerShutdown, Arc<saphir::server::SeverShutdownState>, Option<u64>, u64, futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t1>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#1}]>, saphir::server::ServerFuture<futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t17>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#1}]>, saphir::server::ServerShutdown>, futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t33>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#2}]>, saphir::server::ServerFuture<futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t46>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#2}]>, saphir::server::ServerShutdown>}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@saphir::server::Server::run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25, 't26, 't27, 't28, 't29, 't30, 't31, 't32, 't33, 't34, 't35, 't36, 't37, 't38, 't39, 't40, 't41, 't42, 't43, 't44, 't45, 't46, 't47, 't48, 't49, 't50, 't51, 't52, 't53, 't54, 't55, 't56, 't57, 't58> {ResumeTy, saphir::server::Server, ListenerConfig, saphir::server::Stack, HeaderValue, Option<usize>, &'r saphir::server::Stack, saphir::hyper::server::conn::Http, &'s String, String, impl Future, (), tokio::net::tcp::listener::TcpListener, SocketAddr, tokio::net::tcp::incoming::Incoming<'t0>, saphir::server::ServerShutdown, Arc<saphir::server::SeverShutdownState>, Option<u64>, u64, futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t1>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#1}]>, saphir::server::ServerFuture<futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t17>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#1}]>, saphir::server::ServerShutdown>, futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t33>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#2}]>, saphir::server::ServerFuture<futures_util::stream::stream::for_each_concurrent::ForEachConcurrent<tokio::net::tcp::incoming::Incoming<'t46>, impl Future, [closure@saphir::server::Server::run::{closure#0}::{closure#2}]>, saphir::server::ServerShutdown>}]>`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
error: aborting due to previous error; 1 warning emitted
However, on version 2.7.7 of saphir everything works as expected.
Expected behavior
The provided snippet can be run with saphir 2.8.0 the same way it works with saphir 2.7.7
Additional info (please complete the following information):
Add prefix and suffix literal to match if some path segment start or end with something
(e.g. /my/path/*.htm
)
Add possibility to match any route like /page/<path..>/view
. This would match any route that begins with /page and ends with /view, the in between path will be saved in the path
capture
Description
If you use the FileMiddleware with a cache, there is an issue if you receive a HEAD request on a file before any GET request. The problem is that we save in cache an empty file since we don't read it so we save an empty file in cache. All GET request receive after don't return the file as expected.
(Of course, the file has to be cached. Depending of the cache configuration, it could work or not. But for sure, you can get cases that don't work)
Expected behavior
GET request on a file should return the file, even if we have receive a HEAD request before.
Additional info (please complete the following information):
When the anonymous object contains a Vec of a primitive type, the openapi generated file doesn't contain the anonymous object.
I found two edge-cases where the query string parameters are not working in a macro handler in version 3.0.0:
#[get("/queries")]
async fn multiple_queries(&self, queries: Option<usize>) -> Result<Json<Vec<World>>, BenchmarkControllerError> {
// GET /queries?queries=20
println!("{:?}", queries); // None
}
#[get("/queries")]
async fn multiple_queries(&self, q: Option<usize>) -> Result<Json<Vec<World>>, BenchmarkControllerError> {
// GET /queries?q=20
println!("{:?}", q); // None
}
Other schemes works properly:
#[get("/queries")]
async fn multiple_queries(&self, nb: Option<usize>) -> Result<Json<Vec<World>>, BenchmarkControllerError> {
// GET /queries?nb=20
println!("{:?}", q); // Some(20)
}
Description
If I build with the feature file
without multipart, there ir an error.
Hello, @richerarc
I would like to know, if I can upgrade the Http request to websocket?
Also, I would like to know if the framework could work with pool of threads to handle those connections ?
And, Iโm new in rust, so if there is any example how to handle the questions above, I would appreciated
Thanks you so much
Description
A clear and concise description of what the bug is.
saphir v2.6.7
error[E0277]: the trait bound hyper::body::body::Body: std::convert::From<std::boxed::Box<dyn futures_core::stream::Stream<Item = std::result::Result<bytes::bytes::Bytes, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>> + std::marker::Send + std::marker::Sync>>
is not satisfied
--> /home/guoyibin3/.cargo/registry/src/github.com-1ecc6299db9ec823/saphir-2.6.7/src/response.rs:374:18
|
374 | self.body(Box::new(file.into())
| ^^^^ the trait std::convert::From<std::boxed::Box<dyn futures_core::stream::Stream<Item = std::result::Result<bytes::bytes::Bytes, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>> + std::marker::Send + std::marker::Sync>>
is not implemented for hyper::body::body::Body
|
= help: the following implementations were found:
<hyper::body::body::Body as std::convert::From<&'static [u8]>>
<hyper::body::body::Body as std::convert::From<&'static str>>
<hyper::body::body::Body as std::convert::Frombytes::bytes::Bytes>
<hyper::body::body::Body as std::convert::From<std::borrow::Cow<'static, [u8]>>>
and 4 others
= note: required because of the requirements on the impl of std::convert::Into<hyper::body::body::Body>
for std::boxed::Box<dyn futures_core::stream::Stream<Item = std::result::Result<bytes::bytes::Bytes, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>> + std::marker::Send + std::marker::Sync>
error: aborting due to previous error
For more information about this error, try rustc --explain E0277
.
error: could not compile saphir
.
Expected behavior
A clear and concise description of what you expected to happen.
Additional info (please complete the following information):
Add a notion of dependency injection inside the server
Description of the feature
The documentation on docs.rs does not include any related features restricted function.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.