proxy: Refactor router implementation (#894)

The Router's primary `call` implementation is somewhat difficult to
follow.

This change does not introduce any functional changes, but makes the
function easier to reason about.

This is being done in preparation for functional changes.
This commit is contained in:
Oliver Gould 2018-05-02 15:47:36 -07:00 committed by GitHub
parent 7f16079f64
commit 3310968647
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 25 additions and 58 deletions

View File

@ -121,69 +121,36 @@ where T: Recognize,
} }
fn call(&mut self, request: Self::Request) -> Self::Future { fn call(&mut self, request: Self::Request) -> Self::Future {
let mut inner = self.inner.lock().unwrap(); let inner = &mut *self.inner.lock().expect("lock router cache");
let inner = &mut *inner;
// This insanity is to make the borrow checker happy... let key = match inner.recognize.recognize(&request) {
Some(k) => k,
None => {
return ResponseFuture { state: State::NotRecognized };
}
};
// These vars will be used to insert a new service in the cache.
let new_key;
let mut new_service;
// This loop is used to create a borrow checker scope as well as being
// able to call `break` to jump out of it.
loop {
let service;
if let Some(key) = inner.recognize.recognize(&request) {
// Is the bound service for that key reusable? If `recognize` // Is the bound service for that key reusable? If `recognize`
// returned `SingleUse`, that indicates that the service may // returned `SingleUse`, that indicates that the service may
// not be used to serve multiple requests. // not be used to serve multiple requests.
let cached = if let Reuse::Reusable(ref key) = key { if let Reuse::Reusable(ref k) = key {
// The key is reusable --- look in the cache. if let Some(service) = inner.routes.get_mut(k) {
inner.routes.get_mut(key)
} else {
None
};
if let Some(s) = cached {
// The service for the authority is already cached.
service = s;
} else {
// The authority does not match an existing route, try to
// recognize it.
match inner.recognize.bind_service(key.as_ref()) {
Ok(s) => {
// A new service has been matched. Set the outer
// variables and jump out o the loop.
new_key = key.clone();
new_service = s;
break;
}
Err(e) => {
// Route recognition failed.
return ResponseFuture { state: State::RouteError(e) };
}
}
}
} else {
// The request has no authority.
return ResponseFuture { state: State::NotRecognized };
}
// Route to the cached service.
let response = service.call(request); let response = service.call(request);
return ResponseFuture { state: State::Inner(response) }; return ResponseFuture { state: State::Inner(response) };
} }
};
// First, route the request to the new service. let mut service = match inner.recognize.bind_service(key.as_ref()) {
let response = new_service.call(request); Ok(s) => s,
Err(e) => {
// Now, cache the new service. return ResponseFuture { state: State::RouteError(e) };
if let Reuse::Reusable(new_key) = new_key {
inner.routes.insert(new_key, new_service);
} }
};
// And finally, return the response. let response = service.call(request);
if let Reuse::Reusable(k) = key {
inner.routes.insert(k, service);
}
ResponseFuture { state: State::Inner(response) } ResponseFuture { state: State::Inner(response) }
} }
} }