use futures_util::StreamExt;
use std::future::Future;
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
use ws_reconnect_client::MessageStream;
use crate::{Result, websocket::WebSocketMessage};
const MAX_RECONNECTION_ATTEMPTS: u32 = 10;
const BASE_BACKOFF_DELAY_MS: u64 = 1000; const MAX_BACKOFF_DELAY_MS: u64 = 60000;
pub(crate) fn spawn_forwarding_task_with_reconnect<F, Fut>(
message_stream: MessageStream<WebSocketMessage>,
tx: mpsc::UnboundedSender<Result<WebSocketMessage>>,
channel_name: &'static str,
reconnect_fn: F,
) -> JoinHandle<()>
where
F: Fn() -> Fut + Send + 'static,
Fut: Future<Output = Result<MessageStream<WebSocketMessage>>> + Send + 'static,
{
tokio::spawn(async move {
let mut current_stream = message_stream;
let mut reconnect_attempt = 0u32;
loop {
match current_stream.next().await {
Some(msg_result) => {
match msg_result {
Ok(msg) => {
reconnect_attempt = 0;
if tx.send(Ok(msg)).is_err() {
break;
}
}
Err(e) => {
eprintln!(
"❌ {} WebSocket error: {}, triggering reconnection",
channel_name, e
);
reconnect_attempt += 1;
if reconnect_attempt > MAX_RECONNECTION_ATTEMPTS {
eprintln!(
"❌ {} WebSocket: Max reconnection attempts ({}) exceeded",
channel_name, MAX_RECONNECTION_ATTEMPTS
);
break;
}
let delay_ms = (BASE_BACKOFF_DELAY_MS * 2u64.pow(reconnect_attempt - 1))
.min(MAX_BACKOFF_DELAY_MS);
eprintln!(
"⏳ {} WebSocket: Reconnecting in {}ms (attempt {}/{})",
channel_name, delay_ms, reconnect_attempt, MAX_RECONNECTION_ATTEMPTS
);
tokio::time::sleep(tokio::time::Duration::from_millis(delay_ms)).await;
eprintln!("🔄 {} WebSocket: Attempting to reconnect...", channel_name);
match reconnect_fn().await {
Ok(new_stream) => {
current_stream = new_stream;
eprintln!("✅ {} WebSocket: Reconnected successfully", channel_name);
}
Err(e) => {
eprintln!(
"❌ {} WebSocket: Reconnection attempt {} failed: {}",
channel_name, reconnect_attempt, e
);
}
}
}
}
}
None => {
reconnect_attempt += 1;
if reconnect_attempt > MAX_RECONNECTION_ATTEMPTS {
eprintln!(
"❌ {} WebSocket: Max reconnection attempts ({}) exceeded",
channel_name, MAX_RECONNECTION_ATTEMPTS
);
break;
}
let delay_ms = (BASE_BACKOFF_DELAY_MS * 2u64.pow(reconnect_attempt - 1))
.min(MAX_BACKOFF_DELAY_MS);
eprintln!(
"⏳ {} WebSocket: Reconnecting in {}ms (attempt {}/{})",
channel_name, delay_ms, reconnect_attempt, MAX_RECONNECTION_ATTEMPTS
);
tokio::time::sleep(tokio::time::Duration::from_millis(delay_ms)).await;
eprintln!("🔄 {} WebSocket: Attempting to reconnect...", channel_name);
match reconnect_fn().await {
Ok(new_stream) => {
current_stream = new_stream;
eprintln!("✅ {} WebSocket: Reconnected successfully", channel_name);
}
Err(e) => {
eprintln!(
"❌ {} WebSocket: Reconnection attempt {} failed: {}",
channel_name, reconnect_attempt, e
);
}
}
}
}
}
})
}