1use std::collections::HashMap;
2use std::ops::{Deref, DerefMut};
3use std::sync::Arc;
4
5use anyhow::Result;
6use parking_lot::Mutex;
7use rivet_envoy_client::config::{HttpRequestBodyStream, ResponseChunk};
8use serde::{Deserialize, Serialize};
9use tokio::sync::mpsc;
10use tokio_util::sync::CancellationToken;
11
12use crate::actor::connection::ConnHandle;
13use crate::actor::lifecycle_hooks::Reply;
14use crate::actor::schedule::ScheduledFireInfo;
15use crate::actor::task_types::ShutdownKind;
16use crate::error::ProtocolError;
17use crate::telemetry::ActorInvocationTelemetry;
18use crate::types::ConnId;
19use crate::websocket::WebSocket;
20
21#[derive(Clone, Debug)]
22pub struct Request {
23 inner: http::Request<Vec<u8>>,
24 body_stream: Option<Arc<Mutex<Option<HttpRequestBodyStream>>>>,
25 cancel_token: CancellationToken,
26}
27
28impl Request {
29 pub fn new(body: Vec<u8>) -> Self {
30 Self {
31 inner: http::Request::new(body),
32 body_stream: None,
33 cancel_token: CancellationToken::new(),
34 }
35 }
36
37 pub fn from_parts(
38 method: &str,
39 uri: &str,
40 headers: HashMap<String, String>,
41 body: Vec<u8>,
42 ) -> Result<Self> {
43 Self::from_parts_with_stream(method, uri, headers, body, None)
44 }
45
46 pub fn from_parts_with_stream(
47 method: &str,
48 uri: &str,
49 headers: HashMap<String, String>,
50 body: Vec<u8>,
51 body_stream: Option<HttpRequestBodyStream>,
52 ) -> Result<Self> {
53 let method = method
54 .parse::<http::Method>()
55 .map_err(|error| invalid_http_request("method", format!("{method}: {error}")))?;
56 let uri = uri
57 .parse::<http::Uri>()
58 .map_err(|error| invalid_http_request("uri", format!("{uri}: {error}")))?;
59 let mut request = http::Request::builder()
60 .method(method)
61 .uri(uri)
62 .body(body)?;
63
64 for (name, value) in headers {
65 let header_name: http::header::HeaderName = name
66 .parse()
67 .map_err(|error| invalid_http_request("header name", format!("{name}: {error}")))?;
68 let header_value: http::header::HeaderValue = value.parse().map_err(|error| {
69 invalid_http_request("header value", format!("{name}: {error}"))
70 })?;
71 request.headers_mut().insert(header_name, header_value);
72 }
73
74 Ok(Self {
75 inner: request,
76 body_stream: body_stream.map(|rx| Arc::new(Mutex::new(Some(rx)))),
77 cancel_token: CancellationToken::new(),
78 })
79 }
80
81 pub fn to_parts(&self) -> (String, String, HashMap<String, String>, Vec<u8>) {
82 (
83 self.method().to_string(),
84 self.uri().to_string(),
85 self.headers()
86 .iter()
87 .map(|(name, value)| {
88 (
89 name.to_string(),
90 String::from_utf8_lossy(value.as_bytes()).into_owned(),
91 )
92 })
93 .collect(),
94 self.body().clone(),
95 )
96 }
97
98 pub fn has_body_stream(&self) -> bool {
99 self.body_stream
100 .as_ref()
101 .is_some_and(|body_stream| body_stream.lock().is_some())
102 }
103
104 pub fn take_body_stream(&self) -> Option<HttpRequestBodyStream> {
105 self.body_stream
106 .as_ref()
107 .and_then(|body_stream| body_stream.lock().take())
108 }
109
110 pub fn cancellation_token(&self) -> CancellationToken {
111 self.cancel_token.clone()
112 }
113
114 pub(crate) fn set_cancellation_parent(&mut self, parent: &CancellationToken) {
118 self.cancel_token = parent.child_token();
119 }
120
121 pub async fn into_buffered(mut self) -> Result<Self> {
122 if let Some(body_stream) = &self.body_stream {
123 let mut body_stream = body_stream.lock().take();
124 if let Some(mut body_stream) = body_stream.take() {
125 while let Some(chunk) = body_stream.recv().await? {
126 self.inner.body_mut().extend_from_slice(&chunk);
127 }
128 }
129 }
130 self.body_stream = None;
131 Ok(self)
132 }
133
134 pub fn into_inner(self) -> http::Request<Vec<u8>> {
135 self.inner
136 }
137
138 pub fn into_body(self) -> Vec<u8> {
139 self.inner.into_body()
140 }
141}
142
143impl Default for Request {
144 fn default() -> Self {
145 Self::new(Vec::new())
146 }
147}
148
149impl Deref for Request {
150 type Target = http::Request<Vec<u8>>;
151
152 fn deref(&self) -> &Self::Target {
153 &self.inner
154 }
155}
156
157impl DerefMut for Request {
158 fn deref_mut(&mut self) -> &mut Self::Target {
159 &mut self.inner
160 }
161}
162
163impl From<http::Request<Vec<u8>>> for Request {
164 fn from(value: http::Request<Vec<u8>>) -> Self {
165 Self {
166 inner: value,
167 body_stream: None,
168 cancel_token: CancellationToken::new(),
169 }
170 }
171}
172
173impl From<Request> for http::Request<Vec<u8>> {
174 fn from(value: Request) -> Self {
175 value.inner
176 }
177}
178
179#[derive(Clone, Debug)]
180pub struct Response(http::Response<Vec<u8>>);
181
182impl Response {
183 pub fn new(body: Vec<u8>) -> Self {
184 Self(http::Response::new(body))
185 }
186
187 pub fn from_parts(
188 status: u16,
189 headers: HashMap<String, String>,
190 body: Vec<u8>,
191 ) -> Result<Self> {
192 let mut response = http::Response::new(body);
193 *response.status_mut() = status
194 .try_into()
195 .map_err(|error| invalid_http_response("status", format!("{status}: {error}")))?;
196
197 for (name, value) in headers {
198 let header_name: http::header::HeaderName = name.parse().map_err(|error| {
199 invalid_http_response("header name", format!("{name}: {error}"))
200 })?;
201 let header_value: http::header::HeaderValue = value.parse().map_err(|error| {
202 invalid_http_response("header value", format!("{name}: {error}"))
203 })?;
204 response.headers_mut().insert(header_name, header_value);
205 }
206
207 Ok(Self(response))
208 }
209
210 pub fn to_parts(&self) -> (u16, HashMap<String, String>, Vec<u8>) {
211 (
212 self.status().as_u16(),
213 self.headers()
214 .iter()
215 .map(|(name, value)| {
216 (
217 name.to_string(),
218 String::from_utf8_lossy(value.as_bytes()).into_owned(),
219 )
220 })
221 .collect(),
222 self.body().clone(),
223 )
224 }
225
226 pub fn into_inner(self) -> http::Response<Vec<u8>> {
227 self.0
228 }
229
230 pub fn into_body(self) -> Vec<u8> {
231 self.0.into_body()
232 }
233}
234
235fn invalid_http_request(field: &str, reason: String) -> anyhow::Error {
236 ProtocolError::InvalidHttpRequest {
237 field: field.to_owned(),
238 reason,
239 }
240 .build()
241}
242
243fn invalid_http_response(field: &str, reason: String) -> anyhow::Error {
244 ProtocolError::InvalidHttpResponse {
245 field: field.to_owned(),
246 reason,
247 }
248 .build()
249}
250
251impl Default for Response {
252 fn default() -> Self {
253 Self::new(Vec::new())
254 }
255}
256
257impl Deref for Response {
258 type Target = http::Response<Vec<u8>>;
259
260 fn deref(&self) -> &Self::Target {
261 &self.0
262 }
263}
264
265impl DerefMut for Response {
266 fn deref_mut(&mut self) -> &mut Self::Target {
267 &mut self.0
268 }
269}
270
271impl From<http::Response<Vec<u8>>> for Response {
272 fn from(value: http::Response<Vec<u8>>) -> Self {
273 Self(value)
274 }
275}
276
277impl From<Response> for http::Response<Vec<u8>> {
278 fn from(value: Response) -> Self {
279 value.0
280 }
281}
282
283pub struct StreamingResponse {
284 status: u16,
285 headers: HashMap<String, String>,
286 body_stream: mpsc::Receiver<ResponseChunk>,
287}
288
289impl StreamingResponse {
290 pub fn from_parts(
291 status: u16,
292 headers: HashMap<String, String>,
293 body_stream: mpsc::Receiver<ResponseChunk>,
294 ) -> Result<Self> {
295 let status_code: http::StatusCode = status
296 .try_into()
297 .map_err(|error| invalid_http_response("status", format!("{status}: {error}")))?;
298 for (name, value) in &headers {
299 let _: http::header::HeaderName = name.parse().map_err(|error| {
300 invalid_http_response("header name", format!("{name}: {error}"))
301 })?;
302 let _: http::header::HeaderValue = value.parse().map_err(|error| {
303 invalid_http_response("header value", format!("{name}: {error}"))
304 })?;
305 }
306
307 Ok(Self {
308 status: status_code.as_u16(),
309 headers,
310 body_stream,
311 })
312 }
313
314 pub fn into_parts(self) -> (u16, HashMap<String, String>, mpsc::Receiver<ResponseChunk>) {
315 (self.status, self.headers, self.body_stream)
316 }
317}
318
319pub enum ActorHttpResponse {
320 Buffered(Response),
321 Stream(StreamingResponse),
322}
323
324impl ActorHttpResponse {
325 pub fn status(&self) -> u16 {
326 match self {
327 Self::Buffered(response) => response.status().as_u16(),
328 Self::Stream(response) => response.status,
329 }
330 }
331}
332
333impl From<Response> for ActorHttpResponse {
334 fn from(value: Response) -> Self {
335 Self::Buffered(value)
336 }
337}
338
339impl From<StreamingResponse> for ActorHttpResponse {
340 fn from(value: StreamingResponse) -> Self {
341 Self::Stream(value)
342 }
343}
344
345#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
346pub enum StateDelta {
347 ActorState(Vec<u8>),
348 ConnHibernation { conn: ConnId, bytes: Vec<u8> },
349 ConnHibernationRemoved(ConnId),
350}
351
352#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
355pub struct WorkflowKvWrite {
356 pub key: Vec<u8>,
357 pub value: Vec<u8>,
358}
359
360impl StateDelta {
361 pub(crate) fn payload_len(&self) -> usize {
362 match self {
363 Self::ActorState(bytes) | Self::ConnHibernation { bytes, .. } => bytes.len(),
364 Self::ConnHibernationRemoved(_) => 0,
365 }
366 }
367}
368
369#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
370pub enum SerializeStateReason {
371 Save,
372 Inspector,
373}
374
375impl SerializeStateReason {
376 pub(crate) fn label(self) -> &'static str {
377 match self {
378 Self::Save => "save",
379 Self::Inspector => "inspector",
380 }
381 }
382}
383
384#[derive(Clone, Debug, PartialEq, Eq)]
385pub enum QueueSendStatus {
386 Completed,
387 TimedOut,
388}
389
390impl QueueSendStatus {
391 pub(crate) fn as_str(&self) -> &'static str {
392 match self {
393 Self::Completed => "completed",
394 Self::TimedOut => "timedOut",
395 }
396 }
397}
398
399#[derive(Clone, Debug, PartialEq, Eq)]
400pub struct QueueSendResult {
401 pub status: QueueSendStatus,
402 pub response: Option<Vec<u8>>,
403}
404
405#[derive(Debug)]
406pub enum ActorEvent {
407 Action {
408 name: String,
409 args: Vec<u8>,
410 conn: Option<ConnHandle>,
411 scheduled_fire: Option<ScheduledFireInfo>,
412 invocation_telemetry: Option<ActorInvocationTelemetry>,
416 reply: Reply<Vec<u8>>,
417 },
418 HttpRequest {
419 request: Request,
420 invocation_telemetry: Option<crate::ActorInvocationTelemetry>,
422 reply: Reply<ActorHttpResponse>,
423 },
424 QueueSend {
425 name: String,
426 body: Vec<u8>,
427 conn: ConnHandle,
428 request: Request,
429 wait: bool,
430 timeout_ms: Option<u64>,
431 invocation_telemetry: Option<crate::ActorInvocationTelemetry>,
433 reply: Reply<QueueSendResult>,
434 },
435 WebSocketOpen {
436 conn: ConnHandle,
437 ws: WebSocket,
438 request: Option<Request>,
439 reply: Reply<()>,
440 },
441 ConnectionPreflight {
442 conn: ConnHandle,
443 params: Vec<u8>,
444 request: Option<Request>,
445 reply: Reply<()>,
446 },
447 ConnectionOpen {
448 conn: ConnHandle,
449 request: Option<Request>,
450 reply: Reply<()>,
451 },
452 ConnectionClosed {
453 conn: ConnHandle,
454 },
455 SubscribeRequest {
456 conn: ConnHandle,
457 event_name: String,
458 reply: Reply<()>,
459 },
460 SerializeState {
461 reason: SerializeStateReason,
462 reply: Reply<Vec<StateDelta>>,
463 },
464 RunGracefulCleanup {
465 reason: ShutdownKind,
466 reply: Reply<()>,
467 },
468 DisconnectConn {
469 conn_id: ConnId,
470 reply: Reply<()>,
471 },
472
473
474
475 WorkflowHistoryRequested {
476 reply: Reply<Option<Vec<u8>>>,
477 },
478 WorkflowReplayRequested {
479 entry_id: Option<String>,
480 reply: Reply<Option<Vec<u8>>>,
481 },
482 RunWake {
485 wake_at: i64,
486 wake_revision: u64,
487 reply: Reply<()>,
488 },
489}
490
491impl ActorEvent {
492 pub(crate) fn kind(&self) -> &'static str {
493 match self {
494 Self::Action { .. } => "action",
495 Self::HttpRequest { .. } => "http_request",
496 Self::QueueSend { .. } => "queue_send",
497 Self::WebSocketOpen { .. } => "websocket_open",
498 Self::ConnectionPreflight { .. } => "connection_preflight",
499 Self::ConnectionOpen { .. } => "connection_open",
500 Self::ConnectionClosed { .. } => "connection_closed",
501 Self::SubscribeRequest { .. } => "subscribe_request",
502 Self::SerializeState { reason, .. } => match reason {
503 SerializeStateReason::Save => "serialize_state_save",
504 SerializeStateReason::Inspector => "serialize_state_inspector",
505 },
506 Self::RunGracefulCleanup { reason, .. } => match reason {
507 ShutdownKind::Sleep => "run_sleep_cleanup",
508 ShutdownKind::Destroy => "run_destroy_cleanup",
509 },
510 Self::DisconnectConn { .. } => "disconnect_conn",
511
512
513
514 Self::WorkflowHistoryRequested { .. } => "workflow_history_requested",
515 Self::WorkflowReplayRequested { .. } => "workflow_replay_requested",
516 Self::RunWake { .. } => "run_wake",
517 }
518 }
519}
520
521