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::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}