1use runestick::Bytes;
55use std::fmt;
56use std::fmt::Write as _;
57
58#[derive(Debug)]
59pub struct Error {
60 inner: reqwest::Error,
61}
62
63impl From<reqwest::Error> for Error {
64 fn from(inner: reqwest::Error) -> Self {
65 Self { inner }
66 }
67}
68
69#[derive(Debug)]
70struct Client {
71 client: reqwest::Client,
72}
73
74#[derive(Debug)]
75pub struct Response {
76 response: reqwest::Response,
77}
78
79#[derive(Debug)]
80pub struct StatusCode {
81 inner: reqwest::StatusCode,
82}
83
84impl StatusCode {
85 fn display(&self, buf: &mut String) -> fmt::Result {
86 write!(buf, "{}", self.inner)
87 }
88}
89
90impl Response {
91 async fn text(self) -> Result<String, Error> {
92 let text = self.response.text().await?;
93 Ok(text)
94 }
95
96 fn status(&self) -> StatusCode {
98 let inner = self.response.status();
99
100 StatusCode { inner }
101 }
102}
103
104#[derive(Debug)]
105pub struct RequestBuilder {
106 request: reqwest::RequestBuilder,
107}
108
109impl RequestBuilder {
110 async fn send(self) -> Result<Response, Error> {
112 let response = self.request.send().await?;
113 Ok(Response { response })
114 }
115
116 fn header(self, key: &str, value: &str) -> Self {
118 Self {
119 request: self.request.header(key, value),
120 }
121 }
122
123 async fn body_bytes(self, bytes: Bytes) -> Result<Self, Error> {
125 let bytes = bytes.into_vec();
126
127 Ok(Self {
128 request: self.request.body(bytes),
129 })
130 }
131}
132
133impl Client {
134 fn new() -> Self {
135 Self {
136 client: reqwest::Client::new(),
137 }
138 }
139
140 async fn get(&self, url: &str) -> Result<RequestBuilder, Error> {
142 let request = self.client.get(url);
143 Ok(RequestBuilder { request })
144 }
145
146 async fn post(&self, url: &str) -> Result<RequestBuilder, Error> {
148 let request = self.client.post(url);
149 Ok(RequestBuilder { request })
150 }
151}
152
153async fn get(url: &str) -> Result<Response, Error> {
155 Ok(Response {
156 response: reqwest::get(url).await?,
157 })
158}
159
160runestick::decl_external!(Error);
161runestick::decl_external!(Client);
162runestick::decl_external!(Response);
163runestick::decl_external!(RequestBuilder);
164runestick::decl_external!(StatusCode);
165
166pub fn module() -> Result<runestick::Module, runestick::ContextError> {
168 let mut module = runestick::Module::new(&["http"]);
169
170 module.ty(&["Client"]).build::<Client>()?;
171 module.ty(&["Response"]).build::<Response>()?;
172 module.ty(&["RequestBuilder"]).build::<RequestBuilder>()?;
173 module.ty(&["StatusCode"]).build::<StatusCode>()?;
174 module.ty(&["Error"]).build::<Error>()?;
175
176 module.function(&["Client", "new"], Client::new)?;
177 module.async_function(&["get"], get)?;
178
179 module.async_inst_fn("get", Client::get)?;
180 module.async_inst_fn("post", Client::post)?;
181
182 module.async_inst_fn("text", Response::text)?;
183 module.inst_fn("status", Response::status)?;
184
185 module.async_inst_fn("send", RequestBuilder::send)?;
186 module.inst_fn("header", RequestBuilder::header)?;
187 module.async_inst_fn("body_bytes", RequestBuilder::body_bytes)?;
188
189 module.inst_fn(runestick::STRING_DISPLAY, StatusCode::display)?;
190 Ok(module)
191}