mochi_rs/imports/
http.rs

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")]
13// #[link(name = "swift-bindings", kind = "static")]
14extern "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
60// By default, the method it uses is `GET`
61impl 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}