use std::net::TcpStream;
use tungstenite::{Message, WebSocket, client::connect as ws_connect, stream::MaybeTlsStream};
use crate::error::BlinkError;
pub const WS_POLL_INTERVAL_MS: u64 = 5;
type Sock = WebSocket<MaybeTlsStream<TcpStream>>;
pub struct WsClient {
socket: Sock,
}
impl WsClient {
pub fn connect(url: &str) -> Result<Self, BlinkError> {
tracing::debug!(url, "connecting CDP WebSocket");
let (socket, _response) =
ws_connect(url).map_err(|e| BlinkError::WsConnect(e.to_string()))?;
Ok(Self { socket })
}
pub fn send_text(&mut self, text: String) -> Result<(), BlinkError> {
self.socket
.send(Message::Text(text))
.map_err(|e| BlinkError::WsIo(e.to_string()))
}
pub fn recv_text(&mut self) -> Result<String, BlinkError> {
loop {
match self.socket.read() {
Ok(Message::Text(t)) => return Ok(t.to_string()),
Ok(Message::Binary(b)) => {
return String::from_utf8(b)
.map_err(|e| BlinkError::WsIo(format!("binary frame utf8: {e}")));
}
Ok(Message::Ping(_) | Message::Pong(_)) => continue,
Ok(Message::Close(_)) => {
return Err(BlinkError::WsIo("connection closed by server".into()));
}
Ok(Message::Frame(_)) => continue,
Err(e) => return Err(BlinkError::WsIo(e.to_string())),
}
}
}
pub fn try_recv_text(&mut self) -> Result<Option<String>, BlinkError> {
use std::time::Duration;
use tungstenite::stream::MaybeTlsStream;
let timeout = Some(Duration::from_millis(WS_POLL_INTERVAL_MS));
let set_ok = match self.socket.get_mut() {
MaybeTlsStream::Plain(tcp) => tcp.set_read_timeout(timeout).is_ok(),
_ => false, };
let result = match self.socket.read() {
Ok(Message::Text(t)) => Ok(Some(t.to_string())),
Ok(Message::Binary(b)) => String::from_utf8(b)
.map(Some)
.map_err(|e| BlinkError::WsIo(format!("binary frame utf8: {e}"))),
Ok(Message::Ping(_) | Message::Pong(_) | Message::Frame(_)) => Ok(None),
Ok(Message::Close(_)) => Err(BlinkError::WsIo("connection closed by server".into())),
Err(tungstenite::Error::Io(ref io_err))
if io_err.kind() == std::io::ErrorKind::WouldBlock
|| io_err.kind() == std::io::ErrorKind::TimedOut =>
{
Ok(None)
}
Err(e) => Err(BlinkError::WsIo(e.to_string())),
};
if set_ok && let MaybeTlsStream::Plain(tcp) = self.socket.get_mut() {
let _ = tcp.set_read_timeout(None);
}
result
}
}