1use futures_util::{SinkExt, StreamExt};
21#[cfg(feature = "ws")]
22use tokio::net::TcpStream;
23#[cfg(feature = "ws")]
24use tokio_tungstenite::{
25 MaybeTlsStream, WebSocketStream,
26 tungstenite::{
27 Message,
28 protocol::{CloseFrame, frame::coding::CloseCode},
29 },
30};
31#[cfg(feature = "wasm")]
32use tokio_tungstenite_wasm::{Message, WebSocketStream};
33#[cfg(any(feature = "ws", feature = "wasm"))]
34use tracing::debug;
35use worterbuch_common::{ClientMessage, ServerMessage, error::ConnectionResult};
36
37pub struct WsClientSocket {
38 #[cfg(feature = "ws")]
39 websocket: WebSocketStream<MaybeTlsStream<TcpStream>>,
40 #[cfg(feature = "wasm")]
41 websocket: WebSocketStream,
42}
43
44impl WsClientSocket {
45 #[cfg(feature = "ws")]
46 pub fn new(websocket: WebSocketStream<MaybeTlsStream<TcpStream>>) -> Self {
47 Self { websocket }
48 }
49
50 #[cfg(feature = "wasm")]
51 pub fn new(websocket: WebSocketStream) -> Self {
52 Self { websocket }
53 }
54
55 pub async fn send_msg(&mut self, msg: &ClientMessage) -> ConnectionResult<()> {
56 let json = serde_json::to_string(msg)?;
57 debug!("Sending message: {json}");
58 let msg = Message::Text(json.into());
59 self.websocket.send(msg).await?;
60 Ok(())
61 }
62
63 pub async fn receive_msg(&mut self) -> ConnectionResult<Option<ServerMessage>> {
64 match self.websocket.next().await {
65 Some(Ok(Message::Text(json))) => {
66 debug!("Received message: {json}");
67 let msg = serde_json::from_str(&json)?;
68 Ok(Some(msg))
69 }
70 Some(Err(e)) => Err(e.into()),
71 Some(Ok(_)) | None => Ok(None),
72 }
73 }
74
75 pub async fn close(mut self) -> ConnectionResult<()> {
76 #[cfg(feature = "ws")]
77 self.websocket
78 .close(Some(CloseFrame {
79 code: CloseCode::Normal,
80 reason: "client closed".into(),
81 }))
82 .await?;
83
84 #[cfg(feature = "wasm")]
85 self.websocket.close().await?;
86
87 Ok(())
88 }
89}