tide icon indicating copy to clipboard operation
tide copied to clipboard

Proposal: Refactor Middleware Execution / Next with Cursors and Async Recursion

Open nyxtom opened this issue 3 years ago • 1 comments

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
        }
    }

nyxtom avatar Jul 16 '22 02:07 nyxtom

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

nyxtom avatar Jul 16 '22 05:07 nyxtom