tide
tide copied to clipboard
Proposal: Refactor Middleware Execution / Next with Cursors and Async Recursion
I recently came across the salvo implementation for middleware (control flow) and I really like the use of the async_recursion combined with a simple cursor to allow middleware to run without any additional lifetimes. I think we could probably clean up the middleware to do something similar possibly.
/// Call next handler. If get next handler and executed, returns true, otherwise returns false.
///
/// If resposne's statuse code is error or is redirection, all reset handlers will skipped.
#[inline]
#[async_recursion]
pub async fn call_next(&mut self, req: &mut Request, depot: &mut Depot, res: &mut Response) -> bool {
if let Some(code) = res.status_code() {
if code.is_client_error() || code.is_server_error() || code.is_redirection() {
self.skip_rest();
return false;
}
}
if let Some(handler) = self.handlers.get(self.cursor) {
self.cursor += 1;
handler.clone().handle(req, depot, res, self).await;
if self.has_next() {
self.call_next(req, depot, res).await;
}
true
} else {
false
}
}
My current implementation https://github.com/http-rs/tide/pull/895 solves this issue by eliminating the need for both <State> on the Request as well as removing the for<'a> requirements on middleware. This allows us to use just Next and Request. I've implemented a simple cursor step process and the use of Arcs to solve this issue. This also solves the issue of having closures https://github.com/http-rs/tide/issues/854