scratch_cloud_server/
lib.rs1use futures_util::SinkExt;
2use futures_util::StreamExt;
3use tokio::net::TcpStream;
4use tokio_tungstenite::tungstenite::Message as WSMessage;
5
6pub mod messages;
7
8use messages::*;
9
10#[derive(Debug)]
11pub enum Error {
12 ExpectedTextMsg,
13 JSONError(serde_json::Error),
14 WSError(tokio_tungstenite::tungstenite::Error),
15}
16impl From<serde_json::Error> for Error {
17 fn from(value: serde_json::Error) -> Self {
18 Self::JSONError(value)
19 }
20}
21impl From<tokio_tungstenite::tungstenite::Error> for Error {
22 fn from(value: tokio_tungstenite::tungstenite::Error) -> Self {
23 Self::WSError(value)
24 }
25}
26
27pub struct CloudServerStream {
28 write:
29 futures_util::stream::SplitSink<tokio_tungstenite::WebSocketStream<TcpStream>, WSMessage>,
30 read: futures_util::stream::SplitStream<tokio_tungstenite::WebSocketStream<TcpStream>>,
31}
32impl CloudServerStream {
33 pub async fn from_tcp_stream(stream: TcpStream) -> Result<Self, Error> {
34 let ws_stream = tokio_tungstenite::accept_async(stream).await?;
35 let (write, read) = ws_stream.split();
36
37 Ok(Self { write, read })
38 }
39
40 pub async fn recv(&mut self) -> Result<Option<ServerboundMessage>, Error> {
41 let msg = match self.read.next().await {
42 Some(msg) => match msg? {
43 WSMessage::Text(msg) => msg.to_string(),
44 WSMessage::Close(msg) => {
45 match msg {
46 Some(msg) => println!("Closed with frame: {}", msg),
47 None => {}
48 }
49 return Ok(None);
50 }
51 _ => {
52 return Err(Error::ExpectedTextMsg);
53 }
54 },
55 None => {
56 return Ok(None);
57 }
58 };
59 Ok(Some(serde_json::from_str(&msg)?))
60 }
61
62 pub async fn send(&mut self, msg: ClientboundMessage) -> Result<(), Error> {
63 let value = serde_json::to_string(&msg)?;
64 self.write.send(WSMessage::Text(value.into())).await?;
65 Ok(())
66 }
67}