wasm_http_hyper/
incoming_message.rs

1use bytes::Bytes;
2use futures::Stream;
3use futures::StreamExt;
4use gloo_utils::format::JsValueSerdeExt;
5use std::{collections::HashMap, future::Future};
6use wasm_bindgen::prelude::*;
7
8#[wasm_bindgen(typescript_custom_section)]
9const TS_IMPORT: &'static str = r#"
10import { IncomingMessage } from "node:http";
11"#;
12
13#[wasm_bindgen]
14extern "C" {
15    #[wasm_bindgen(typescript_type = "IncomingMessage")]
16    pub type IncomingMessage;
17
18    #[wasm_bindgen(method)]
19    pub fn on(this: &IncomingMessage, event: &str, callback: &js_sys::Function) -> JsValue;
20
21    #[wasm_bindgen(method, getter)]
22    pub fn method(this: &IncomingMessage) -> String;
23
24    #[wasm_bindgen(method, getter)]
25    pub fn url(this: &IncomingMessage) -> String;
26
27    #[wasm_bindgen(method, getter, js_name = headers)]
28    pub fn headers(this: &IncomingMessage) -> js_sys::Object;
29}
30
31impl IncomingMessage {
32    pub fn body_fut(&self) -> impl Future<Output = Bytes> {
33        let body = self.body_stream();
34        async move {
35            let bytes: Vec<_> = body.collect().await;
36            let mut result = Vec::new();
37            for chunk in bytes {
38                result.extend_from_slice(&chunk);
39            }
40            Bytes::from(result)
41        }
42    }
43
44    pub fn body_stream(&self) -> impl Stream<Item = Bytes> {
45        let (tx, rx) = futures::channel::mpsc::unbounded();
46
47        let data_handler = Closure::wrap(Box::new({
48            let tx = tx.clone();
49            move |chunk: JsValue| {
50                let buffer = js_sys::Uint8Array::new(&chunk).to_vec();
51                let _ = tx.unbounded_send(Bytes::from(buffer));
52            }
53        }) as Box<dyn FnMut(JsValue)>);
54        let end_handler = Closure::wrap(Box::new(move || {
55            let _ = tx.close_channel();
56        }) as Box<dyn FnMut()>);
57
58        self.on("data", data_handler.as_ref().unchecked_ref());
59        self.on("end", end_handler.as_ref().unchecked_ref());
60
61        // Prevent handlers from being dropped
62        data_handler.forget();
63        end_handler.forget();
64
65        rx
66    }
67
68    pub fn headers_map(&self) -> HashMap<String, String> {
69        self.headers()
70            .into_serde::<HashMap<String, String>>()
71            .expect("headers is not a map")
72    }
73}