rivet_envoy_client/
http.rs1use std::collections::HashMap;
2
3use rivet_envoy_protocol as protocol;
4use tokio::sync::{mpsc, watch};
5
6pub const HTTP_BODY_STREAM_CHANNEL_CAPACITY: usize = 16;
7pub const HTTP_BODY_MAX_CHUNK_SIZE: usize = 64 * 1024;
8
9#[derive(Clone, Debug)]
10pub struct HttpRequestBodyError {
11 pub reason: protocol::HttpStreamAbortReason,
12}
13
14impl std::fmt::Display for HttpRequestBodyError {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 match &self.reason.detail {
17 Some(detail) => write!(f, "{:?}: {detail}", self.reason.kind),
18 None => write!(f, "{:?}", self.reason.kind),
19 }
20 }
21}
22
23impl std::error::Error for HttpRequestBodyError {}
24
25#[derive(Debug)]
26pub struct HttpRequestBodyStream {
27 rx: mpsc::Receiver<Vec<u8>>,
28 abort_rx: watch::Receiver<Option<HttpRequestBodyError>>,
29}
30
31impl HttpRequestBodyStream {
32 pub fn new(
33 rx: mpsc::Receiver<Vec<u8>>,
34 abort_rx: watch::Receiver<Option<HttpRequestBodyError>>,
35 ) -> Self {
36 Self { rx, abort_rx }
37 }
38
39 pub async fn recv(&mut self) -> Result<Option<Vec<u8>>, HttpRequestBodyError> {
40 loop {
41 if let Some(error) = self.abort_rx.borrow().clone() {
42 return Err(error);
43 }
44
45 tokio::select! {
46 biased;
47 changed = self.abort_rx.changed() => {
48 if changed.is_ok() {
49 continue;
50 }
51 return Ok(self.rx.recv().await);
52 }
53 chunk = self.rx.recv() => return Ok(chunk),
54 }
55 }
56 }
57}
58
59pub struct HttpRequest {
61 pub method: String,
62 pub path: String,
63 pub headers: HashMap<String, String>,
64 pub body: Option<Vec<u8>>,
65 pub body_stream: Option<HttpRequestBodyStream>,
67}
68
69pub struct HttpResponse {
70 pub status: u16,
71 pub headers: HashMap<String, String>,
72 pub body: Option<Vec<u8>>,
73 pub body_stream: Option<HttpResponseBodyStream>,
76}
77
78pub enum ResponseChunk {
80 Data { data: Vec<u8>, finish: bool },
81 Error(String),
82}
83
84pub struct HttpResponseBodyStream {
85 rx: mpsc::Receiver<ResponseChunk>,
86 on_drop: Option<Box<dyn FnOnce() + Send>>,
87}
88
89impl HttpResponseBodyStream {
90 pub fn set_on_drop(&mut self, on_drop: impl FnOnce() + Send + 'static) {
91 self.on_drop = Some(Box::new(on_drop));
92 }
93
94 pub async fn recv(&mut self) -> Option<ResponseChunk> {
95 self.rx.recv().await
96 }
97}
98
99impl From<mpsc::Receiver<ResponseChunk>> for HttpResponseBodyStream {
100 fn from(rx: mpsc::Receiver<ResponseChunk>) -> Self {
101 Self { rx, on_drop: None }
102 }
103}
104
105impl Drop for HttpResponseBodyStream {
106 fn drop(&mut self) {
107 if let Some(on_drop) = self.on_drop.take() {
108 on_drop();
109 }
110 }
111}