1use rivet_envoy_protocol as protocol;
2use std::collections::HashMap;
3
4use crate::utils::id_to_str;
5
6fn stringify_bytes(data: &[u8]) -> String {
7 format!("Bytes({})", data.len())
8}
9
10fn stringify_map(map: &HashMap<String, String>) -> String {
11 let entries: Vec<String> = map
12 .iter()
13 .map(|(k, v)| format!("\"{k}\": \"{v}\""))
14 .collect();
15 format!("Map({}){{{}}}", map.len(), entries.join(", "))
16}
17
18fn stringify_message_id(msg_id: &protocol::MessageId) -> String {
19 format!(
20 "MessageId{{gatewayId: {}, requestId: {}, messageIndex: {}}}",
21 id_to_str(&msg_id.gateway_id),
22 id_to_str(&msg_id.request_id),
23 msg_id.message_index
24 )
25}
26
27pub fn stringify_to_rivet_tunnel_message_kind(kind: &protocol::ToRivetTunnelMessageKind) -> String {
28 match kind {
29 protocol::ToRivetTunnelMessageKind::ToRivetResponseStart(val) => {
30 let body_str = match &val.body {
31 Some(b) => stringify_bytes(b),
32 None => "null".to_string(),
33 };
34 format!(
35 "ToRivetResponseStart{{status: {}, headers: {}, body: {}, stream: {}}}",
36 val.status,
37 stringify_map(&val.headers),
38 body_str,
39 val.stream
40 )
41 }
42 protocol::ToRivetTunnelMessageKind::ToRivetResponseChunk(val) => {
43 format!(
44 "ToRivetResponseChunk{{body: {}, finish: {}}}",
45 stringify_bytes(&val.body),
46 val.finish
47 )
48 }
49 protocol::ToRivetTunnelMessageKind::ToRivetResponseAbort(_) => {
50 "ToRivetResponseAbort".to_string()
51 }
52 protocol::ToRivetTunnelMessageKind::ToRivetRequestBodyWindowUpdate(val) => {
53 format!(
54 "ToRivetRequestBodyWindowUpdate{{consumedBytes: {}}}",
55 val.consumed_bytes
56 )
57 }
58 protocol::ToRivetTunnelMessageKind::ToRivetRequestBodyCancel => {
59 "ToRivetRequestBodyCancel".to_string()
60 }
61 protocol::ToRivetTunnelMessageKind::ToRivetWebSocketOpen(val) => {
62 format!(
63 "ToRivetWebSocketOpen{{canHibernate: {}}}",
64 val.can_hibernate
65 )
66 }
67 protocol::ToRivetTunnelMessageKind::ToRivetWebSocketMessage(val) => {
68 format!(
69 "ToRivetWebSocketMessage{{data: {}, binary: {}}}",
70 stringify_bytes(&val.data),
71 val.binary
72 )
73 }
74 protocol::ToRivetTunnelMessageKind::ToRivetWebSocketMessageAck(val) => {
75 format!("ToRivetWebSocketMessageAck{{index: {}}}", val.index)
76 }
77 protocol::ToRivetTunnelMessageKind::ToRivetWebSocketClose(val) => {
78 let code_str = match &val.code {
79 Some(c) => c.to_string(),
80 None => "null".to_string(),
81 };
82 let reason_str = match &val.reason {
83 Some(r) => format!("\"{r}\""),
84 None => "null".to_string(),
85 };
86 format!(
87 "ToRivetWebSocketClose{{code: {code_str}, reason: {reason_str}, hibernate: {}}}",
88 val.hibernate
89 )
90 }
91 }
92}
93
94pub fn stringify_to_envoy_tunnel_message_kind(kind: &protocol::ToEnvoyTunnelMessageKind) -> String {
95 match kind {
96 protocol::ToEnvoyTunnelMessageKind::ToEnvoyRequestStart(val) => {
97 let body_str = match &val.body {
98 Some(b) => stringify_bytes(b),
99 None => "null".to_string(),
100 };
101 format!(
102 "ToEnvoyRequestStart{{actorId: \"{}\", method: \"{}\", path: \"{}\", headers: {}, body: {}, stream: {}}}",
103 val.actor_id,
104 val.method,
105 val.path,
106 stringify_map(&val.headers),
107 body_str,
108 val.stream
109 )
110 }
111 protocol::ToEnvoyTunnelMessageKind::ToEnvoyRequestChunk(val) => {
112 format!(
113 "ToEnvoyRequestChunk{{body: {}, finish: {}}}",
114 stringify_bytes(&val.body),
115 val.finish
116 )
117 }
118 protocol::ToEnvoyTunnelMessageKind::ToEnvoyRequestAbort(_) => {
119 "ToEnvoyRequestAbort".to_string()
120 }
121 protocol::ToEnvoyTunnelMessageKind::ToEnvoyRequestBodyCancel => {
122 "ToEnvoyRequestBodyCancel".to_string()
123 }
124 protocol::ToEnvoyTunnelMessageKind::ToEnvoyResponseBodyWindowUpdate(val) => {
125 format!(
126 "ToEnvoyResponseBodyWindowUpdate{{consumedBytes: {}}}",
127 val.consumed_bytes
128 )
129 }
130 protocol::ToEnvoyTunnelMessageKind::ToEnvoyWebSocketOpen(val) => {
131 format!(
132 "ToEnvoyWebSocketOpen{{actorId: \"{}\", path: \"{}\", headers: {}}}",
133 val.actor_id,
134 val.path,
135 stringify_map(&val.headers)
136 )
137 }
138 protocol::ToEnvoyTunnelMessageKind::ToEnvoyWebSocketMessage(val) => {
139 format!(
140 "ToEnvoyWebSocketMessage{{data: {}, binary: {}}}",
141 stringify_bytes(&val.data),
142 val.binary
143 )
144 }
145 protocol::ToEnvoyTunnelMessageKind::ToEnvoyWebSocketClose(val) => {
146 let code_str = match &val.code {
147 Some(c) => c.to_string(),
148 None => "null".to_string(),
149 };
150 let reason_str = match &val.reason {
151 Some(r) => format!("\"{r}\""),
152 None => "null".to_string(),
153 };
154 format!("ToEnvoyWebSocketClose{{code: {code_str}, reason: {reason_str}}}")
155 }
156 }
157}
158
159pub fn stringify_command(command: &protocol::Command) -> String {
160 match command {
161 protocol::Command::CommandStartActor(val) => {
162 let key_str = match &val.config.key {
163 Some(k) => format!("\"{k}\""),
164 None => "null".to_string(),
165 };
166 let input_str = match &val.config.input {
167 Some(i) => stringify_bytes(i),
168 None => "null".to_string(),
169 };
170 let hib_str = if val.hibernating_requests.is_empty() {
171 "[]".to_string()
172 } else {
173 let entries: Vec<String> = val
174 .hibernating_requests
175 .iter()
176 .map(|hr| {
177 format!(
178 "{{gatewayId: {}, requestId: {}}}",
179 id_to_str(&hr.gateway_id),
180 id_to_str(&hr.request_id)
181 )
182 })
183 .collect();
184 format!("[{}]", entries.join(", "))
185 };
186 format!(
187 "CommandStartActor{{config: {{name: \"{}\", key: {key_str}, createTs: {}, input: {input_str}}}, hibernatingRequests: {hib_str}}}",
188 val.config.name, val.config.create_ts
189 )
190 }
191 protocol::Command::CommandStopActor(val) => {
192 format!("CommandStopActor{{reason: {:?}}}", val.reason)
193 }
194 }
195}
196
197pub fn stringify_command_wrapper(wrapper: &protocol::CommandWrapper) -> String {
198 format!(
199 "CommandWrapper{{actorId: \"{}\", generation: {}, index: {}, inner: {}}}",
200 wrapper.checkpoint.actor_id,
201 wrapper.checkpoint.generation,
202 wrapper.checkpoint.index,
203 stringify_command(&wrapper.inner)
204 )
205}
206
207pub fn stringify_event(event: &protocol::Event) -> String {
208 match event {
209 protocol::Event::EventActorIntent(val) => {
210 let intent_str = match &val.intent {
211 protocol::ActorIntent::ActorIntentSleep => "Sleep",
212 protocol::ActorIntent::ActorIntentStop => "Stop",
213 };
214 format!("EventActorIntent{{intent: {intent_str}}}")
215 }
216 protocol::Event::EventActorStateUpdate(val) => {
217 let state_str = match &val.state {
218 protocol::ActorState::ActorStateRunning => "Running".to_string(),
219 protocol::ActorState::ActorStateStopped(stopped) => {
220 let message_str = match &stopped.message {
221 Some(m) => format!("\"{m}\""),
222 None => "null".to_string(),
223 };
224 format!(
225 "Stopped{{code: {:?}, message: {message_str}}}",
226 stopped.code
227 )
228 }
229 };
230 format!("EventActorStateUpdate{{state: {state_str}}}")
231 }
232 protocol::Event::EventActorSetAlarm(val) => {
233 let alarm_str = match val.alarm_ts {
234 Some(ts) => ts.to_string(),
235 None => "null".to_string(),
236 };
237 format!("EventActorSetAlarm{{alarmTs: {alarm_str}}}")
238 }
239 }
240}
241
242pub fn stringify_event_wrapper(wrapper: &protocol::EventWrapper) -> String {
243 format!(
244 "EventWrapper{{actorId: {}, generation: {}, index: {}, inner: {}}}",
245 wrapper.checkpoint.actor_id,
246 wrapper.checkpoint.generation,
247 wrapper.checkpoint.index,
248 stringify_event(&wrapper.inner)
249 )
250}
251
252pub fn stringify_to_rivet(message: &protocol::ToRivet) -> String {
253 match message {
254 protocol::ToRivet::ToRivetMetadata(_) => "ToRivetMetadata".to_string(),
255 protocol::ToRivet::ToRivetEvents(events) => {
256 let event_strs: Vec<String> = events.iter().map(stringify_event_wrapper).collect();
257 format!(
258 "ToRivetEvents{{count: {}, events: [{}]}}",
259 events.len(),
260 event_strs.join(", ")
261 )
262 }
263 protocol::ToRivet::ToRivetAckCommands(val) => {
264 let checkpoints: Vec<String> = val
265 .last_command_checkpoints
266 .iter()
267 .map(|cp| format!("{{actorId: \"{}\", index: {}}}", cp.actor_id, cp.index))
268 .collect();
269 format!(
270 "ToRivetAckCommands{{lastCommandCheckpoints: [{}]}}",
271 checkpoints.join(", ")
272 )
273 }
274 protocol::ToRivet::ToRivetStopping => "ToRivetStopping".to_string(),
275 protocol::ToRivet::ToRivetPong(val) => {
276 format!("ToRivetPong{{ts: {}}}", val.ts)
277 }
278 protocol::ToRivet::ToRivetKvRequest(val) => {
279 format!(
280 "ToRivetKvRequest{{actorId: \"{}\", requestId: {}}}",
281 val.actor_id, val.request_id
282 )
283 }
284 protocol::ToRivet::ToRivetSqliteGetPagesRequest(val) => {
285 format!(
286 "ToRivetSqliteGetPagesRequest{{requestId: {}}}",
287 val.request_id
288 )
289 }
290 protocol::ToRivet::ToRivetSqliteCommitRequest(val) => {
291 format!(
292 "ToRivetSqliteCommitRequest{{requestId: {}}}",
293 val.request_id
294 )
295 }
296 protocol::ToRivet::ToRivetSqliteExecRequest(val) => {
297 format!(
298 "ToRivetSqliteExecRequest{{requestId: {}, actorId: \"{}\", generation: {}}}",
299 val.request_id, val.data.actor_id, val.data.generation
300 )
301 }
302 protocol::ToRivet::ToRivetSqliteExecuteRequest(val) => {
303 format!(
304 "ToRivetSqliteExecuteRequest{{requestId: {}, actorId: \"{}\", generation: {}}}",
305 val.request_id, val.data.actor_id, val.data.generation
306 )
307 }
308 protocol::ToRivet::ToRivetSqliteExecuteBatchRequest(val) => {
309 format!(
310 "ToRivetSqliteExecuteBatchRequest{{requestId: {}, actorId: \"{}\", generation: {}, statements: {}}}",
311 val.request_id,
312 val.data.actor_id,
313 val.data.generation,
314 val.data.statements.len()
315 )
316 }
317 protocol::ToRivet::ToRivetTunnelMessage(val) => {
318 format!(
319 "ToRivetTunnelMessage{{messageId: {}, messageKind: {}}}",
320 stringify_message_id(&val.message_id),
321 stringify_to_rivet_tunnel_message_kind(&val.message_kind)
322 )
323 }
324 }
325}
326
327pub fn stringify_to_envoy(message: &protocol::ToEnvoy) -> String {
328 match message {
329 protocol::ToEnvoy::ToEnvoyInit(val) => {
330 format!(
331 "ToEnvoyInit{{metadata: {{envoyLostThreshold: {}, actorStopThreshold: {}}}}}",
332 val.metadata.envoy_lost_threshold, val.metadata.actor_stop_threshold
333 )
334 }
335 protocol::ToEnvoy::ToEnvoyCommands(commands) => {
336 let cmd_strs: Vec<String> = commands.iter().map(stringify_command_wrapper).collect();
337 format!(
338 "ToEnvoyCommands{{count: {}, commands: [{}]}}",
339 commands.len(),
340 cmd_strs.join(", ")
341 )
342 }
343 protocol::ToEnvoy::ToEnvoyAckEvents(val) => {
344 let checkpoints: Vec<String> = val
345 .last_event_checkpoints
346 .iter()
347 .map(|cp| format!("{{actorId: \"{}\", index: {}}}", cp.actor_id, cp.index))
348 .collect();
349 format!(
350 "ToEnvoyAckEvents{{lastEventCheckpoints: [{}]}}",
351 checkpoints.join(", ")
352 )
353 }
354 protocol::ToEnvoy::ToEnvoyKvResponse(val) => {
355 format!("ToEnvoyKvResponse{{requestId: {}}}", val.request_id)
356 }
357 protocol::ToEnvoy::ToEnvoySqliteGetPagesResponse(val) => {
358 format!(
359 "ToEnvoySqliteGetPagesResponse{{requestId: {}}}",
360 val.request_id
361 )
362 }
363 protocol::ToEnvoy::ToEnvoySqliteCommitResponse(val) => {
364 format!(
365 "ToEnvoySqliteCommitResponse{{requestId: {}}}",
366 val.request_id
367 )
368 }
369 protocol::ToEnvoy::ToEnvoySqliteExecResponse(val) => {
370 format!("ToEnvoySqliteExecResponse{{requestId: {}}}", val.request_id)
371 }
372 protocol::ToEnvoy::ToEnvoySqliteExecuteResponse(val) => {
373 format!(
374 "ToEnvoySqliteExecuteResponse{{requestId: {}}}",
375 val.request_id
376 )
377 }
378 protocol::ToEnvoy::ToEnvoySqliteExecuteBatchResponse(val) => {
379 format!(
380 "ToEnvoySqliteExecuteBatchResponse{{requestId: {}}}",
381 val.request_id
382 )
383 }
384 protocol::ToEnvoy::ToEnvoyTunnelMessage(val) => {
385 format!(
386 "ToEnvoyTunnelMessage{{messageId: {}, messageKind: {}}}",
387 stringify_message_id(&val.message_id),
388 stringify_to_envoy_tunnel_message_kind(&val.message_kind)
389 )
390 }
391 protocol::ToEnvoy::ToEnvoyPing(val) => {
392 format!("ToEnvoyPing{{ts: {}}}", val.ts)
393 }
394 }
395}