dust_devil_core/sandstorm/
handshake.rs1use std::io::{Error, ErrorKind};
2
3use tokio::io::{AsyncRead, AsyncWrite};
4
5use crate::{
6 serialize::{ByteRead, ByteWrite, SmallReadString, SmallWriteString},
7 u8_repr_enum::U8ReprEnum,
8};
9
10pub struct SandstormHandshake {
12 pub username: String,
14
15 pub password: String,
17}
18
19pub struct SandstormHandshakeRef<'a> {
21 pub username: &'a str,
23
24 pub password: &'a str,
26}
27
28pub enum ParseHandshakeError {
30 InvalidVersion(u8),
32
33 IO(Error),
35}
36
37impl From<Error> for ParseHandshakeError {
38 fn from(value: Error) -> Self {
39 ParseHandshakeError::IO(value)
40 }
41}
42
43impl SandstormHandshake {
44 pub fn new(username: String, password: String) -> Self {
45 Self { username, password }
46 }
47
48 pub fn as_ref(&self) -> SandstormHandshakeRef {
49 SandstormHandshakeRef {
50 username: &self.username,
51 password: &self.password,
52 }
53 }
54
55 pub async fn read_with_version_check<R: AsyncRead + Unpin + ?Sized>(reader: &mut R) -> Result<Self, ParseHandshakeError> {
56 let version = u8::read(reader).await?;
57 if version != 1 {
58 Err(ParseHandshakeError::InvalidVersion(version))
59 } else {
60 Ok(Self {
61 username: SmallReadString::read(reader).await?.0,
62 password: SmallReadString::read(reader).await?.0,
63 })
64 }
65 }
66}
67
68impl<'a> SandstormHandshakeRef<'a> {
69 pub fn new(username: &'a str, password: &'a str) -> Self {
70 Self { username, password }
71 }
72}
73
74impl ByteRead for SandstormHandshake {
75 async fn read<R: AsyncRead + Unpin + ?Sized>(reader: &mut R) -> Result<Self, Error> {
76 match Self::read_with_version_check(reader).await {
77 Ok(value) => Ok(value),
78 Err(ParseHandshakeError::InvalidVersion(version)) => {
79 Err(Error::new(ErrorKind::InvalidInput, format!("Invalid Sandstorm version: {version}")))
80 }
81 Err(ParseHandshakeError::IO(error)) => Err(error),
82 }
83 }
84}
85
86impl ByteWrite for SandstormHandshake {
87 async fn write<W: AsyncWrite + Unpin + ?Sized>(&self, writer: &mut W) -> Result<(), Error> {
88 self.as_ref().write(writer).await
89 }
90}
91
92impl<'a> ByteWrite for SandstormHandshakeRef<'a> {
93 async fn write<W: AsyncWrite + Unpin + ?Sized>(&self, writer: &mut W) -> Result<(), Error> {
94 (0x01u8, SmallWriteString(self.username), SmallWriteString(self.password))
95 .write(writer)
96 .await
97 }
98}
99
100#[repr(u8)]
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum SandstormHandshakeStatus {
104 Ok = 0x00,
106
107 UnsupportedVersion = 0x01,
109
110 InvalidUsernameOrPassword = 0x02,
112
113 PermissionDenied = 0x03,
115
116 UnspecifiedError = 0xFF,
118}
119
120impl U8ReprEnum for SandstormHandshakeStatus {
121 fn from_u8(value: u8) -> Option<SandstormHandshakeStatus> {
122 match value {
123 0x00 => Some(SandstormHandshakeStatus::Ok),
124 0x01 => Some(SandstormHandshakeStatus::UnsupportedVersion),
125 0x02 => Some(SandstormHandshakeStatus::InvalidUsernameOrPassword),
126 0x03 => Some(SandstormHandshakeStatus::PermissionDenied),
127 _ => None,
128 }
129 }
130
131 fn into_u8(self) -> u8 {
132 self as u8
133 }
134}
135
136impl ByteRead for SandstormHandshakeStatus {
137 async fn read<R: AsyncRead + Unpin + ?Sized>(reader: &mut R) -> Result<Self, Error> {
138 match Self::from_u8(u8::read(reader).await?) {
139 Some(value) => Ok(value),
140 None => Err(Error::new(ErrorKind::InvalidData, "Invalid SandstormHandshakeStatus type byte")),
141 }
142 }
143}
144impl ByteWrite for SandstormHandshakeStatus {
145 async fn write<W: AsyncWrite + Unpin + ?Sized>(&self, writer: &mut W) -> Result<(), Error> {
146 self.into_u8().write(writer).await
147 }
148}