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