Skip to main content

rivet_envoy_client/
stringify.rs

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