mirror of
https://github.com/lune-org/lune.git
synced 2025-05-04 10:43:57 +01:00
Initial working request function in net
This commit is contained in:
parent
f9fc1c6de1
commit
07744d0079
8 changed files with 169 additions and 8 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
@ -1336,6 +1336,19 @@ dependencies = [
|
|||
"http 1.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.1"
|
||||
|
@ -1379,9 +1392,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1839,6 +1860,7 @@ dependencies = [
|
|||
"bstr",
|
||||
"futures-lite",
|
||||
"futures-rustls",
|
||||
"http-body-util",
|
||||
"hyper 1.6.0",
|
||||
"lune-std-serde",
|
||||
"lune-utils",
|
||||
|
|
|
@ -24,7 +24,8 @@ blocking = "1.6"
|
|||
bstr = "1.9"
|
||||
futures-lite = "2.6"
|
||||
futures-rustls = "0.26"
|
||||
hyper = "1.6"
|
||||
http-body-util = "0.1"
|
||||
hyper = { version = "1.6", features = ["http1", "client", "server"] }
|
||||
pin-project-lite = "0.2"
|
||||
rustls = "0.23"
|
||||
rustls-pki-types = "1.11"
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
mod hyper;
|
||||
mod request;
|
||||
mod stream;
|
||||
|
||||
pub use self::request::{Request, Response};
|
||||
|
|
115
crates/lune-std-net/src/client/request.rs
Normal file
115
crates/lune-std-net/src/client/request.rs
Normal file
|
@ -0,0 +1,115 @@
|
|||
use bstr::BString;
|
||||
use futures_lite::prelude::*;
|
||||
use http_body_util::{BodyStream, Full};
|
||||
use hyper::{
|
||||
body::{Bytes, Incoming},
|
||||
client::conn::http1::handshake,
|
||||
Method, Request as HyperRequest, Response as HyperResponse,
|
||||
};
|
||||
|
||||
use mlua::prelude::*;
|
||||
|
||||
use crate::{
|
||||
client::stream::HttpRequestStream,
|
||||
shared::hyper::{HyperExecutor, HyperIo},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Request {
|
||||
inner: HyperRequest<Full<Bytes>>,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
pub async fn send(self, lua: Lua) -> LuaResult<Response> {
|
||||
let stream = HttpRequestStream::connect(self.inner.uri()).await?;
|
||||
|
||||
let (mut sender, conn) = handshake(HyperIo::from(stream))
|
||||
.await
|
||||
.map_err(LuaError::external)?;
|
||||
|
||||
HyperExecutor::execute(lua, conn);
|
||||
|
||||
let incoming = sender
|
||||
.send_request(self.inner)
|
||||
.await
|
||||
.map_err(LuaError::external)?;
|
||||
|
||||
Response::from_incoming(incoming).await
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for Request {
|
||||
fn from_lua(value: LuaValue, _lua: &Lua) -> LuaResult<Self> {
|
||||
if let LuaValue::String(s) = value {
|
||||
// We got a string, assume it's a URL + GET method
|
||||
let uri = s.to_str()?;
|
||||
Ok(Self {
|
||||
inner: HyperRequest::builder()
|
||||
.uri(uri.as_ref())
|
||||
.body(Full::new(Bytes::new()))
|
||||
.into_lua_err()?,
|
||||
})
|
||||
} else if let LuaValue::Table(t) = value {
|
||||
// URL is always required with table options
|
||||
let url = t.get::<String>("url")?;
|
||||
let builder = HyperRequest::builder().uri(url);
|
||||
|
||||
// Add method, if provided
|
||||
let builder = match t.get::<Option<String>>("method") {
|
||||
Ok(Some(method)) => builder.method(method.as_str()),
|
||||
Ok(None) => builder.method(Method::GET),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
// Add body, if provided
|
||||
let builder = match t.get::<Option<BString>>("body") {
|
||||
Ok(Some(body)) => builder.body(Full::new(body.to_vec().into())),
|
||||
Ok(None) => builder.body(Full::new(Bytes::new())),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
inner: builder.into_lua_err()?,
|
||||
})
|
||||
} else {
|
||||
Err(LuaError::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: String::from("HttpRequest"),
|
||||
message: Some(String::from("HttpRequest must be a string or table")),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Response {
|
||||
inner: HyperResponse<Full<Bytes>>,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
pub async fn from_incoming(incoming: HyperResponse<Incoming>) -> LuaResult<Self> {
|
||||
let (parts, body) = incoming.into_parts();
|
||||
|
||||
let body = BodyStream::new(body)
|
||||
.try_fold(Vec::<u8>::new(), |mut body, chunk| {
|
||||
if let Some(chunk) = chunk.data_ref() {
|
||||
body.extend_from_slice(chunk);
|
||||
}
|
||||
Ok(body)
|
||||
})
|
||||
.await
|
||||
.into_lua_err()?;
|
||||
|
||||
let bytes = Full::new(Bytes::from(body));
|
||||
let inner = HyperResponse::from_parts(parts, bytes);
|
||||
|
||||
Ok(Self { inner })
|
||||
}
|
||||
}
|
||||
|
||||
impl LuaUserData for Response {
|
||||
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("ok", |_, this| Ok(this.inner.status().is_success()));
|
||||
fields.add_field_method_get("status", |_, this| Ok(this.inner.status().as_u16()));
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ pub enum HttpRequestStream {
|
|||
}
|
||||
|
||||
impl HttpRequestStream {
|
||||
pub async fn connect(url: Uri) -> Result<Self, io::Error> {
|
||||
pub async fn connect(url: &Uri) -> Result<Self, io::Error> {
|
||||
let Some(host) = url.host() else {
|
||||
return Err(make_err("unknown or missing host"));
|
||||
};
|
||||
|
|
|
@ -8,6 +8,10 @@ mod client;
|
|||
mod server;
|
||||
mod url;
|
||||
|
||||
use self::client::{Request, Response};
|
||||
|
||||
pub(crate) mod shared;
|
||||
|
||||
const TYPEDEFS: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/types.d.luau"));
|
||||
|
||||
/**
|
||||
|
@ -27,10 +31,14 @@ pub fn typedefs() -> String {
|
|||
*/
|
||||
pub fn module(lua: Lua) -> LuaResult<LuaTable> {
|
||||
TableBuilder::new(lua)?
|
||||
// .with_async_function("request", net_request)?
|
||||
.with_async_function("request", net_request)?
|
||||
// .with_async_function("socket", net_socket)?
|
||||
// .with_async_function("serve", net_serve)?
|
||||
// .with_function("urlEncode", net_url_encode)?
|
||||
// .with_function("urlDecode", net_url_decode)?
|
||||
.build_readonly()
|
||||
}
|
||||
|
||||
async fn net_request(lua: Lua, req: Request) -> LuaResult<Response> {
|
||||
req.send(lua).await
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::{
|
|||
|
||||
use async_io::Timer;
|
||||
use futures_lite::prelude::*;
|
||||
use hyper::rt::{self, ReadBufCursor};
|
||||
use hyper::rt::{self, Executor, ReadBufCursor};
|
||||
use mlua::prelude::*;
|
||||
use mlua_luau_scheduler::LuaSpawnExt;
|
||||
|
||||
|
@ -20,9 +20,21 @@ pub struct HyperExecutor {
|
|||
lua: Lua,
|
||||
}
|
||||
|
||||
impl From<Lua> for HyperExecutor {
|
||||
fn from(lua: Lua) -> Self {
|
||||
Self { lua }
|
||||
#[allow(dead_code)]
|
||||
impl HyperExecutor {
|
||||
pub fn execute<Fut>(lua: Lua, fut: Fut)
|
||||
where
|
||||
Fut: Future + Send + 'static,
|
||||
Fut::Output: Send + 'static,
|
||||
{
|
||||
let exec = if let Some(exec) = lua.app_data_ref::<Self>() {
|
||||
exec
|
||||
} else {
|
||||
lua.set_app_data(Self { lua: lua.clone() });
|
||||
lua.app_data_ref::<Self>().unwrap()
|
||||
};
|
||||
|
||||
exec.execute(fut);
|
||||
}
|
||||
}
|
||||
|
1
crates/lune-std-net/src/shared/mod.rs
Normal file
1
crates/lune-std-net/src/shared/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod hyper;
|
Loading…
Add table
Reference in a new issue