http_req icon indicating copy to clipboard operation
http_req copied to clipboard

async support

Open JayceFayne opened this issue 6 years ago • 5 comments

Are there any plans on adding async support? Let me know if a pull request in that direction would be welcome.

JayceFayne avatar Jan 18 '20 05:01 JayceFayne

Yes, pull request in that direction would be welcome. But please try not to overuse dependencies, because it could make the library too heavy.

jayjamesjay avatar Jan 18 '20 19:01 jayjamesjay

@jayjamesjay are you expecting something with mio more like this?

tmp-h9kdub v0.1.0 (/home/cecile/.cache/cargo-temp/tmp-h9KDuB)
├── http_req v0.8.1
│   ├── native-tls v0.2.8
│   │   ├── log v0.4.14
│   │   │   └── cfg-if v1.0.0
│   │   ├── openssl v0.10.36
│   │   │   ├── bitflags v1.3.2
│   │   │   ├── cfg-if v1.0.0
│   │   │   ├── foreign-types v0.3.2
│   │   │   │   └── foreign-types-shared v0.1.1
│   │   │   ├── libc v0.2.101
│   │   │   ├── once_cell v1.8.0
│   │   │   └── openssl-sys v0.9.66
│   │   │       └── libc v0.2.101
│   │   │       [build-dependencies]
│   │   │       ├── autocfg v1.0.1
│   │   │       ├── cc v1.0.70
│   │   │       └── pkg-config v0.3.19
│   │   ├── openssl-probe v0.1.4
│   │   └── openssl-sys v0.9.66 (*)
│   └── unicase v2.6.0
│       [build-dependencies]
│       └── version_check v0.9.3
└── mio v0.7.13
    ├── libc v0.2.101
    └── log v0.4.14 (*)

POC (this code is flawed):

use std::error::Error;

use mio::net::{TcpListener, TcpStream};
use mio::{event, Events, Interest, Poll, Token};

use http_req::{request::RequestBuilder, response::StatusCode, tls, uri::Uri};
use std::convert::TryFrom;
use std::io::{Read, Write};
use std::net::{SocketAddr, ToSocketAddrs};

// Some tokens to allow us to identify which event is for which socket.
const SERVER: Token = Token(0);
const CLIENT: Token = Token(1);

fn main() -> Result<(), Box<dyn Error>> {
    let addr: Uri = Uri::try_from("http://example.org").unwrap();
    let mut writer = Vec::new();

    // Create a poll instance.
    let mut poll = Poll::new()?;
    // Create storage for events.
    let mut events = Events::with_capacity(128);

    // Setup the client socket.
    let mut client = TcpStream::connect(
        (addr.host().unwrap(), addr.corr_port())
            .to_socket_addrs()
            .unwrap()
            .next()
            .unwrap(),
    )?;
    /*
    let mut tls = tls::Config::default()
        .connect(addr.host().unwrap_or(""), &mut client)
        .unwrap();
    */
    // Register the socket.
    poll.registry()
        .register(&mut client, CLIENT, Interest::READABLE | Interest::WRITABLE)?;

    let mut response = None;

    // Start an event loop.
    'main: loop {
        // Poll Mio for events, blocking until we get an event.
        poll.poll(&mut events, None)?;

        // Process each event.
        for event in events.iter() {
            // We can use the token we previously provided to `register` to
            // determine for which socket the event is.
            match event.token() {
                CLIENT => {
                    if event.is_writable() {
                        eprintln!("##### write");
                        match RequestBuilder::new(&addr)
                            .header("Connection", "Close")
                            .send(&mut client, &mut writer)
                        {
                            Err(err) => {
                                eprintln!("{:?}", err);
                            }
                            Ok(res) => {
                                response.replace(res);
                                let _ = std::io::stdout().write_all(&writer);
                                break 'main;
                            }
                        }

                        // We can (likely) write to the socket without blocking.
                    }

                    if event.is_readable() {
                        // We can (likely) read from the socket without blocking.
                    }

                    // Since the server just shuts down the connection, let's
                    // just exit from our event loop.
                    //return Ok(());
                }
                // We don't expect any events with tokens other than those we provided.
                _ => unreachable!(),
            }
        }
    }

    if let Some(response) = response.as_ref() {
        assert_eq!(response.status_code(), StatusCode::new(200));
    }

    Ok(())
}

Then use std::futures::Future to make this async.

cecton avatar Sep 07 '21 05:09 cecton

Yes, something like this.

jayjamesjay avatar Sep 29 '21 20:09 jayjamesjay