minechat_protocol/
packets.rs

1use crate::protocol::*;
2use log::trace;
3use tokio::{
4    io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader},
5    net::TcpStream,
6};
7use uuid::Uuid;
8
9/// Sends a message to the server.
10///
11/// # Arguments
12///
13/// * `writer` - A mutable reference to an asynchronous writer.
14/// * `msg` - A reference to the message to be sent.
15///
16/// # Returns
17///
18/// * `Result<(), MineChatError>` - Returns `Ok(())` if the message is sent successfully, otherwise
19///   returns an error.
20pub async fn send_message<W>(writer: &mut W, msg: &MineChatMessage) -> Result<(), MineChatError>
21where
22    W: AsyncWrite + Unpin,
23{
24    trace!("Serializing message {:?}", msg);
25    let json = serde_json::to_string(msg)? + "\n";
26    trace!("Sending message to server");
27    writer.write_all(json.as_bytes()).await?;
28    Ok(())
29}
30
31/// Receives a message from the server.
32///
33/// # Arguments
34///
35/// * `reader` - A mutable reference to an asynchronous reader.
36///
37/// # Returns
38///
39/// * `Result<MineChatMessage, MineChatError>` - Returns the received message if successful,
40///   otherwise returns an error.
41pub async fn receive_message<R>(reader: &mut R) -> Result<MineChatMessage, MineChatError>
42where
43    R: AsyncBufRead + Unpin,
44{
45    let mut line = String::new();
46    reader.read_line(&mut line).await?;
47    Ok(serde_json::from_str(&line)?)
48}
49
50/// Handles linking with the server.
51///
52/// # Arguments
53///
54/// * `server_addr` - The address of the server to connect to.
55/// * `code` - The link code to authenticate with the server.
56///
57/// # Returns
58/// * `Result<(String, String), MineChatError>` - Returns a tuple containing the client UUID and
59///   server address if linking is successful, otherwise returns an error.
60pub async fn link_with_server(
61    server_addr: impl AsRef<str>,
62    code: impl AsRef<str>,
63) -> Result<(String, String), MineChatError> {
64    let addr = server_addr.as_ref();
65    let link_code = code.as_ref();
66
67    handle_link(addr, link_code).await
68}
69
70/// Handles linking with the server. The same as link_with_server.
71///
72/// Deprecated, use link_with_server instead, as it has a more descriptive and self-explaining name.
73#[deprecated(since = "0.1.1", note = "use link_with_server instead")]
74pub async fn handle_link(server_addr: &str, code: &str) -> Result<(String, String), MineChatError> {
75    let client_uuid = Uuid::new_v4().to_string();
76    trace!("Connecting to server {}", server_addr);
77
78    let mut stream = TcpStream::connect(server_addr).await?;
79    let (reader, mut writer) = stream.split();
80
81    trace!("Connected to server");
82
83    let mut reader = BufReader::new(reader);
84
85    trace!("Sending message to server {}", server_addr);
86    send_message(
87        &mut writer,
88        &MineChatMessage::Auth {
89            payload: AuthPayload {
90                client_uuid: client_uuid.clone(),
91                link_code: code.to_string(),
92            },
93        },
94    )
95    .await?;
96
97    match receive_message(&mut reader).await? {
98        MineChatMessage::AuthAck { payload } => {
99            if payload.status != "success" {
100                return Err(MineChatError::AuthFailed(payload.message));
101            }
102            trace!("Linked successfully: {}", payload.message);
103            Ok((client_uuid, server_addr.to_string()))
104        }
105        _ => Err(MineChatError::AuthFailed("Unexpected response".into())),
106    }
107}