Hyper, tokio and templates

Hello!
I learn Rust and try to make a Google OAuth 2.0 client for practice. I use hyper library as https client and i got some questions about it types and templates.
I wrote this code but it doesn’t compile because of retrieve_url function return type.

fn retrieve_auth_url() {
    let (sender, receiver) = futures::sync::oneshot::channel::<Url>();
    hyper::rt::run(hyper::rt::lazy(move || {
        retrieve_url(sender)
    }));

    let location = receiver.wait();

    println!("Response: {:?}", location);
}

fn retrieve_url(send: Sender<Url>) -> Client<HttpsConnector<Error>> {
    let uri = Url::parse_with_params(GOOGLE_AUTH_URL, [
        ("client_id", CLIENT_ID),
        ("redirect_uri", "http://[::1]:3000"),
        ("response_type", "code"),
        ("scope", "https://www.googleapis.com/auth/drive")
    ].iter());

    let url = uri.unwrap().as_str().parse::<Uri>().unwrap();

    let https = HttpsConnector::new(1).unwrap();
    let client = Client::builder().build::<_, hyper::Body>(https);

    client.get(url)
        .map(|res| {
            Url::parse(res.headers().get("location").unwrap().to_str().unwrap()).unwrap()
        })
        .map_err(|err| {
            err
        })
}

If I embed retrieve_url body into closure - everything works. Which type should be there? And why MapErr type can be used as a parameter for lazy function? I understand it implement Future trait but it isn’t a Client! But hyper::rt::run should run Client exactly!

Thank you!

From a quick glance over the docs for hyper::rt::run, it looks like it wants a future that doesn’t return anything (a tuple).

Did you try to add a semicolon like so:

hyper::rt::run(hyper::rt::lazy(move || {
        retrieve_url(sender);
    }));

It’s not easy to verify without a self contained example that I can compile. It’s kind of common for anything in futures that is being spawned to require both item and error to be an empty tuple because you won’t be able to retrieve the result, except with remote_handle from futures-preview 0.3.

No, I think it won’t help.
I change code, now it’s work

fn retrieve_auth_url() {
    let (sender, receiver) = futures::sync::oneshot::channel::<String>();
    hyper::rt::run(retrieve_url(sender));
    let location = receiver.wait();

    println!("Response: {:?}", &location);
}

fn retrieve_url(sender: Sender<String>) -> impl Future<Item = (), Error = ()> {
    let uri = Url::parse_with_params(
        GOOGLE_AUTH_URL,
        [
            ("client_id", CLIENT_ID),
            ("redirect_uri", "http://[::1]:3000"),
            ("response_type", "code"),
            ("scope", "https://www.googleapis.com/auth/drive"),
        ]
        .iter(),
    );

    let url = uri.unwrap().as_str().parse::<Uri>().unwrap();

    let https = HttpsConnector::new(1).unwrap();
    let client = Client::builder().build::<_, hyper::Body>(https);

    client
        .get(url)
        .map(|res| {
            let url = String::from(res.headers().get("location").unwrap().to_str().unwrap());
            sender.send(url);
        })
        .map_err(|err| ())
}

There are no need to make Lazy object!

That’s a clean solution, congrats!