worterbuch_client/
ws.rs

1/*
2 *  Worterbuch client WebSocket module
3 *
4 *  Copyright (C) 2024 Michael Bachmann
5 *
6 *  This program is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU Affero General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU Affero General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Affero General Public License
17 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20use 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}