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 async fn into_buffered(mut self) -> Result<Self> {
115 if let Some(body_stream) = &self.body_stream {
116 let mut body_stream = body_stream.lock().take();
117 if let Some(mut body_stream) = body_stream.take() {
118 while let Some(chunk) = body_stream.recv().await? {
119 self.inner.body_mut().extend_from_slice(&chunk);
120 }
121 }
122 }
123 self.body_stream = None;
124 Ok(self)
125 }
126
127 pub fn into_inner(self) -> http::Request<Vec<u8>> {
128 self.inner
129 }
130
131 pub fn into_body(self) -> Vec<u8> {
132 self.inner.into_body()
133 }
134}
135
136impl Default for Request {
137 fn default() -> Self {
138 Self::new(Vec::new())
139 }
140}
141
142impl Deref for Request {
143 type Target = http::Request<Vec<u8>>;
144
145 fn deref(&self) -> &Self::Target {
146 &self.inner
147 }
148}
149
150impl DerefMut for Request {
151 fn deref_mut(&mut self) -> &mut Self::Target {
152 &mut self.inner
153 }
154}
155
156impl From<http::Request<Vec<u8>>> for Request {
157 fn from(value: http::Request<Vec<u8>>) -> Self {
158 Self {
159 inner: value,
160 body_stream: None,
161 cancel_token: CancellationToken::new(),
162 }
163 }
164}
165
166impl From<Request> for http::Request<Vec<u8>> {
167 fn from(value: Request) -> Self {
168 value.inner
169 }
170}
171
172#[derive(Clone, Debug)]
173pub struct Response(http::Response<Vec<u8>>);
174
175impl Response {
176 pub fn new(body: Vec<u8>) -> Self {
177 Self(http::Response::new(body))
178 }
179
180 pub fn from_parts(
181 status: u16,
182 headers: HashMap<String, String>,
183 body: Vec<u8>,
184 ) -> Result<Self> {
185 let mut response = http::Response::new(body);
186 *response.status_mut() = status
187 .try_into()
188 .map_err(|error| invalid_http_response("status", format!("{status}: {error}")))?;
189
190 for (name, value) in headers {
191 let header_name: http::header::HeaderName = name.parse().map_err(|error| {
192 invalid_http_response("header name", format!("{name}: {error}"))
193 })?;
194 let header_value: http::header::HeaderValue = value.parse().map_err(|error| {
195 invalid_http_response("header value", format!("{name}: {error}"))
196 })?;
197 response.headers_mut().insert(header_name, header_value);
198 }
199
200 Ok(Self(response))
201 }
202
203 pub fn to_parts(&self) -> (u16, HashMap<String, String>, Vec<u8>) {
204 (
205 self.status().as_u16(),
206 self.headers()
207 .iter()
208 .map(|(name, value)| {
209 (
210 name.to_string(),
211 String::from_utf8_lossy(value.as_bytes()).into_owned(),
212 )
213 })
214 .collect(),
215 self.body().clone(),
216 )
217 }
218
219 pub fn into_inner(self) -> http::Response<Vec<u8>> {
220 self.0
221 }
222
223 pub fn into_body(self) -> Vec<u8> {
224 self.0.into_body()
225 }
226}
227
228fn invalid_http_request(field: &str, reason: String) -> anyhow::Error {
229 ProtocolError::InvalidHttpRequest {
230 field: field.to_owned(),
231 reason,
232 }
233 .build()
234}
235
236fn invalid_http_response(field: &str, reason: String) -> anyhow::Error {
237 ProtocolError::InvalidHttpResponse {
238 field: field.to_owned(),
239 reason,
240 }
241 .build()
242}
243
244impl Default for Response {
245 fn default() -> Self {
246 Self::new(Vec::new())
247 }
248}
249
250impl Deref for Response {
251 type Target = http::Response<Vec<u8>>;
252
253 fn deref(&self) -> &Self::Target {
254 &self.0
255 }
256}
257
258impl DerefMut for Response {
259 fn deref_mut(&mut self) -> &mut Self::Target {
260 &mut self.0
261 }
262}
263
264impl From<http::Response<Vec<u8>>> for Response {
265 fn from(value: http::Response<Vec<u8>>) -> Self {
266 Self(value)
267 }
268}
269
270impl From<Response> for http::Response<Vec<u8>> {
271 fn from(value: Response) -> Self {
272 value.0
273 }
274}
275
276pub struct StreamingResponse {
277 status: u16,
278 headers: HashMap<String, String>,
279 body_stream: mpsc::Receiver<ResponseChunk>,
280}
281
282impl StreamingResponse {
283 pub fn from_parts(
284 status: u16,
285 headers: HashMap<String, String>,
286 body_stream: mpsc::Receiver<ResponseChunk>,
287 ) -> Result<Self> {
288 let status_code: http::StatusCode = status
289 .try_into()
290 .map_err(|error| invalid_http_response("status", format!("{status}: {error}")))?;
291 for (name, value) in &headers {
292 let _: http::header::HeaderName = name.parse().map_err(|error| {
293 invalid_http_response("header name", format!("{name}: {error}"))
294 })?;
295 let _: http::header::HeaderValue = value.parse().map_err(|error| {
296 invalid_http_response("header value", format!("{name}: {error}"))
297 })?;
298 }
299
300 Ok(Self {
301 status: status_code.as_u16(),
302 headers,
303 body_stream,
304 })
305 }
306
307 pub fn into_parts(self) -> (u16, HashMap<String, String>, mpsc::Receiver<ResponseChunk>) {
308 (self.status, self.headers, self.body_stream)
309 }
310}
311
312pub enum ActorHttpResponse {
313 Buffered(Response),
314 Stream(StreamingResponse),
315}
316
317impl ActorHttpResponse {
318 pub fn status(&self) -> u16 {
319 match self {
320 Self::Buffered(response) => response.status().as_u16(),
321 Self::Stream(response) => response.status,
322 }
323 }
324}
325
326impl From<Response> for ActorHttpResponse {
327 fn from(value: Response) -> Self {
328 Self::Buffered(value)
329 }
330}
331
332impl From<StreamingResponse> for ActorHttpResponse {
333 fn from(value: StreamingResponse) -> Self {
334 Self::Stream(value)
335 }
336}
337
338#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
339pub enum StateDelta {
340 ActorState(Vec<u8>),
341 ConnHibernation { conn: ConnId, bytes: Vec<u8> },
342 ConnHibernationRemoved(ConnId),
343}
344
345#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
348pub struct WorkflowKvWrite {
349 pub key: Vec<u8>,
350 pub value: Vec<u8>,
351}
352
353impl StateDelta {
354 pub(crate) fn payload_len(&self) -> usize {
355 match self {
356 Self::ActorState(bytes) | Self::ConnHibernation { bytes, .. } => bytes.len(),
357 Self::ConnHibernationRemoved(_) => 0,
358 }
359 }
360}
361
362#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
363pub enum SerializeStateReason {
364 Save,
365 Inspector,
366}
367
368impl SerializeStateReason {
369 pub(crate) fn label(self) -> &'static str {
370 match self {
371 Self::Save => "save",
372 Self::Inspector => "inspector",
373 }
374 }
375}
376
377#[derive(Clone, Debug, PartialEq, Eq)]
378pub enum QueueSendStatus {
379 Completed,
380 TimedOut,
381}
382
383impl QueueSendStatus {
384 pub(crate) fn as_str(&self) -> &'static str {
385 match self {
386 Self::Completed => "completed",
387 Self::TimedOut => "timedOut",
388 }
389 }
390}
391
392#[derive(Clone, Debug, PartialEq, Eq)]
393pub struct QueueSendResult {
394 pub status: QueueSendStatus,
395 pub response: Option<Vec<u8>>,
396}
397
398#[derive(Debug)]
399pub enum ActorEvent {
400 Action {
401 name: String,
402 args: Vec<u8>,
403 conn: Option<ConnHandle>,
404 scheduled_fire: Option<ScheduledFireInfo>,
405 invocation_telemetry: Option<ActorInvocationTelemetry>,
409 reply: Reply<Vec<u8>>,
410 },
411 HttpRequest {
412 request: Request,
413 invocation_telemetry: Option<crate::ActorInvocationTelemetry>,
415 reply: Reply<ActorHttpResponse>,
416 },
417 QueueSend {
418 name: String,
419 body: Vec<u8>,
420 conn: ConnHandle,
421 request: Request,
422 wait: bool,
423 timeout_ms: Option<u64>,
424 invocation_telemetry: Option<crate::ActorInvocationTelemetry>,
426 reply: Reply<QueueSendResult>,
427 },
428 WebSocketOpen {
429 conn: ConnHandle,
430 ws: WebSocket,
431 request: Option<Request>,
432 reply: Reply<()>,
433 },
434 ConnectionPreflight {
435 conn: ConnHandle,
436 params: Vec<u8>,
437 request: Option<Request>,
438 reply: Reply<()>,
439 },
440 ConnectionOpen {
441 conn: ConnHandle,
442 request: Option<Request>,
443 reply: Reply<()>,
444 },
445 ConnectionClosed {
446 conn: ConnHandle,
447 },
448 SubscribeRequest {
449 conn: ConnHandle,
450 event_name: String,
451 reply: Reply<()>,
452 },
453 SerializeState {
454 reason: SerializeStateReason,
455 reply: Reply<Vec<StateDelta>>,
456 },
457 RunGracefulCleanup {
458 reason: ShutdownKind,
459 reply: Reply<()>,
460 },
461 DisconnectConn {
462 conn_id: ConnId,
463 reply: Reply<()>,
464 },
465 #[cfg(test)]
466 BeginSleep,
467 #[cfg(test)]
468 FinalizeSleep {
469 reply: Reply<()>,
470 },
471 #[cfg(test)]
472 Destroy {
473 reply: Reply<()>,
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 #[cfg(test)]
512 Self::BeginSleep => "begin_sleep",
513 #[cfg(test)]
514 Self::FinalizeSleep { .. } => "finalize_sleep",
515 #[cfg(test)]
516 Self::Destroy { .. } => "destroy",
517 Self::WorkflowHistoryRequested { .. } => "workflow_history_requested",
518 Self::WorkflowReplayRequested { .. } => "workflow_replay_requested",
519 Self::RunWake { .. } => "run_wake",
520 }
521 }
522}
523
524#[cfg(test)]
526#[path = "../../tests/messages.rs"]
527mod tests;