use std::{sync::Arc, time::Duration};
use bytes::Bytes;
use engineioxide::{
Str,
config::EngineIoConfig,
handler::EngineIoHandler,
service::EngineIoService,
socket::{DisconnectReason, Socket},
};
use tokio::sync::mpsc;
mod fixture;
use fixture::{create_polling_connection, send_req_raw};
#[derive(Debug, Clone)]
struct SocketHandler {
socket_tx: mpsc::Sender<Arc<Socket<()>>>,
}
impl EngineIoHandler for SocketHandler {
type Data = ();
fn on_connect(self: Arc<Self>, socket: Arc<Socket<()>>) {
self.socket_tx.try_send(socket).unwrap();
}
fn on_disconnect(&self, _socket: Arc<Socket<()>>, _reason: DisconnectReason) {}
fn on_message(self: &Arc<Self>, _msg: Str, _socket: Arc<Socket<()>>) {}
fn on_binary(self: &Arc<Self>, _data: Bytes, _socket: Arc<Socket<()>>) {}
}
async fn create_small_payload_server(
max_payload: u64,
) -> (
EngineIoService<SocketHandler>,
mpsc::Receiver<Arc<Socket<()>>>,
) {
let (socket_tx, socket_rx) = mpsc::channel(1);
let config = EngineIoConfig::builder()
.ping_interval(Duration::from_secs(60))
.ping_timeout(Duration::from_secs(60))
.max_payload(max_payload)
.build();
let svc = EngineIoService::with_config(Arc::new(SocketHandler { socket_tx }), config);
(svc, socket_rx)
}
async fn drain_initial_ping<H: EngineIoHandler>(svc: &mut EngineIoService<H>, sid: &str) {
let ping = poll(svc, sid).await;
assert_eq!(ping, "2", "expected the initial heartbeat ping");
}
async fn poll<H: EngineIoHandler>(svc: &mut EngineIoService<H>, sid: &str) -> String {
let fut = send_req_raw(
svc,
format!("transport=polling&sid={sid}"),
http::Method::GET,
None,
);
tokio::time::timeout(Duration::from_secs(1), fut)
.await
.expect("polling request timed out (a peeked packet was likely lost)")
}
#[tokio::test]
async fn polling_peeked_packet_sent_on_next_poll() {
let (mut svc, mut socket_rx) = create_small_payload_server(10).await;
let sid = create_polling_connection(&mut svc).await;
let socket = socket_rx.recv().await.unwrap();
drain_initial_ping(&mut svc, &sid).await;
socket.emit("hello").unwrap();
socket.emit("world").unwrap();
assert_eq!(poll(&mut svc, &sid).await, "4hello");
assert_eq!(poll(&mut svc, &sid).await, "4world");
}
#[tokio::test]
async fn polling_peeked_packets_preserve_order() {
let (mut svc, mut socket_rx) = create_small_payload_server(10).await;
let sid = create_polling_connection(&mut svc).await;
let socket = socket_rx.recv().await.unwrap();
drain_initial_ping(&mut svc, &sid).await;
socket.emit("hello").unwrap();
socket.emit("world").unwrap();
socket.emit("there").unwrap();
assert_eq!(poll(&mut svc, &sid).await, "4hello");
assert_eq!(poll(&mut svc, &sid).await, "4world");
assert_eq!(poll(&mut svc, &sid).await, "4there");
}