Skip to main content

basm_sdk_community/
http.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::json;
5use thiserror::Error;
6
7//use base64::{engine::general_purpose::STANDARD, Engine};
8
9use crate::{io::HostResult, memory::{leak_to_shared_memory, FatPointer}};
10
11#[link(wasm_import_module = "env")]
12extern "C" {
13    pub fn httpRequest(offset: u32, size: u32) -> FatPointer;
14}
15
16#[derive(Serialize, Deserialize, Debug)]
17pub struct HttpRequestOutput {
18    pub status_code: u16,
19    pub headers: Option<BTreeMap<String, Vec<String>>>,
20    pub body: Option<String>,
21}
22
23#[derive(Error, Debug)]
24pub enum HttpRequestError {
25    #[error("Bad serialization of input data: {0}")]
26    BadSerialization(serde_json::Error),
27    #[error("Bad deserialization of output data: {0}")]
28    BadDeserialization(serde_json::Error),
29    #[error("Request Failed: {0}")]
30    RequestFailed(String)
31}
32
33/// Sends an HTTP request to the host environment and returns the result.
34/// An HttpRequestError implies that there was some issue with sending or
35/// receiving the request or response.
36/// 
37/// The url, method, headers, and body are serialized into JSON before being
38/// sent to the host.
39/// 
40/// Example:
41/// ```
42/// let result = send_http_request(
43///     "GET".into(),
44///     "https://my-example-api.example.com/api/v2/test".into(),
45///     &BTreeMap::from([
46///         ("Content-Type".into(), vec!["application/json".into()]),
47///         ("Authorization".into(), vec!["Bearer mytoken".into()])
48///     ]),
49///     &[]
50/// );
51/// 
52/// log!("HTTP Request Result: {:?}", result);
53/// ```
54pub fn send_http_request(
55    method: String,
56    url: String,
57    headers: &BTreeMap<String, Vec<String>>,
58    body: &[u8],
59) -> Result<HttpRequestOutput, HttpRequestError> {
60    let input = json!({
61        "url": url,
62        "method": method,
63        "headers": headers,
64        "body": body
65    });
66
67    let serialized_input = serde_json::to_string(&input)
68        .map_err(|e| HttpRequestError::BadSerialization(e))?;
69    let input_ptr = leak_to_shared_memory(serialized_input.as_bytes());
70    let output_ptr = unsafe { httpRequest(input_ptr.offset(), input_ptr.size()) };
71    let data = unsafe { output_ptr.copy_data() };
72
73    let host_result = serde_json::from_slice::<HostResult<HttpRequestOutput>>(&data)
74        .map_err(|e| HttpRequestError::BadDeserialization(e))?;
75    
76    // TODO: deserialize from b64
77
78    if host_result.ok {
79        Ok(host_result.value)
80    } else {
81        Err(HttpRequestError::RequestFailed(host_result.error))
82    }
83}