Skip to main content

rivetkit_client/drivers/
ws.rs

1use anyhow::{Context, Result};
2use futures_util::{SinkExt, StreamExt};
3use std::sync::Arc;
4use tokio::sync::mpsc;
5use tokio_tungstenite::tungstenite::Message;
6use tracing::debug;
7
8use crate::{
9	protocol::{codec, to_client, to_server},
10	EncodingKind,
11};
12
13use super::{
14	DriverConnectArgs, DriverConnection, DriverHandle, DriverStopReason, MessageToClient,
15	MessageToServer,
16};
17
18pub(crate) async fn connect(args: DriverConnectArgs) -> Result<DriverConnection> {
19	// Resolve gateway target (query targets are resolved by the gateway).
20	let target = args.remote_manager.gateway_target(&args.query).await?;
21
22	debug!(?target, "opening WebSocket connection to actor via gateway");
23
24	// Open WebSocket via remote manager (gateway)
25	let ws = args
26		.remote_manager
27		.open_websocket(
28			&target,
29			args.encoding_kind,
30			args.parameters,
31			args.conn_id,
32			args.conn_token,
33		)
34		.await
35		.context("Failed to connect to WebSocket via gateway")?;
36
37	let (in_tx, in_rx) = mpsc::unbounded_channel::<MessageToClient>();
38	let (out_tx, out_rx) = mpsc::unbounded_channel::<MessageToServer>();
39
40	let task = tokio::spawn(start(ws, args.encoding_kind, in_tx, out_rx));
41	let handle = DriverHandle::new(out_tx, task.abort_handle());
42
43	Ok((handle, in_rx, task))
44}
45
46async fn start(
47	ws: tokio_tungstenite::WebSocketStream<
48		tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>,
49	>,
50	encoding_kind: EncodingKind,
51	in_tx: mpsc::UnboundedSender<MessageToClient>,
52	mut out_rx: mpsc::UnboundedReceiver<MessageToServer>,
53) -> DriverStopReason {
54	let (mut ws_sink, mut ws_stream) = ws.split();
55
56	let serialize = get_msg_serializer(encoding_kind);
57	let deserialize = get_msg_deserializer(encoding_kind);
58
59	loop {
60		tokio::select! {
61			// Dispatch ws outgoing queue
62			msg = out_rx.recv() => {
63				// If the sender is dropped, break the loop
64				let Some(msg) = msg else {
65					debug!("Sender dropped");
66					return DriverStopReason::UserAborted;
67				};
68
69				let msg = match serialize(&msg) {
70					Ok(msg) => msg,
71					Err(e) => {
72						debug!("Failed to serialize message: {:?}", e);
73						continue;
74					}
75				};
76
77				if let Err(e) = ws_sink.send(msg).await {
78					debug!("Failed to send message: {:?}", e);
79					continue;
80				}
81			},
82			// Handle ws incoming
83			msg = ws_stream.next() => {
84				let Some(msg) = msg else {
85					debug!("Receiver dropped");
86					return DriverStopReason::ServerDisconnect;
87				};
88
89				match msg {
90					Ok(msg) => match msg {
91						Message::Text(_) | Message::Binary(_) => {
92							let Ok(msg) = deserialize(&msg) else {
93								debug!("Failed to parse message: {:?}", msg);
94								continue;
95							};
96
97							if let Err(e) = in_tx.send(Arc::new(msg)) {
98								debug!("Failed to send text message: {}", e);
99								// failure to send means user dropped incoming receiver
100								return DriverStopReason::UserAborted;
101							}
102						},
103						Message::Close(_) => {
104							debug!("Close message");
105							return DriverStopReason::ServerDisconnect;
106						},
107						_ => {
108							debug!("Invalid message type received");
109						}
110					}
111					Err(e) => {
112						debug!("WebSocket error: {}", e);
113						return DriverStopReason::ServerError;
114					}
115				}
116			}
117		}
118	}
119}
120
121fn get_msg_deserializer(
122	encoding_kind: EncodingKind,
123) -> fn(&Message) -> Result<to_client::ToClient> {
124	match encoding_kind {
125		EncodingKind::Json => json_msg_deserialize,
126		EncodingKind::Cbor => cbor_msg_deserialize,
127		EncodingKind::Bare => bare_msg_deserialize,
128	}
129}
130
131fn get_msg_serializer(encoding_kind: EncodingKind) -> fn(&to_server::ToServer) -> Result<Message> {
132	match encoding_kind {
133		EncodingKind::Json => json_msg_serialize,
134		EncodingKind::Cbor => cbor_msg_serialize,
135		EncodingKind::Bare => bare_msg_serialize,
136	}
137}
138
139fn json_msg_deserialize(value: &Message) -> Result<to_client::ToClient> {
140	match value {
141		Message::Text(text) => codec::decode_to_client(EncodingKind::Json, text.as_bytes()),
142		Message::Binary(bin) => codec::decode_to_client(EncodingKind::Json, bin),
143		_ => Err(anyhow::anyhow!("Invalid message type")),
144	}
145}
146
147fn cbor_msg_deserialize(value: &Message) -> Result<to_client::ToClient> {
148	match value {
149		Message::Binary(bin) => codec::decode_to_client(EncodingKind::Cbor, bin),
150		Message::Text(text) => codec::decode_to_client(EncodingKind::Cbor, text.as_bytes()),
151		_ => Err(anyhow::anyhow!("Invalid message type")),
152	}
153}
154
155fn json_msg_serialize(value: &to_server::ToServer) -> Result<Message> {
156	let payload = codec::encode_to_server(EncodingKind::Json, value)?;
157	Ok(Message::Text(String::from_utf8(payload)?.into()))
158}
159
160fn cbor_msg_serialize(value: &to_server::ToServer) -> Result<Message> {
161	Ok(Message::Binary(
162		codec::encode_to_server(EncodingKind::Cbor, value)?.into(),
163	))
164}
165
166fn bare_msg_deserialize(value: &Message) -> Result<to_client::ToClient> {
167	match value {
168		Message::Binary(bin) => codec::decode_to_client(EncodingKind::Bare, bin),
169		Message::Text(text) => codec::decode_to_client(EncodingKind::Bare, text.as_bytes()),
170		_ => Err(anyhow::anyhow!("Invalid message type")),
171	}
172}
173
174fn bare_msg_serialize(value: &to_server::ToServer) -> Result<Message> {
175	Ok(Message::Binary(
176		codec::encode_to_server(EncodingKind::Bare, value)?.into(),
177	))
178}