Skip to main content

rivetkit_client/
connection.rs

1use anyhow::Result;
2use futures_util::FutureExt;
3use parking_lot::Mutex as SyncMutex;
4use scc::{hash_map::Entry as SccEntry, HashMap as SccHashMap};
5use serde_json::Value;
6use std::fmt::{Debug, Display};
7use std::ops::Deref;
8use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
9use std::sync::{Arc, Weak};
10use std::time::Duration;
11use tokio::sync::{broadcast, oneshot, watch, Mutex};
12
13use crate::{
14	backoff::Backoff,
15	drivers::*,
16	protocol::{query::ActorQuery, *},
17	remote_manager::RemoteManager,
18	EncodingKind, TransportKind,
19};
20use tracing::debug;
21
22type RpcResponse = Result<to_client::ActionResponse, to_client::Error>;
23type EventCallback = dyn Fn(Event) + Send + Sync;
24type VoidCallback = dyn Fn() + Send + Sync;
25type ErrorCallback = dyn Fn(&str) + Send + Sync;
26type StatusCallback = dyn Fn(ConnectionStatus) + Send + Sync;
27
28#[derive(Debug, Clone)]
29pub struct Event {
30	pub name: String,
31	pub args: Vec<Value>,
32	pub raw_args: Vec<u8>,
33}
34
35struct EventSubscription {
36	id: u64,
37	callback: Box<EventCallback>,
38}
39
40#[derive(Clone)]
41pub struct SubscriptionHandle {
42	inner: Arc<SubscriptionHandleInner>,
43}
44
45struct SubscriptionHandleInner {
46	conn: Weak<ActorConnectionInner>,
47	event_name: String,
48	id: u64,
49	active: AtomicBool,
50}
51
52impl SubscriptionHandle {
53	fn new(conn: &Arc<ActorConnectionInner>, event_name: String, id: u64) -> Self {
54		Self {
55			inner: Arc::new(SubscriptionHandleInner {
56				conn: Arc::downgrade(conn),
57				event_name,
58				id,
59				active: AtomicBool::new(true),
60			}),
61		}
62	}
63
64	pub async fn unsubscribe(&self) {
65		if !self.inner.active.swap(false, Ordering::SeqCst) {
66			return;
67		}
68
69		let Some(conn) = self.inner.conn.upgrade() else {
70			return;
71		};
72
73		conn.remove_event_subscription(&self.inner.event_name, self.inner.id)
74			.await;
75	}
76}
77
78struct SendMsgOpts {
79	ephemeral: bool,
80}
81
82impl Default for SendMsgOpts {
83	fn default() -> Self {
84		Self { ephemeral: false }
85	}
86}
87
88type WatchPair = (watch::Sender<bool>, watch::Receiver<bool>);
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub enum ConnectionStatus {
92	Idle,
93	Connecting,
94	Connected,
95	Disconnected,
96}
97
98pub type ActorConnection = Arc<ActorConnectionInner>;
99
100struct ConnectionAttempt {
101	did_open: bool,
102	task_end_reason: DriverStopReason,
103}
104
105pub struct ActorConnectionInner {
106	remote_manager: RemoteManager,
107	transport_kind: TransportKind,
108	encoding_kind: EncodingKind,
109	query: ActorQuery,
110	parameters: Option<Value>,
111
112	driver: Mutex<Option<DriverHandle>>,
113	msg_queue: Mutex<Vec<Arc<to_server::ToServer>>>,
114
115	rpc_counter: AtomicU64,
116	event_subscription_counter: AtomicU64,
117	in_flight_rpcs: SccHashMap<u64, oneshot::Sender<RpcResponse>>,
118
119	event_subscriptions: SccHashMap<String, Vec<Arc<EventSubscription>>>,
120	on_open_callbacks: Mutex<Vec<Box<VoidCallback>>>,
121	on_close_callbacks: Mutex<Vec<Box<VoidCallback>>>,
122	on_error_callbacks: Mutex<Vec<Box<ErrorCallback>>>,
123	on_status_change_callbacks: Mutex<Vec<Box<StatusCallback>>>,
124
125	// Connection info for reconnection
126	actor_id: Mutex<Option<String>>,
127	connection_id: Mutex<Option<String>>,
128	connection_token: Mutex<Option<String>>,
129
130	dc_watch: WatchPair,
131	stop_error: Mutex<Option<StopError>>,
132	status_watch: (
133		watch::Sender<ConnectionStatus>,
134		watch::Receiver<ConnectionStatus>,
135	),
136	disconnection_rx: Mutex<Option<oneshot::Receiver<()>>>,
137}
138
139impl ActorConnectionInner {
140	pub(crate) fn new(
141		remote_manager: RemoteManager,
142		query: ActorQuery,
143		transport_kind: TransportKind,
144		encoding_kind: EncodingKind,
145		parameters: Option<Value>,
146	) -> ActorConnection {
147		Arc::new(Self {
148			remote_manager,
149			transport_kind,
150			encoding_kind,
151			query,
152			parameters,
153			driver: Mutex::new(None),
154			msg_queue: Mutex::new(Vec::new()),
155			rpc_counter: AtomicU64::new(0),
156			event_subscription_counter: AtomicU64::new(0),
157			in_flight_rpcs: SccHashMap::new(),
158			event_subscriptions: SccHashMap::new(),
159			on_open_callbacks: Mutex::new(Vec::new()),
160			on_close_callbacks: Mutex::new(Vec::new()),
161			on_error_callbacks: Mutex::new(Vec::new()),
162			on_status_change_callbacks: Mutex::new(Vec::new()),
163			actor_id: Mutex::new(None),
164			connection_id: Mutex::new(None),
165			connection_token: Mutex::new(None),
166			dc_watch: watch::channel(false),
167			stop_error: Mutex::new(None),
168			status_watch: watch::channel(ConnectionStatus::Idle),
169			disconnection_rx: Mutex::new(None),
170		})
171	}
172
173	fn is_disconnecting(self: &Arc<Self>) -> bool {
174		*self.dc_watch.1.borrow() == true
175	}
176
177	async fn try_connect(self: &Arc<Self>) -> ConnectionAttempt {
178		self.set_status(ConnectionStatus::Connecting).await;
179
180		// Get connection info for reconnection
181		let conn_id = self.connection_id.lock().await.clone();
182		let conn_token = self.connection_token.lock().await.clone();
183
184		let (driver, mut recver, task) = match connect_driver(
185			self.transport_kind,
186			DriverConnectArgs {
187				remote_manager: self.remote_manager.clone(),
188				query: self.query.clone(),
189				encoding_kind: self.encoding_kind,
190				parameters: self.parameters.clone(),
191				conn_id,
192				conn_token,
193			},
194		)
195		.await
196		{
197			Ok(value) => value,
198			Err(error) => {
199				let message = error.to_string();
200				self.emit_error(&message).await;
201				self.set_status(ConnectionStatus::Disconnected).await;
202				return ConnectionAttempt {
203					did_open: false,
204					task_end_reason: DriverStopReason::TaskError,
205				};
206			}
207		};
208
209		{
210			let mut my_driver = self.driver.lock().await;
211			*my_driver = Some(driver);
212		}
213
214		let mut task_end_reason = task.map(|res| match res {
215			Ok(a) => a,
216			Err(task_err) => {
217				if task_err.is_cancelled() {
218					debug!("Connection task was cancelled");
219					DriverStopReason::UserAborted
220				} else {
221					DriverStopReason::TaskError
222				}
223			}
224		});
225
226		let mut did_connection_open = false;
227
228		// spawn listener for rpcs
229		let task_end_reason = loop {
230			tokio::select! {
231				reason = &mut task_end_reason => {
232					debug!("Connection closed: {:?}", reason);
233
234					break reason;
235				},
236				msg = recver.recv() => {
237					// If the sender is dropped, break the loop
238					let Some(msg) = msg else {
239						// break DriverStopReason::ServerDisconnect;
240						continue;
241					};
242
243					if let to_client::ToClientBody::Init(_) = &msg.body {
244						did_connection_open = true;
245					}
246
247					self.on_message(msg).await;
248				}
249			}
250		};
251
252		'destroy_driver: {
253			debug!("Destroying driver");
254			let mut d_guard = self.driver.lock().await;
255			let Some(d) = d_guard.take() else {
256				// We destroyed the driver already,
257				// e.g. .disconnect() was called
258				break 'destroy_driver;
259			};
260
261			d.disconnect();
262		}
263
264		self.set_status(ConnectionStatus::Disconnected).await;
265		self.emit_close().await;
266
267		ConnectionAttempt {
268			did_open: did_connection_open,
269			task_end_reason,
270		}
271	}
272
273	async fn handle_open(self: &Arc<Self>, init: &to_client::Init) {
274		debug!("Connected to server: {:?}", init);
275
276		// Store connection info for reconnection
277		*self.actor_id.lock().await = Some(init.actor_id.clone());
278		*self.connection_id.lock().await = Some(init.connection_id.clone());
279		*self.connection_token.lock().await = init.connection_token.clone();
280		self.set_status(ConnectionStatus::Connected).await;
281		self.emit_open().await;
282
283		let mut event_names = Vec::new();
284		self.event_subscriptions
285			.iter_async(|event_name, _| {
286				event_names.push(event_name.clone());
287				true
288			})
289			.await;
290		for event_name in event_names {
291			self.send_subscription(event_name.clone(), true).await;
292		}
293
294		// Flush message queue
295		for msg in self.msg_queue.lock().await.drain(..) {
296			// If its in the queue, it isn't ephemeral, so we pass
297			// default SendMsgOpts
298			self.send_msg(msg, SendMsgOpts::default()).await;
299		}
300	}
301
302	async fn on_message(self: &Arc<Self>, msg: Arc<to_client::ToClient>) {
303		let body = &msg.body;
304
305		match body {
306			to_client::ToClientBody::Init(init) => {
307				self.handle_open(init).await;
308			}
309			to_client::ToClientBody::ActionResponse(ar) => {
310				let id = ar.id;
311				let Some((_, tx)) = self.in_flight_rpcs.remove_async(&id).await else {
312					debug!("Unexpected response: rpc id not found");
313					return;
314				};
315				if let Err(e) = tx.send(Ok(ar.clone())) {
316					debug!("{:?}", e);
317					return;
318				}
319			}
320			to_client::ToClientBody::Event(ev) => {
321				let args = decode_event_args(&ev.args);
322
323				let callbacks = {
324					self.event_subscriptions
325						.read_async(&ev.name, |_, listeners| listeners.clone())
326						.await
327						.unwrap_or_default()
328				};
329				let event = Event {
330					name: ev.name.clone(),
331					args,
332					raw_args: ev.args.clone(),
333				};
334				for subscription in callbacks {
335					(subscription.callback)(event.clone());
336				}
337			}
338			to_client::ToClientBody::Error(e) => {
339				if let Some(action_id) = e.action_id {
340					let Some((_, tx)) = self.in_flight_rpcs.remove_async(&action_id).await else {
341						debug!("Unexpected response: rpc id not found");
342						return;
343					};
344					if let Err(e) = tx.send(Err(e.clone())) {
345						debug!("{:?}", e);
346						return;
347					}
348
349					return;
350				}
351
352				debug!("Connection error: {} - {}", e.code, e.message);
353				self.emit_error(&e.message).await;
354			}
355		}
356	}
357
358	async fn set_status(self: &Arc<Self>, status: ConnectionStatus) {
359		if *self.status_watch.1.borrow() == status {
360			return;
361		}
362		self.status_watch.0.send(status).ok();
363		for callback in self.on_status_change_callbacks.lock().await.iter() {
364			callback(status);
365		}
366	}
367
368	async fn emit_open(self: &Arc<Self>) {
369		for callback in self.on_open_callbacks.lock().await.iter() {
370			callback();
371		}
372	}
373
374	async fn emit_close(self: &Arc<Self>) {
375		for callback in self.on_close_callbacks.lock().await.iter() {
376			callback();
377		}
378	}
379
380	async fn emit_error(self: &Arc<Self>, message: &str) {
381		for callback in self.on_error_callbacks.lock().await.iter() {
382			callback(message);
383		}
384	}
385
386	async fn send_msg(self: &Arc<Self>, msg: Arc<to_server::ToServer>, opts: SendMsgOpts) {
387		let guard = self.driver.lock().await;
388
389		'send_immediately: {
390			let Some(driver) = guard.deref() else {
391				break 'send_immediately;
392			};
393
394			let Ok(_) = driver.send(msg.clone()).await else {
395				break 'send_immediately;
396			};
397
398			return;
399		}
400
401		// Otherwise queue
402		if opts.ephemeral == false {
403			self.msg_queue.lock().await.push(msg.clone());
404		}
405
406		return;
407	}
408
409	pub async fn action(self: &Arc<Self>, method: &str, params: Vec<Value>) -> Result<Value> {
410		if let Some(stop_error) = self.stop_error.lock().await.as_ref() {
411			return Err(stop_error.to_rpc_error());
412		}
413		let id: u64 = self.rpc_counter.fetch_add(1, Ordering::SeqCst);
414
415		let (tx, rx) = oneshot::channel();
416		if self.in_flight_rpcs.insert_async(id, tx).await.is_err() {
417			return Err(anyhow::anyhow!("duplicate rpc id"));
418		}
419		// A stop between the check above and the insert has already cleared the in-flight map, so
420		// this call would never be answered.
421		if let Some(stop_error) = self.stop_error.lock().await.as_ref() {
422			self.in_flight_rpcs.remove_async(&id).await;
423			return Err(stop_error.to_rpc_error());
424		}
425
426		// Encode params as CBOR
427		let args_cbor = serde_cbor::to_vec(&params)?;
428
429		self.send_msg(
430			Arc::new(to_server::ToServer {
431				body: to_server::ToServerBody::ActionRequest(to_server::ActionRequest {
432					id,
433					name: method.to_string(),
434					args: args_cbor,
435				}),
436			}),
437			SendMsgOpts::default(),
438		)
439		.await;
440
441		let Ok(res) = rx.await else {
442			if let Some(stop_error) = self.stop_error.lock().await.as_ref() {
443				return Err(stop_error.to_rpc_error());
444			}
445			return Err(anyhow::anyhow!("Socket closed during rpc"));
446		};
447
448		match res {
449			Ok(ok) => {
450				// Decode CBOR output
451				let output: Value = serde_cbor::from_slice(&ok.output)?;
452				Ok(output)
453			}
454			Err(err) => {
455				let metadata = if let Some(md) = &err.metadata {
456					match serde_cbor::from_slice::<Value>(md) {
457						Ok(v) => v,
458						Err(_) => Value::Null,
459					}
460				} else {
461					Value::Null
462				};
463
464				Err(anyhow::anyhow!(
465					"RPC Error({}/{}): {}, {:#}",
466					err.group,
467					err.code,
468					err.message,
469					metadata
470				))
471			}
472		}
473	}
474
475	async fn send_subscription(self: &Arc<Self>, event_name: String, subscribe: bool) {
476		self.send_msg(
477			Arc::new(to_server::ToServer {
478				body: to_server::ToServerBody::SubscriptionRequest(
479					to_server::SubscriptionRequest {
480						event_name,
481						subscribe,
482					},
483				),
484			}),
485			SendMsgOpts { ephemeral: true },
486		)
487		.await;
488	}
489
490	async fn add_event_subscription(
491		self: &Arc<Self>,
492		event_name: String,
493		callback: Box<EventCallback>,
494	) -> SubscriptionHandle {
495		let id = self
496			.event_subscription_counter
497			.fetch_add(1, Ordering::SeqCst);
498		let handle = SubscriptionHandle::new(self, event_name.clone(), id);
499
500		self.insert_event_subscription(event_name, id, callback)
501			.await;
502
503		handle
504	}
505
506	async fn insert_event_subscription(
507		self: &Arc<Self>,
508		event_name: String,
509		id: u64,
510		callback: Box<EventCallback>,
511	) {
512		let is_new_subscription = {
513			let mut listeners = self
514				.event_subscriptions
515				.entry_async(event_name.clone())
516				.await
517				.or_insert_with(Vec::new);
518			let is_new_subscription = listeners.is_empty();
519
520			listeners.push(Arc::new(EventSubscription { id, callback }));
521
522			is_new_subscription
523		};
524
525		if is_new_subscription {
526			self.send_subscription(event_name, true).await;
527		}
528	}
529
530	async fn remove_event_subscription(self: &Arc<Self>, event_name: &str, id: u64) {
531		let should_unsubscribe = {
532			match self
533				.event_subscriptions
534				.entry_async(event_name.to_string())
535				.await
536			{
537				SccEntry::Occupied(mut entry) => {
538					entry.retain(|subscription| subscription.id != id);
539					if entry.is_empty() {
540						let _ = entry.remove_entry();
541						true
542					} else {
543						false
544					}
545				}
546				SccEntry::Vacant(entry) => {
547					drop(entry);
548					false
549				}
550			}
551		};
552
553		if should_unsubscribe {
554			self.send_subscription(event_name.to_string(), false).await;
555		}
556	}
557
558	pub async fn on_event<F>(self: &Arc<Self>, event_name: &str, callback: F) -> SubscriptionHandle
559	where
560		F: Fn(&Vec<Value>) + Send + Sync + 'static,
561	{
562		self.add_event_subscription(
563			event_name.to_string(),
564			Box::new(move |event| callback(&event.args)),
565		)
566		.await
567	}
568
569	pub async fn on_event_raw<F>(
570		self: &Arc<Self>,
571		event_name: &str,
572		callback: F,
573	) -> SubscriptionHandle
574	where
575		F: Fn(Event) + Send + Sync + 'static,
576	{
577		self.add_event_subscription(event_name.to_string(), Box::new(callback))
578			.await
579	}
580
581	pub async fn once_event<F>(
582		self: &Arc<Self>,
583		event_name: &str,
584		callback: F,
585	) -> SubscriptionHandle
586	where
587		F: FnOnce(Event) + Send + 'static,
588	{
589		let id = self
590			.event_subscription_counter
591			.fetch_add(1, Ordering::SeqCst);
592		let handle = SubscriptionHandle::new(self, event_name.to_string(), id);
593		// Event callbacks are synchronous, so a FnOnce lives behind a short sync lock.
594		let callback = Arc::new(SyncMutex::new(Some(callback)));
595		let unsubscribe_handle = handle.clone();
596		let fired = Arc::new(AtomicBool::new(false));
597		self.insert_event_subscription(
598			event_name.to_string(),
599			id,
600			Box::new(move |event| {
601				if fired.swap(true, Ordering::SeqCst) {
602					return;
603				}
604
605				let unsubscribe_handle = unsubscribe_handle.clone();
606				tokio::spawn(async move {
607					unsubscribe_handle.unsubscribe().await;
608				});
609
610				let Some(callback) = callback.lock().take() else {
611					return;
612				};
613				callback(event);
614			}),
615		)
616		.await;
617
618		handle
619	}
620
621	pub async fn on_open<F>(self: &Arc<Self>, callback: F)
622	where
623		F: Fn() + Send + Sync + 'static,
624	{
625		self.on_open_callbacks.lock().await.push(Box::new(callback));
626	}
627
628	pub async fn on_close<F>(self: &Arc<Self>, callback: F)
629	where
630		F: Fn() + Send + Sync + 'static,
631	{
632		self.on_close_callbacks
633			.lock()
634			.await
635			.push(Box::new(callback));
636	}
637
638	pub async fn on_error<F>(self: &Arc<Self>, callback: F)
639	where
640		F: Fn(&str) + Send + Sync + 'static,
641	{
642		self.on_error_callbacks
643			.lock()
644			.await
645			.push(Box::new(callback));
646	}
647
648	pub async fn on_status_change<F>(self: &Arc<Self>, callback: F)
649	where
650		F: Fn(ConnectionStatus) + Send + Sync + 'static,
651	{
652		self.on_status_change_callbacks
653			.lock()
654			.await
655			.push(Box::new(callback));
656	}
657
658	pub fn conn_status(self: &Arc<Self>) -> ConnectionStatus {
659		*self.status_watch.1.borrow()
660	}
661
662	pub fn status_receiver(self: &Arc<Self>) -> watch::Receiver<ConnectionStatus> {
663		self.status_watch.1.clone()
664	}
665
666	pub async fn disconnect(self: &Arc<Self>) {
667		if self.is_disconnecting() {
668			// We are already disconnecting
669			return;
670		}
671
672		debug!("Disconnecting from actor conn");
673
674		self.dc_watch.0.send(true).ok();
675		self.set_status(ConnectionStatus::Disconnected).await;
676
677		if let Some(d) = self.driver.lock().await.deref() {
678			d.disconnect();
679		}
680		self.in_flight_rpcs.clear_async().await;
681		self.event_subscriptions.clear_async().await;
682		let Some(rx) = self.disconnection_rx.lock().await.take() else {
683			return;
684		};
685
686		rx.await.ok();
687	}
688
689	pub async fn dispose(self: &Arc<Self>) {
690		self.disconnect().await
691	}
692
693	async fn stop_permanently(self: &Arc<Self>, stop_error: StopError) {
694		let message = stop_error.to_string();
695		*self.stop_error.lock().await = Some(stop_error);
696		self.set_status(ConnectionStatus::Idle).await;
697		self.in_flight_rpcs.clear_async().await;
698		self.emit_error(&message).await;
699	}
700}
701
702#[derive(Debug, Clone)]
703struct StopError {
704	group: String,
705	code: String,
706	reason: String,
707}
708
709impl StopError {
710	fn from_close_reason(reason: &str) -> Self {
711		let group_code = reason.split('#').next().unwrap_or(reason);
712		let (group, code) = group_code.split_once('.').unwrap_or((group_code, ""));
713		Self {
714			group: group.to_owned(),
715			code: code.to_owned(),
716			reason: reason.to_owned(),
717		}
718	}
719
720	fn to_rpc_error(&self) -> anyhow::Error {
721		anyhow::anyhow!(
722			"RPC Error({}/{}): Connection closed: {}",
723			self.group,
724			self.code,
725			self.reason
726		)
727	}
728}
729
730impl Display for StopError {
731	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
732		write!(
733			f,
734			"{}.{}: Connection closed: {}",
735			self.group, self.code, self.reason
736		)
737	}
738}
739
740pub fn start_connection(
741	conn: &Arc<ActorConnectionInner>,
742	mut shutdown_rx: broadcast::Receiver<()>,
743) {
744	let (tx, rx) = oneshot::channel();
745
746	let conn = conn.clone();
747
748	tokio::spawn(async move {
749		{
750			let mut stop_rx = conn.disconnection_rx.lock().await;
751			if stop_rx.is_some() {
752				// Already doing connection_with_retry
753				// - this drops the oneshot
754				return;
755			}
756
757			*stop_rx = Some(rx);
758		}
759
760		'keepalive: loop {
761			debug!("Attempting to reconnect");
762			let mut backoff = Backoff::new(Duration::from_secs(1), Duration::from_secs(30));
763			let mut retry_attempt = 0;
764			'retry: loop {
765				retry_attempt += 1;
766				debug!(
767					"Establish conn: attempt={}, timeout={:?}",
768					retry_attempt,
769					backoff.delay()
770				);
771				let attempt = conn.try_connect().await;
772
773				if conn.is_disconnecting() {
774					break 'keepalive;
775				}
776
777				match &attempt.task_end_reason {
778					DriverStopReason::ActorDestroyed { reason } => {
779						conn.stop_permanently(StopError::from_close_reason(reason))
780							.await;
781						break 'keepalive;
782					}
783					// The client cannot refresh its token, so a refused connection would be refused
784					// again on every retry.
785					DriverStopReason::AuthRefused { reason } => {
786						conn.stop_permanently(StopError::from_close_reason(reason))
787							.await;
788						break 'keepalive;
789					}
790					DriverStopReason::ActorNotFound { reason } => {
791						let stops = match &conn.query {
792							ActorQuery::GetForId { .. } => true,
793							ActorQuery::GetForKey { .. } => !attempt.did_open,
794							ActorQuery::GetOrCreateForKey { .. } | ActorQuery::Create { .. } => {
795								false
796							}
797						};
798						if stops {
799							conn.stop_permanently(StopError::from_close_reason(reason))
800								.await;
801							break 'keepalive;
802						}
803					}
804					DriverStopReason::UserAborted
805					| DriverStopReason::ServerDisconnect
806					| DriverStopReason::ServerError
807					| DriverStopReason::TaskError => {}
808				}
809
810				if attempt.did_open {
811					break 'retry;
812				}
813
814				let mut dc_rx = conn.dc_watch.0.subscribe();
815
816				tokio::select! {
817					_ = backoff.tick() => {},
818					_ = dc_rx.wait_for(|x| *x == true) => {
819						break 'keepalive;
820					}
821					_ = shutdown_rx.recv() => {
822						debug!("Received shutdown signal, stopping connection attempts");
823						break 'keepalive;
824					}
825				}
826			}
827		}
828
829		tx.send(()).ok();
830		conn.disconnection_rx.lock().await.take();
831	});
832}
833
834impl Debug for ActorConnectionInner {
835	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
836		f.debug_struct("ActorConnection")
837			.field("transport_kind", &self.transport_kind)
838			.field("encoding_kind", &self.encoding_kind)
839			.finish()
840	}
841}
842
843fn decode_event_args(raw_args: &[u8]) -> Vec<Value> {
844	match serde_cbor::from_slice::<Vec<Value>>(raw_args) {
845		Ok(args) => args,
846		Err(vector_error) => match serde_cbor::from_slice::<Value>(raw_args) {
847			Ok(Value::Array(args)) => args,
848			Ok(value) => vec![value],
849			Err(value_error) => {
850				debug!(?vector_error, ?value_error, "failed to decode event args");
851				Vec::new()
852			}
853		},
854	}
855}