1extern crate alloc;
2
3use alloc::{vec::Vec, string::String};
4
5use super::error::{Result, MochiError, PtrCastError};
6use super::core::PtrRef;
7use super::html::Node;
8use super::json::{parse, JsonValue};
9
10type ReqRef = i32;
11
12#[link(wasm_import_module = "http")]
13extern "C" {
15 #[link_name = "create"]
16 fn request_create(method: RequestMethod) -> ReqRef;
17 #[link_name = "send"]
18 fn request_send(ptr: ReqRef);
19 #[link_name = "close"]
20 fn request_close(ptr: ReqRef);
21
22 #[link_name = "set_url"]
23 fn request_set_url(ptr: ReqRef, url_ptr: i32, url_len: i32);
24 #[link_name = "set_header"]
25 fn request_set_header(ptr: ReqRef, key_ptr: i32, key_len: i32, value_ptr: i32, value_len: i32);
26 #[link_name = "set_body"]
27 fn request_set_body(ptr: ReqRef, data_ptr: i32, data_len: i32);
28 #[link_name = "set_method"]
29 fn request_set_method(ptr: ReqRef, method: RequestMethod);
30
31 #[link_name = "get_method"]
32 fn request_get_method(ptr: ReqRef) -> RequestMethod;
33 #[link_name = "get_url"]
34 fn request_get_url(ptr: ReqRef) -> i32;
35 #[link_name = "get_header"]
36 fn request_get_header(ptr: ReqRef, key_ptr: i32, key_len: i32) -> i32;
37 #[link_name = "get_status_code"]
38 fn request_get_status_code(ptr: ReqRef) -> i32;
39 #[link_name = "get_data_len"]
40 fn request_get_data_len(ptr: ReqRef) -> i32;
41 #[link_name = "get_data"]
42 fn request_get_data(ptr: ReqRef, arr_ptr: i32, len: i32);
43}
44
45#[repr(C)]
46#[derive(Debug)]
47pub enum RequestMethod {
48 Get,
49 Post,
50 Put,
51 Patch,
52 Delete
53}
54
55#[derive(Debug)]
56pub struct Request {
57 ptr: i32,
58}
59
60impl Request {
62 pub fn new(url: &str, method: RequestMethod) -> Self {
63 unsafe {
64 let ptr: i32 = request_create(method);
65 request_set_url(
66 ptr,
67 url.as_ptr() as i32,
68 url.len() as i32
69 );
70 Self { ptr }
71 }
72 }
73
74 #[inline]
75 pub fn send(&self) {
76 unsafe { request_send(self.ptr); }
77 }
78
79 #[inline]
80 fn close(&self) {
81 unsafe { request_close(self.ptr); }
82 }
83
84 pub fn set_url<T: AsRef<str>>(self, url: T) -> Self {
85 let url = url.as_ref();
86 unsafe {
87 request_set_url(
88 self.ptr,
89 url.as_ptr() as i32,
90 url.len() as i32
91 );
92 };
93 self
94 }
95
96 pub fn header<T: AsRef<str>>(self, key: T, value: T) -> Self {
97 let key = key.as_ref();
98 let value = value.as_ref();
99 unsafe {
100 request_set_header(
101 self.ptr as i32,
102 key.as_ptr() as i32,
103 key.len() as i32,
104 value.as_ptr() as i32,
105 value.len() as i32
106 )
107 };
108 self
109 }
110
111 pub fn body<T: AsRef<[u8]>>(self, data: T) -> Self {
112 let data = data.as_ref();
113 unsafe {
114 request_set_body(
115 self.ptr,
116 data.as_ptr() as i32,
117 data.len() as i32
118 )
119 };
120 self
121 }
122
123 pub fn set_method(self, method: RequestMethod) -> Self {
124 unsafe {
125 request_set_method(self.ptr, method)
126 }
127 self
128 }
129
130 #[inline]
131 pub fn status_code(&self) -> i32 {
132 unsafe {
133 request_get_status_code(self.ptr)
134 }
135 }
136
137 pub fn get_method(&self) -> RequestMethod {
138 unsafe {
139 request_get_method(self.ptr)
140 }
141 }
142
143 pub fn get_header<T: AsRef<str>>(&self, key: T) -> Result<String> {
144 let key = key.as_ref();
145 let value_ptr = unsafe {
146 request_get_header(
147 self.ptr,
148 key.as_ptr() as i32,
149 key.len() as i32
150 )
151 };
152 PtrRef::new(value_ptr).as_string()
153 }
154
155 pub fn url(&self) -> String {
156 let str_ptr = unsafe {
157 request_get_url(self.ptr)
158 };
159 PtrRef::new(str_ptr).as_string().unwrap_or_default()
160 }
161
162 pub fn data(self) -> Vec<u8> {
163 self.send();
164 let size = unsafe { request_get_data_len(self.ptr) };
165 let mut buf = Vec::with_capacity(size as usize);
166 unsafe {
167 request_get_data(self.ptr, buf.as_mut_ptr() as i32, size);
168 buf.set_len(size as usize);
169 }
170 self.close();
171 buf
172 }
173
174 pub fn string(self) -> Result<String> {
175 match String::from_utf8(self.data()) {
176 Ok(v) => Ok(v),
177 Err(_) => Err(MochiError::from(PtrCastError::Utf8NotValid)),
178 }
179 }
180
181 pub fn json(self) -> Result<JsonValue> {
182 parse(self.data())
183 }
184
185 pub fn html(self) -> Result<Node> {
186 let url = self.url();
187 let data = self.data();
188
189 if url.is_empty() {
190 Node::new(data)
191 } else {
192 Node::new_with_uri(data, url)
193 }
194 }
195}
196
197impl Drop for Request {
198 fn drop(&mut self) {
199 self.close();
200 }
201}