-
Notifications
You must be signed in to change notification settings - Fork 321
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Introduce the notion of a middleware stack #73
Comments
I'd like to take this to start contributing to tide. Seems pretty simple: impl<Data> Iterator<Item=&Middleware<Data>> for MiddlewareStack<Data> {
// ...
}
impl<Data> FromIterator<Item=dyn Middleware<Data> + Send + Sync> for MiddlewareStack<Data> {
// ...
}
impl<Data> Middleware<Data> for MiddlewareStack<Data> {
fn handle(/* ... */) -> FutureObj<'a, Response> {
// Apply internal middlewares in order..
}
} Anything I'm missing? |
@RoGryza seems like a good starting point! Feel free to make a PR, and then we can build on that over time (with introspection etc) |
Sorry for the delay, I hacked something together that works but I've introduced some allocations that could be eliminated and never got time to work on it again. I'll submit a PR once I get home from work in order to ask for help |
This is worth revisiting now that #156 has landed -- anybody want to take it back up? |
I can take a look if no one else is already working on it. |
I am taking a look at this and came up with the following pub struct MiddlewareStack<State> {
middlewares: Vec<Arc<dyn Middleware<State> + Send + Sync>>,
}
impl<State> MiddlewareStack<State> {
pub fn new() -> MiddlewareStack<State> {
MiddlewareStack {
middlewares: Vec::new(),
}
}
pub fn push(&mut self, m: impl Middleware<State>) {
self.middlewares.push(Arc::new(m));
}
}
impl<State: 'static> Middleware<State> for MiddlewareStack<State> {
fn handle<'a>(&'a self, cx: Context<State>, next: Next<'a, State>) -> BoxFuture<'a, Response> {
if let Some((head, tail)) = self.middlewares.split_first() {
let next = Next {
endpoint: next.endpoint,
next_middleware: tail, // todo: append middlewares from next
};
head.handle(cx, next)
} else {
next.run(cx)
}
}
} But I got in trouble with the incompatible types of MiddlewareStack.middlewares and Next.next_middlewares |
I don't know of any bounds that |
Thanks @skade, I cleaned up my previous attempt. /// Middleware stack.
pub struct MiddlewareStack<State> {
stack: Vec<Arc<dyn Middleware<State>>>,
}
impl<State> MiddlewareStack<State> {
/// Create an empty stack of middlewares.
pub fn new() -> MiddlewareStack<State> {
MiddlewareStack {
stack: Vec::new(),
}
}
/// Add a middleware to the stack.
pub fn push(&mut self, m: impl Middleware<State>) {
self.stack.push(Arc::new(m));
}
}
impl<State: 'static> Middleware<State> for MiddlewareStack<State> {
fn handle<'a>(&'a self, cx: Context<State>, next: Next<'a, State>) -> BoxFuture<'a, Response> {
if let Some((last, others)) = self.stack.split_last() {
last.handle(cx, Next::new(next.endpoint, others))
} else {
next.run(cx)
}
}
} I am not sure if the middleware stack should behave like a stack as the name suggests or like a queue (respectively split_last and split_first). Maybe I can start a pull request and collect some comments/reviews? edit: I just noted a problem. |
As i see it we have three options how to approach this:
I Tried But after second thought i think that |
I have been learning the tide code base for a while, and have decided to work on this issue. Currently I have something working where I added a field called I also wrote some tests, and so far it seems to be working fine, and I would welcome some feedback as to whether I'm on the right track. |
Currently, the type of a collection of middlewares is
Vec<Arc<dyn Middleware<Data> + Send + Sync>>
. I think it would make sense to introduce a properMiddlewareStack
type that itself implementsMiddleware
. This allows better sharing of middleware instances and the way to address them, for example for debugging.The text was updated successfully, but these errors were encountered: