1use std::{cell::RefCell, collections::HashMap};
2
3pub use crows_macros::config;
4pub use crows_shared::Config as ExecutorConfig;
5pub use crows_shared::ConstantArrivalRateConfig;
6use serde::{de::DeserializeOwned, Deserialize, Serialize};
7use serde_json::{from_slice, to_vec};
8
9#[derive(Serialize, Deserialize, PartialEq, Debug)]
10pub enum HTTPMethod {
11 HEAD,
12 GET,
13 POST,
14 PUT,
15 DELETE,
16 OPTIONS,
17}
18
19#[derive(Serialize, Deserialize, PartialEq, Debug)]
20pub struct HTTPRequest {
21 pub url: String,
23 pub method: HTTPMethod,
24 pub headers: HashMap<String, String>,
25 pub body: Option<String>,
26}
27
28#[derive(Debug, Deserialize, Serialize)]
29pub struct HTTPError {
30 pub message: String,
31}
32
33#[derive(Serialize, Deserialize, PartialEq, Debug)]
34pub struct HTTPResponse {
35 pub headers: HashMap<String, String>,
37 pub body: String,
38 pub status: u16,
39}
40
41fn extract_from_return_value(value: u64) -> (u8, u32, u32) {
42 let status = ((value >> 56) & 0xFF) as u8;
43 let length = ((value >> 32) & 0x00FFFFFF) as u32;
44 let ptr = (value & 0xFFFFFFFF) as u32;
45 (status, length, ptr)
46}
47
48mod bindings {
49 #[link(wasm_import_module = "crows")]
50 extern "C" {
51 pub fn log(content: *mut u8, content_len: usize);
52 pub fn http(content: *mut u8, content_len: usize) -> u64;
53 pub fn consume_buffer(index: u32, content: *mut u8, content_len: usize);
54 pub fn set_config(content: *mut u8, content_len: usize) -> u32;
55 }
56}
57
58fn with_buffer<R>(f: impl FnOnce(&mut Vec<u8>) -> R) -> R {
59 thread_local! {
61 static BUFFER: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(1024));
62 }
63
64 BUFFER.with(|r| {
65 let mut buf = r.borrow_mut();
66 buf.clear();
67 f(&mut buf)
68 })
69}
70
71pub fn http_request(
72 url: String,
73 method: HTTPMethod,
74 headers: HashMap<String, String>,
75 body: String,
76) -> Result<HTTPResponse, HTTPError> {
77 let body = Some(body);
78 let request = HTTPRequest {
79 method,
80 url,
81 headers,
82 body,
83 };
84
85 call_host_function(&request, |buf| unsafe {
86 bindings::http(buf.as_mut_ptr(), buf.len())
87 })
88}
89
90fn call_host_function<T, R, E>(arguments: &T, f: impl FnOnce(&mut Vec<u8>) -> u64) -> Result<R, E>
91where
92 T: Serialize,
93 R: DeserializeOwned,
94 E: DeserializeOwned,
95{
96 let mut encoded = to_vec(arguments).unwrap();
97
98 let response = f(&mut encoded);
99
100 let (status, length, index) = extract_from_return_value(response);
101
102 let mut buf = encoded;
103 buf.clear();
104
105 buf.reserve_exact(length as usize);
108
109 unsafe {
110 bindings::consume_buffer(index, buf.as_mut_ptr(), length as usize);
111 buf.set_len(length as usize);
112 }
113
114 if status == 0 {
115 Ok(from_slice(&buf).expect("Couldn't decode message from the host"))
116 } else {
117 Err(from_slice(&buf).expect("Couldn't decode message from the host"))
118 }
119}
120
121pub fn __set_config(config: ExecutorConfig) -> u32 {
122 let mut encoded = to_vec(&config).unwrap();
123 unsafe { bindings::set_config(encoded.as_mut_ptr(), encoded.len()) }
124}