aboutsummaryrefslogtreecommitdiff
path: root/azalea-protocol/src/lib.rs
blob: 58ffac0ab5d9003ae4d6dade9b52328a5744260f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! This lib is responsible for parsing Minecraft packets.

// these two are necessary for thiserror backtraces
#![feature(error_generic_member_access)]
#![feature(provide_any)]

use std::net::IpAddr;
use std::str::FromStr;

#[cfg(feature = "connecting")]
pub mod connect;
#[cfg(feature = "packets")]
pub mod packets;
pub mod read;
pub mod resolver;
pub mod write;

#[derive(Debug)]
pub struct ServerAddress {
    pub host: String,
    pub port: u16,
}

#[derive(Debug)]
pub struct ServerIpAddress {
    pub ip: IpAddr,
    pub port: u16,
}

// impl try_from for ServerAddress
impl<'a> TryFrom<&'a str> for ServerAddress {
    type Error = String;

    /// Convert a Minecraft server address (host:port, the port is optional) to a ServerAddress
    fn try_from(string: &str) -> Result<Self, Self::Error> {
        if string.is_empty() {
            return Err("Empty string".to_string());
        }
        let mut parts = string.split(':');
        let host = parts.next().ok_or("No host specified")?.to_string();
        // default the port to 25565
        let port = parts.next().unwrap_or("25565");
        let port = u16::from_str(port).map_err(|_| "Invalid port specified")?;
        Ok(ServerAddress { host, port })
    }
}

#[cfg(feature = "connecting")]
pub async fn connect(address: ServerAddress) -> Result<(), Box<dyn std::error::Error>> {
    use log::debug;

    let resolved_address = resolver::resolve_address(&address).await;
    debug!("Resolved address: {:?}", resolved_address);
    Ok(())
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use crate::{
        packets::login::{
            serverbound_hello_packet::{ProfilePublicKeyData, ServerboundHelloPacket},
            ServerboundLoginPacket,
        },
        read::read_packet,
        write::write_packet,
    };
    use bytes::BytesMut;
    use uuid::Uuid;

    #[tokio::test]
    async fn test_hello_packet() {
        let packet = ServerboundHelloPacket {
            username: "test".to_string(),
            public_key: Some(ProfilePublicKeyData {
                expires_at: 0,
                key: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
                key_signature: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
            }),
            profile_id: Some(Uuid::from_u128(0)),
        }
        .get();
        let mut stream = Vec::new();
        write_packet(&packet, &mut stream, None, &mut None)
            .await
            .unwrap();

        let mut stream = Cursor::new(stream);

        let _ = read_packet::<ServerboundLoginPacket, _>(
            &mut stream,
            &mut BytesMut::new(),
            None,
            &mut None,
        )
        .await
        .unwrap();
    }

    #[tokio::test]
    async fn test_double_hello_packet() {
        let packet = ServerboundHelloPacket {
            username: "test".to_string(),
            public_key: Some(ProfilePublicKeyData {
                expires_at: 0,
                key: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
                key_signature: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
            }),
            profile_id: Some(Uuid::from_u128(0)),
        }
        .get();
        let mut stream = Vec::new();
        write_packet(&packet, &mut stream, None, &mut None)
            .await
            .unwrap();
        write_packet(&packet, &mut stream, None, &mut None)
            .await
            .unwrap();
        let mut stream = Cursor::new(stream);

        let mut buffer = BytesMut::new();

        let _ = read_packet::<ServerboundLoginPacket, _>(&mut stream, &mut buffer, None, &mut None)
            .await
            .unwrap();
        let _ = read_packet::<ServerboundLoginPacket, _>(&mut stream, &mut buffer, None, &mut None)
            .await
            .unwrap();
    }
}