Need help on using Service/NewService in Hyper 0.12.5


#1

I did similar with hyper 0.11, but don’t know how to get it works with hyper 0.12:

extern crate hyper;
extern crate futures;

use hyper::service::{NewService, Service};
use hyper::{Body,Error,Response,StatusCode,Request,Server};
use futures::{future, Future};

struct TestServer {
    something: u64,
}

impl NewService for TestServer {
    type ReqBody = Body;
    type ResBody = Body;
    type Error = Error;
    type InitError = Error;
    type Service = TestServer;
    type Future = Box<Future<Item = Self::Service, Error = Self::InitError> + Send>;
    fn new_service(&self) -> Self::Future {
        Box::new(future::ok(Self {
            something: self.something,
        }))
    }
}

impl Service for TestServer {
    type ReqBody = Body;
    type ResBody = Body;
    type Error = Error;
    type Future = Box<Future<Item = Response<Body>, Error = Error> + Send>;
    fn call(&mut self, _req: Request<Self::ReqBody>) -> Self::Future {
        let something = self.something.to_string();
        Box::new(future::ok(
            Response::builder()
                .status(StatusCode::OK)
                .body(something.into())
                .unwrap()
        ))
    }
}

impl TestServer {
    fn start(self, port: u16) {
        let addr = format!("0.0.0.0:{}", port).parse().unwrap();
        let server = Server::bind(&addr).serve(self);
        println!("Serving at {}", addr);

        hyper::rt::run(server); //<=========================== Error here!
    }
}

fn main() {
    let test = TestServer{something:42};
    test.start(8888);
}

Error:

error[E0271]: type mismatch resolving `<hyper::Server<hyper::server::conn::AddrIncoming, TestServer> as futures::Future>::Error == ()`
  --> src/main.rs:47:9
   |
47 |         hyper::rt::run(server);
   |         ^^^^^^^^^^^^^^ expected struct `hyper::Error`, found ()
   |
   = note: expected type `hyper::Error`
              found type `()`
   = note: required by `hyper::rt::run`

I also try to do similar to this, but it failed too:

        let mut runtime = tokio::runtime::Runtime::new()?;
        runtime.spawn(server);

Does this piece of code have any chance to compile and run with hyper 0.12?


#2

You need to handle the Error part of the future returned in serve(self). For example:

let server = Server::bind(&addr)
            .serve(self)
            .map_err(|e| eprintln!("error: {}", e));

This just prints it to stderr, but you may want to plug something else in (e.g. logging). The gist is the future you give to hyper::rt::run must not return anything (i.e. Item = ()) and not error (i.e. Error = ()). If the future you’re working with returns something else in those types, then you need to map them away to ().


#3

Thank you very much! The sample code works. But it took a half of my day to get my real code to work.

For anyone who hit the same problem as me: Make sure that both Future of NewService and Service trait have Send in them:

type Future = Box<Future<Item = Self::Service, Error = Self::InitError> + Send>; // Need Send
type Future = Box<Future<Item = Response<Body>, Error = Error> + Send>;     // Need Send

The problem is that the compiler complains about futures::Future is not satisfied for hyper::Server, which is incorrect. This make me lost my day!


#4

Yeah, I sympathize. The compiler is correct though - Server implements Future only when all of the where clause bounds are satisfied; in complex bounds, this can be non-obvious, particularly if not familiar with this.

Perhaps the compiler can generate a better error message, indicating which part(s) weren’t satisfied.