-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
I've put this off for a while claiming that it will be solved in tokio-proto, but I'm now leaning towards may as well fix it in hyper, if a generic way appears in the future, no harm done. So, on to the proposal:
I hinted at a possible solution earlier in another issue, and I think a solution is probably similar: Add a way to combine an Http, Service, TcpListener, and Handle into a impl Future.
Proposed API
Httppub fn bind_handle<S>(&self, addr: &SocketAddr, new_service: S, handle: &Handle) -> Server
Serverpub fn shutdown_signal<F>(&mut self, signal: F) -> &mut Selfimpl Future for Server
Usage
// Spawn 2 servers on the same Core
let mut core = Core::new()?;
let handle = core.handle();
let srv1 = Http::new()
.bind_handle(addr1, new_service1, &handle);
let srv2 = Http::new()
.bind_handle(addr2, new_service2, &handle);
handle.spawn(srv1);
handle.spawn(srv2);
core.run(futures::future::empty())?;// Spawn a Server with a Client
let mut core = Core::new()?;
let handle = core.handle();
let client = Client::new(&handle);
let server = Http::new()
.bind_handle(addr, new_service(client), &handle);
handle.spawn(server);
core.run(futures::future::empty())?;// Spawn a Server and still get graceful shutdown
let mut core = Core::new()?;
let handle = core.handle();
// send on tx to shutdown server future
let (tx, rx) = oneshot::channel();
let client = Client::new(&handle);
let mut server = Http::new()
.bind_handle(addr, new_service(client), &handle);
server.shutdown_signal(rx);
// can even just run server directly
core.run(server)?;Implementation
This proposal is reusing the Server type, which already exists in a form that owns a Core. Internally, it can just change its field to an enum of 2 variants, 1 with a Core, and the other with a Handle. It should be able to use the majority of the same code in both cases.
It might be tricky that you can create a Server using Http::bind, which owns a Core, and then you can send that Server into another Core, calling handle.spawn(server). If you were to do that, the impl Future for Server could make the outer Core lock up, since an implementation might decide to call core.run() on its inner Core.
To prevent that mistake, the impl Future for Server should probably panic if the Server owns a Core, and not a Handle, with a nice message explaining don't do that.