summaryrefslogtreecommitdiff
path: root/examples/async_http_client.rs
blob: e791808259710394e50eb9f3fac55f11273a7d41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use std::collections::HashMap;

use hyper::body::{Body as HyperBody, HttpBody as _};
use hyper::Client as HyperClient;

use mlua::{chunk, AnyUserData, ExternalResult, Lua, Result, UserData, UserDataMethods};

struct BodyReader(HyperBody);

impl UserData for BodyReader {
    fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
        methods.add_async_function("read", |lua, reader: AnyUserData| async move {
            let mut reader = reader.borrow_mut::<Self>()?;
            if let Some(bytes) = reader.0.data().await {
                let bytes = bytes.to_lua_err()?;
                return Some(lua.create_string(&bytes)).transpose();
            }
            Ok(None)
        });
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let lua = Lua::new();

    let fetch_url = lua.create_async_function(|lua, uri: String| async move {
        let client = HyperClient::new();
        let uri = uri.parse().to_lua_err()?;
        let resp = client.get(uri).await.to_lua_err()?;

        let lua_resp = lua.create_table()?;
        lua_resp.set("status", resp.status().as_u16())?;

        let mut headers = HashMap::new();
        for (key, value) in resp.headers() {
            headers
                .entry(key.as_str())
                .or_insert(Vec::new())
                .push(value.to_str().to_lua_err()?);
        }

        lua_resp.set("headers", headers)?;
        lua_resp.set("body", BodyReader(resp.into_body()))?;

        Ok(lua_resp)
    })?;

    let f = lua
        .load(chunk! {
            local res = $fetch_url(...)
            print("status: "..res.status)
            for key, vals in pairs(res.headers) do
                for _, val in ipairs(vals) do
                    print(key..": "..val)
                end
            end
            repeat
                local body = res.body:read()
                if body then
                    print(body)
                end
            until not body
        })
        .into_function()?;

    f.call_async("http://httpbin.org/ip").await
}