174 lines
5.5 KiB
Rust
174 lines
5.5 KiB
Rust
pub mod manager;
|
|
|
|
use crate::{
|
|
config::Config,
|
|
net::{connection::GenericConnection, error::Error},
|
|
protocol::{
|
|
packets::{self, Packet, PacketDirection},
|
|
types::Chat,
|
|
ClientState,
|
|
},
|
|
};
|
|
use tokio::net::TcpStream;
|
|
|
|
/// The connection's current state.
|
|
/// Similar to crate::protocol::ClientState,
|
|
/// but has more fine-grained tracking for packet responses.
|
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
|
pub enum DownstreamConnectionState {
|
|
#[default]
|
|
Handshake,
|
|
StatusRequest,
|
|
StatusPing,
|
|
LoginStart,
|
|
EncryptionResponse,
|
|
LoginPluginResponse,
|
|
Play,
|
|
Disconnected,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct DownstreamConnection {
|
|
inner: GenericConnection,
|
|
state: DownstreamConnectionState,
|
|
}
|
|
impl DownstreamConnection {
|
|
pub fn new(id: u128, stream: TcpStream) -> Self {
|
|
DownstreamConnection {
|
|
// receiving_direction: PacketDirection::Serverbound
|
|
inner: GenericConnection::new(id, PacketDirection::Serverbound, stream),
|
|
state: DownstreamConnectionState::Handshake,
|
|
}
|
|
}
|
|
pub fn client_state(&self) -> DownstreamConnectionState {
|
|
self.state
|
|
}
|
|
pub fn client_state_mut(&mut self) -> &mut DownstreamConnectionState {
|
|
&mut self.state
|
|
}
|
|
pub fn inner_state(&self) -> ClientState {
|
|
self.inner.client_state()
|
|
}
|
|
pub fn inner_state_mut(&mut self) -> &mut ClientState {
|
|
self.inner.client_state_mut()
|
|
}
|
|
pub async fn handle_handshake(&mut self) -> Result<(), Error> {
|
|
use packets::handshake::serverbound::Handshake;
|
|
|
|
let handshake = self
|
|
.read_specific_packet::<Handshake>()
|
|
.await
|
|
.ok_or(Error::Unexpected)??;
|
|
|
|
match handshake.next_state {
|
|
ClientState::Status => {
|
|
*self.client_state_mut() = DownstreamConnectionState::StatusRequest;
|
|
*self.inner_state_mut() = ClientState::Status;
|
|
}
|
|
ClientState::Login => todo!(),
|
|
_ => {
|
|
self.disconnect(Some(
|
|
serde_json::json!({ "text": "Received invalid handshake." }),
|
|
))
|
|
.await?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
pub async fn handle_status_ping(&mut self, online_player_count: usize) -> Result<(), Error> {
|
|
// The state just changed from Handshake to Status.
|
|
use base64::Engine;
|
|
use packets::status::clientbound::{PingResponse, StatusResponse};
|
|
|
|
// Read the status request packet.
|
|
let Packet::StatusRequest(_status_request) =
|
|
self.read_packet().await.ok_or(Error::Unexpected)??
|
|
else {
|
|
return Err(Error::Unexpected);
|
|
};
|
|
|
|
// Send the status response packet.
|
|
let config = Config::instance();
|
|
self.send_packet(StatusResponse {
|
|
response: serde_json::json!({
|
|
"version": {
|
|
"name": config.global.game_version,
|
|
"protocol": config.global.protocol_version
|
|
},
|
|
"players": {
|
|
"max": config.server.max_players,
|
|
"online": online_player_count,
|
|
"sample": []
|
|
},
|
|
"description": {
|
|
"text": config.server.motd
|
|
},
|
|
"favicon": format!("data:image/png;base64,{}", base64::engine::general_purpose::STANDARD_NO_PAD.encode(&config.server.server_icon_bytes)),
|
|
"enforcesSecureChat": false
|
|
}),
|
|
}).await?;
|
|
|
|
// Read the ping request packet.
|
|
let Packet::PingRequest(ping_request) =
|
|
self.read_packet().await.ok_or(Error::Unexpected)??
|
|
else {
|
|
return Err(Error::Unexpected);
|
|
};
|
|
|
|
// Send the ping response packet.
|
|
self.send_packet(PingResponse {
|
|
payload: ping_request.payload,
|
|
})
|
|
.await?;
|
|
|
|
self.disconnect(None).await
|
|
}
|
|
pub async fn read_packet(&mut self) -> Option<Result<Packet, Error>> {
|
|
self.inner.read_packet().await
|
|
}
|
|
pub async fn send_packet<P: Into<Packet>>(&mut self, packet: P) -> Result<(), Error> {
|
|
self.inner.send_packet(packet).await
|
|
}
|
|
pub async fn disconnect(&mut self, reason: Option<Chat>) -> Result<(), Error> {
|
|
use packets::{login::clientbound::LoginDisconnect, play::clientbound::PlayDisconnect};
|
|
|
|
// let reason = reason.unwrap_or(serde_json::json!({
|
|
// "text": "You have been disconnected!"
|
|
// }));
|
|
|
|
if let Some(reason) = reason {
|
|
match self.inner_state() {
|
|
ClientState::Disconnected | ClientState::Handshake | ClientState::Status => {
|
|
// Impossible to send a disconnect in these states.
|
|
}
|
|
ClientState::Login => {
|
|
let _ = self.send_packet(LoginDisconnect { reason }).await;
|
|
}
|
|
ClientState::Play => {
|
|
let _ = self.send_packet(PlayDisconnect { reason }).await;
|
|
}
|
|
}
|
|
}
|
|
|
|
self.inner.disconnect().await
|
|
}
|
|
}
|
|
impl std::ops::Deref for DownstreamConnection {
|
|
type Target = GenericConnection;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.inner
|
|
}
|
|
}
|
|
impl std::ops::DerefMut for DownstreamConnection {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.inner
|
|
}
|
|
}
|
|
impl From<DownstreamConnection> for GenericConnection {
|
|
fn from(value: DownstreamConnection) -> Self {
|
|
value.inner
|
|
}
|
|
}
|