Skip to content
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

Tokio server/client example? #109

Open
bspeice opened this issue May 10, 2020 · 2 comments
Open

Tokio server/client example? #109

bspeice opened this issue May 10, 2020 · 2 comments

Comments

@bspeice
Copy link

bspeice commented May 10, 2020

Question up front: is it possible to use this crate with tokio?

I'm interested in building a library for using the Spotify API; the existing rspotify seems to be tied to tokio through its dependence on reqwest. I'd like this library to be executor-independent, and looking through some recent discussions led me to this crate in particular.

I was initially a bit disappointed to see that there was no client_tokio example or something similar given that it's been claimed that async-h1 doesn't care about the server it's running with. After trying to make such an example myself, I seemed to run into a bigger issue: because tokio's TcpStream doesn't implement futures::io::AsyncRead (it implements tokio::io::AsyncRead instead), I think the orphan rule prevents async-h1 from working with tokio.

Am I crazy, or is it currently impossible to use this crate with tokio?


EDIT: After further research, it appears like this can be accomplished using a compatibility wrapper, there's an example here: https://github.com/Nemo157/futures-tokio-compat/blob/master/src/lib.rs (which seems to have an additional benefit of not allocating the Pin, meaning this should be zero-cost?). I'm planning to keep working on it, if I finish up an example, is that something this project is interested in having added to the examples?

@rylev
Copy link
Collaborator

rylev commented May 15, 2020

@bspeice Thanks for writing! Yes, this should be possible. An example would be super helpful. And if you run into any bugs let us know ❤️🦀

@bspeice
Copy link
Author

bspeice commented May 23, 2020

Apologies that it's taken me so long. Haven't opened a PR yet, because I would appreciate some guidance.

Here's what I have so far:

Client

use http_types::{Error, Method, Request, Url};
use async_h1::client;
use tokio::net::TcpStream as TokioStream;
use tokio_util::compat::Tokio02AsyncReadCompatExt;

#[tokio::main]
async fn main() -> Result<(), Error> {

    // Note that unlike the async-std version, we create a new TcpStream each time.
    for i in 0usize..2 {
        let stream = TokioStream::connect("127.0.0.1:8080").await?;
        let peer_addr = stream.peer_addr()?;
        let stream = stream.compat();
        println!("connecting to {}", peer_addr);

        println!("making request {}/2", i + 1);
        let url = Url::parse(&format!("http://{}/foo", peer_addr)).unwrap();
        let req = Request::new(Method::Get, url);
        let res = client::connect(stream, req).await;
        println!("{:?}", res);
    }

    Ok(())
}

The issue is that async-h1 assumes the TcpStream is clonable, which is true for async-std, but not for tokio. This isn't so bad for the client, because we can just open new connections, but is problematic for the server.

I haven't been able to figure out a good way of hacking in Clone implementations; AsyncWrite isn't implemented for Arc<T>, and it feels a bit silly to build a LocalCompat<Arc<RemoteCompat<TcpStream>>> in order to give this to async-h1. As far as I can tell, the Clone is needed because server::decode needs a 'static reader, but I'm not totally sure on that one.

So I can hack together a client implementation, but the server implementation seems to have issues because Tokio's TcpStream doesn't allow cloning. Is there a "good" way to remove the Clone requirement?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants