1use std::collections::HashMap;
2use std::future::Future;
3use std::pin::Pin;
4use std::sync::Arc;
5use std::sync::Mutex;
6
7use rivet_envoy_protocol as protocol;
8use tokio::sync::{mpsc, oneshot};
9
10use crate::handle::EnvoyHandle;
11
12#[cfg(not(target_arch = "wasm32"))]
13pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
14
15#[cfg(target_arch = "wasm32")]
16pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;
17
18pub struct HttpRequest {
20 pub method: String,
21 pub path: String,
22 pub headers: HashMap<String, String>,
23 pub body: Option<Vec<u8>>,
24 pub body_stream: Option<mpsc::UnboundedReceiver<Vec<u8>>>,
26}
27
28pub struct HttpResponse {
29 pub status: u16,
30 pub headers: HashMap<String, String>,
31 pub body: Option<Vec<u8>>,
32 pub body_stream: Option<mpsc::UnboundedReceiver<ResponseChunk>>,
35}
36
37pub struct ResponseChunk {
39 pub data: Vec<u8>,
40 pub finish: bool,
41}
42
43pub struct EnvoyConfig {
44 pub version: u32,
45 pub endpoint: String,
46 pub token: Option<String>,
47 pub namespace: String,
48 pub pool_name: String,
49 pub prepopulate_actor_names: HashMap<String, ActorName>,
50 pub metadata: Option<serde_json::Value>,
51 pub not_global: bool,
54
55 pub debug_latency_ms: Option<u64>,
57
58 pub callbacks: Arc<dyn EnvoyCallbacks>,
59}
60
61pub struct ActorName {
62 pub metadata: serde_json::Value,
63}
64
65#[derive(Clone)]
67pub struct ActorStopHandle {
68 tx: Arc<Mutex<Option<oneshot::Sender<anyhow::Result<()>>>>>,
69}
70
71impl ActorStopHandle {
72 pub(crate) fn new(tx: oneshot::Sender<anyhow::Result<()>>) -> Self {
73 Self {
74 tx: Arc::new(Mutex::new(Some(tx))),
75 }
76 }
77
78 pub fn complete(self) -> bool {
79 self.finish(Ok(()))
80 }
81
82 pub fn fail(self, error: anyhow::Error) -> bool {
83 self.finish(Err(error))
84 }
85
86 pub fn finish(self, result: anyhow::Result<()>) -> bool {
87 let mut guard = match self.tx.lock() {
88 Ok(guard) => guard,
89 Err(poisoned) => poisoned.into_inner(),
90 };
91
92 let Some(tx) = guard.take() else {
93 return false;
94 };
95
96 tx.send(result).is_ok()
97 }
98}
99
100pub trait EnvoyCallbacks: Send + Sync + 'static {
102 fn on_connect(&self, _handle: EnvoyHandle) {}
103
104 fn on_disconnect(&self, _handle: EnvoyHandle) {}
105
106 fn on_actor_start(
107 &self,
108 handle: EnvoyHandle,
109 actor_id: String,
110 generation: u32,
111 config: protocol::ActorConfig,
112 preloaded_kv: Option<protocol::PreloadedKv>,
113 ) -> BoxFuture<anyhow::Result<()>>;
114
115 fn on_actor_stop(
116 &self,
117 _handle: EnvoyHandle,
118 _actor_id: String,
119 _generation: u32,
120 _reason: protocol::StopActorReason,
121 ) -> BoxFuture<anyhow::Result<()>> {
122 Box::pin(async { Ok(()) })
123 }
124
125 fn on_actor_stop_with_completion(
126 &self,
127 handle: EnvoyHandle,
128 actor_id: String,
129 generation: u32,
130 reason: protocol::StopActorReason,
131 stop_handle: ActorStopHandle,
132 ) -> BoxFuture<anyhow::Result<()>> {
133 let stop_future = self.on_actor_stop(handle, actor_id, generation, reason);
134
135 Box::pin(async move {
136 stop_future.await?;
137 stop_handle.complete();
138 Ok(())
139 })
140 }
141
142 fn on_shutdown(&self);
143
144 fn fetch(
145 &self,
146 handle: EnvoyHandle,
147 actor_id: String,
148 gateway_id: protocol::GatewayId,
149 request_id: protocol::RequestId,
150 request: HttpRequest,
151 ) -> BoxFuture<anyhow::Result<HttpResponse>>;
152
153 fn websocket(
154 &self,
155 handle: EnvoyHandle,
156 actor_id: String,
157 gateway_id: protocol::GatewayId,
158 request_id: protocol::RequestId,
159 request: HttpRequest,
160 path: String,
161 headers: HashMap<String, String>,
162 is_hibernatable: bool,
163 is_restoring_hibernatable: bool,
164 sender: WebSocketSender,
165 ) -> BoxFuture<anyhow::Result<WebSocketHandler>>;
166
167 fn can_hibernate(
168 &self,
169 actor_id: &str,
170 gateway_id: &protocol::GatewayId,
171 request_id: &protocol::RequestId,
172 request: &HttpRequest,
173 ) -> BoxFuture<anyhow::Result<bool>>;
174}
175
176pub struct WebSocketHandler {
178 pub on_message: Box<dyn Fn(WebSocketMessage) -> BoxFuture<()> + Send + Sync>,
179 pub on_close: Box<dyn Fn(u16, String) -> BoxFuture<()> + Send + Sync>,
180 pub on_open: Option<Box<dyn FnOnce(WebSocketSender) -> BoxFuture<()> + Send>>,
181}
182
183pub struct WebSocketMessage {
184 pub data: Vec<u8>,
185 pub binary: bool,
186 pub gateway_id: protocol::GatewayId,
187 pub request_id: protocol::RequestId,
188 pub message_index: u16,
189 pub sender: WebSocketSender,
191}
192
193#[derive(Clone)]
195pub struct WebSocketSender {
196 pub(crate) tx: tokio::sync::mpsc::UnboundedSender<WsOutgoing>,
197}
198
199pub(crate) enum WsOutgoing {
200 Message {
201 data: Vec<u8>,
202 binary: bool,
203 },
204 Flush {
205 tx: tokio::sync::oneshot::Sender<()>,
206 },
207 Close {
208 code: Option<u16>,
209 reason: Option<String>,
210 },
211}
212
213impl WebSocketSender {
214 pub fn send(&self, data: Vec<u8>, binary: bool) {
215 let _ = self.tx.send(WsOutgoing::Message { data, binary });
216 }
217
218 pub fn send_text(&self, text: &str) {
219 self.send(text.as_bytes().to_vec(), false);
220 }
221
222 pub async fn flush(&self) {
223 let (tx, rx) = tokio::sync::oneshot::channel();
224 if self.tx.send(WsOutgoing::Flush { tx }).is_ok() {
225 let _ = rx.await;
226 }
227 }
228
229 pub fn close(&self, code: Option<u16>, reason: Option<String>) {
230 let _ = self.tx.send(WsOutgoing::Close { code, reason });
231 }
232}