Compare commits

..

2 commits

Author SHA1 Message Date
54a16e2762 feat: add url type
Some checks failed
/ build (push) Has been cancelled
2026-06-22 18:52:19 +02:00
241504ac3b chore: some code cleanup
- remove one unwrap
- move `mc_server` module to folder and create `::helpers` submodule
2026-06-22 15:18:25 +02:00
5 changed files with 244 additions and 160 deletions

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, fmt, sync::Arc, time::Duration}; use std::{collections::HashMap, fmt, sync::Arc};
use async_trait::async_trait; use async_trait::async_trait;
use futures::StreamExt; use futures::StreamExt;
@ -13,7 +13,7 @@ use serde_json::json;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use crate::{ use crate::{
mc_server::{sanitize_addr, MinecraftAPI, MinecraftServerHandle, ServerDeploymentStatus}, mc_server::{MinecraftAPI, MinecraftServerHandle, ServerDeploymentStatus, Url},
OpaqueError, OpaqueError,
}; };
const MAIN_LABEL: &str = "tami.moe/minecraft"; const MAIN_LABEL: &str = "tami.moe/minecraft";
@ -33,7 +33,7 @@ pub struct KubeCache {
dep_cache: kube::runtime::reflector::Store<Deployment>, dep_cache: kube::runtime::reflector::Store<Deployment>,
dep_api: Api<Deployment>, dep_api: Api<Deployment>,
srv_api: Api<Service>, srv_api: Api<Service>,
in_cluster: bool, running_in_cluster: bool,
} }
impl KubeCache { impl KubeCache {
/// This initializes the creation of a "kubernetes client" /// This initializes the creation of a "kubernetes client"
@ -86,7 +86,7 @@ impl KubeCache {
dep_cache: dep_reader, dep_cache: dep_reader,
dep_api: dep_api, dep_api: dep_api,
srv_api, srv_api,
in_cluster, running_in_cluster: in_cluster,
}, },
handle, handle,
)); ));
@ -106,19 +106,19 @@ impl KubeCache {
self.srv_api.list(&lp).await.unwrap() self.srv_api.list(&lp).await.unwrap()
} }
pub async fn query_dep(&self, addr: &str, port: &str) -> Option<Arc<Deployment>> { pub async fn query_dep(&self, url: &Url) -> Option<Arc<Deployment>> {
self.dep_cache.find(|x| filter_label_value(x, addr, port)) self.dep_cache.find(|x| filter_label_value(x, url))
} }
pub async fn query_srv(&self, addr: &str, port: &str) -> Option<Service> { pub async fn query_srv(&self, url: &Url) -> Option<Service> {
let deploys = self.list_srvs().await; let deploys = self.list_srvs().await;
deploys.into_iter().find(|x| { deploys.into_iter().find(|x| {
let in_cluster = match x.spec.as_ref().unwrap().type_.as_ref() { let in_cluster = match x.spec.as_ref().unwrap().type_.as_ref() {
Some(t) => t == "ClusterIP", Some(t) => t == "ClusterIP",
None => false, None => false,
}; };
let incorrect_type = in_cluster ^ self.in_cluster; let incorrect_type = in_cluster ^ self.running_in_cluster;
!incorrect_type && filter_label_value(x, addr, port) !incorrect_type && filter_label_value(x, url)
}) })
} }
@ -137,15 +137,11 @@ pub struct McApi {
#[async_trait] #[async_trait]
impl MinecraftAPI<Server> for McApi { impl MinecraftAPI<Server> for McApi {
#[tracing::instrument( #[tracing::instrument(name = "MinecraftAPI::query_server", level = "info", skip(self, url))]
name = "MinecraftAPI::query_server", async fn query_server(&self, url: &Url) -> Result<Server, OpaqueError> {
level = "info", // let addr = sanitize_addr(&addr);
skip(self, addr, port)
)]
async fn query_server(&self, addr: &str, port: &str) -> Result<Server, OpaqueError> {
let addr = sanitize_addr(&addr);
let deployment = match self.cache.query_dep(&addr, &port).await { let deployment = match self.cache.query_dep(url).await {
Some(x) => x, Some(x) => x,
None => { None => {
return Err(OpaqueError::create_with_kind( return Err(OpaqueError::create_with_kind(
@ -154,7 +150,7 @@ impl MinecraftAPI<Server> for McApi {
)) ))
} }
}; };
let service = match self.cache.query_srv(&addr, &port).await { let service = match self.cache.query_srv(url).await {
Some(x) => x, Some(x) => x,
None => { None => {
return Err(OpaqueError::create_with_kind( return Err(OpaqueError::create_with_kind(
@ -164,7 +160,7 @@ impl MinecraftAPI<Server> for McApi {
} }
}; };
let internal_id = match deployment.metadata.name.clone() { let resource_name = match deployment.metadata.name.clone() {
Some(x) => x, Some(x) => x,
None => { None => {
return Err(OpaqueError::create_with_kind( return Err(OpaqueError::create_with_kind(
@ -183,14 +179,8 @@ impl MinecraftAPI<Server> for McApi {
.ok_or(OpaqueError::create( .ok_or(OpaqueError::create(
"Could not find \"mc-router\" nodePort for server", "Could not find \"mc-router\" nodePort for server",
))?; ))?;
let inter_addr = match self.cache.in_cluster {
false => { let inter_addr = match self.cache.running_in_cluster {
let node_port = port_srv
.node_port
.map(|x| x.to_string())
.ok_or(OpaqueError::create("Could not map nodePort to port string"))?;
format!("localhost:{}", node_port)
}
true => { true => {
let target_port = port_srv.port; let target_port = port_srv.port;
format!( format!(
@ -201,12 +191,18 @@ impl MinecraftAPI<Server> for McApi {
target_port target_port
) )
} }
false => {
let node_port = port_srv
.node_port
.map(|x| x.to_string())
.ok_or(OpaqueError::create("Could not map nodePort to port string"))?;
format!("localhost:{}", node_port)
}
}; };
return Ok(Server { return Ok(Server {
server_addr: addr.to_string(), server_url: url.to_owned(),
server_port: port.to_string(),
internal_address: inter_addr, internal_address: inter_addr,
internal_id, resource_name,
cache: self.cache.clone(), cache: self.cache.clone(),
}); });
} }
@ -233,20 +229,16 @@ impl McApi {
#[derive(Clone)] #[derive(Clone)]
pub struct Server { pub struct Server {
server_addr: String, server_url: Url,
server_port: String,
internal_address: String, internal_address: String,
internal_id: String, resource_name: String,
cache: KubeCache, cache: KubeCache,
} }
impl fmt::Debug for Server { impl fmt::Debug for Server {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("KubeServer") f.debug_struct("KubeServer")
.field("internal_id", &self.internal_id) .field("internal_id", &self.resource_name)
.field( .field("join_url", &self.server_url)
"join_addr",
&format!("{}:{}", self.server_addr, self.server_port),
)
.finish() .finish()
} }
} }
@ -268,7 +260,7 @@ impl MinecraftServerHandle for Server {
async fn query_status(&self) -> Result<crate::mc_server::ServerDeploymentStatus, OpaqueError> { async fn query_status(&self) -> Result<crate::mc_server::ServerDeploymentStatus, OpaqueError> {
let dep = self let dep = self
.cache .cache
.get_dep(&self.internal_id) .get_dep(&self.resource_name)
.ok_or_else(|| OpaqueError::create("Failed to get deployment from cache"))?; .ok_or_else(|| OpaqueError::create("Failed to get deployment from cache"))?;
let status = match &dep.status { let status = match &dep.status {
@ -319,19 +311,15 @@ impl MinecraftServerHandle for Server {
self.internal_address.as_str() self.internal_address.as_str()
} }
fn get_internal_id(&self) -> &str { fn get_internal_id(&self) -> &str {
self.internal_id.as_str() self.resource_name.as_str()
} }
fn get_join_addr(&self) -> &str { fn get_join_url(&self) -> &Url {
self.server_addr.as_ref() &self.server_url
}
fn get_join_port(&self) -> &str {
self.server_port.as_ref()
} }
fn get_motd(&self) -> Option<String> { fn get_motd(&self) -> Option<String> {
let dep = self.cache.get_dep(&self.internal_id)?; let dep = self.cache.get_dep(&self.resource_name)?;
let all_container_motds = dep let all_container_motds = dep
.spec .spec
@ -357,40 +345,39 @@ impl MinecraftServerHandle for Server {
impl Server { impl Server {
async fn set_scale(&self, num: i32) -> Result<(), kube::Error> { async fn set_scale(&self, num: i32) -> Result<(), kube::Error> {
let _res = self.cache.set_dep_scale(&self.internal_id, num).await?; let _res = self.cache.set_dep_scale(&self.resource_name, num).await?;
tracing::info!( tracing::info!("scaled replicas of {} to {num}", self.server_url,);
"scaled replicas of {}:{} to {num}",
self.server_addr,
self.server_port
);
Ok(()) Ok(())
} }
} }
fn filter_label_value<R>(res: &R, addr: &str, port: &str) -> bool fn filter_label_value<R>(res: &R, url: &Url) -> bool
where where
R: ResourceExt, R: ResourceExt,
{ {
let addr = url.get_authority();
let port = url.get_port();
let labels_iter = res.labels().iter(); let labels_iter = res.labels().iter();
let annotations_iter = res.annotations().iter(); let annotations_iter = res.annotations().iter();
let iters = labels_iter.merge(annotations_iter); let iters = labels_iter.merge(annotations_iter);
let mut found_port = false;
iters iters
.filter(|(key, value)| match key.as_str() { .filter(|(key, value)| match key.as_str() {
MAIN_LABEL => value.as_str() == addr, MAIN_LABEL => value.as_str() == addr,
PORT_LABEL => { PORT_LABEL => match port {
found_port = true; Some(p) => value.as_str() == p,
value.as_str() == port None => false,
} },
URL_ANNOTATION => value URL_ANNOTATION => value
.lines() .lines()
.find(|str| { .find(|str| {
if str.find(':').is_some() { // if str.find(':').is_some() {
str == &format!("{addr}:{port}").as_str() // str == &format!("{addr}:{port}").as_str()
} else { // } else {
str == &addr // str == &addr
} // }
str.parse::<Url>().ok().as_ref() == Some(url)
}) })
.is_some(), .is_some(),
_ => false, _ => false,

57
src/mc_server/helpers.rs Normal file
View file

@ -0,0 +1,57 @@
use tokio::{io::AsyncWriteExt, net::TcpStream};
use crate::{
packets::{clientbound::status::StatusStructNew, Packet, SendPacket},
OpaqueError,
};
#[tracing::instrument(skip(client_stream))]
pub async fn handle_ping(client_stream: &mut TcpStream) -> Result<(), OpaqueError> {
// --- Respond to ping packet ---
let ping_packet = Packet::parse(client_stream).await?;
match ping_packet.id.get_int() {
1 => Ok(ping_packet
.send_packet(client_stream)
.await
.map_err(|_| "Failed to send ping")?),
_ => Err(OpaqueError::create(&format!(
"Expected ping packet, got: {}",
ping_packet.id.get_int()
))),
}
}
/// small helper function for sending `status request` to client
pub async fn complete_status_request(
client_stream: &mut TcpStream,
status_struct: StatusStructNew,
) -> Result<(), OpaqueError> {
let status_res =
crate::packets::clientbound::status::StatusResponse::set_json(Box::new(status_struct))
.await;
status_res
.send_packet(client_stream)
.await
.map_err(|_| "Failed to send status packet")?;
Ok(())
}
/// Disconnects the client.
///
/// It works if the client is in the login state, and it
/// has *already* and *only* sent the **handshake** and **login_start** packet.
#[tracing::instrument(skip(client_stream))]
pub async fn send_disconnect(
client_stream: &mut TcpStream,
reason: &str,
) -> Result<(), OpaqueError> {
let disconnect_packet =
crate::packets::clientbound::login::Disconnect::set_reason(reason.to_owned())
.await
.ok_or_else(|| "failed to *create* disconnect packet")?;
disconnect_packet
.send_packet(client_stream)
.await
.map_err(|_| "failed to *send* disconnect packet")?;
client_stream.flush().await.map_err(|e| e.to_string())?;
Ok(())
}

View file

@ -1,68 +1,17 @@
use std::{collections::HashMap, sync::Arc}; use std::{borrow::Cow, collections::HashMap, str::FromStr, sync::Arc};
use async_trait::async_trait; use async_trait::async_trait;
use tokio::{io::AsyncWriteExt, net::TcpStream}; use tokio::net::TcpStream;
use tracing::Instrument; use tracing::Instrument;
use crate::{ use crate::{
packets::{ packets::{
clientbound::status::{StatusStructNew, StatusTrait}, clientbound::status::StatusTrait, serverbound::handshake::Handshake, Packet, SendPacket,
serverbound::handshake::Handshake,
Packet, SendPacket,
}, },
OpaqueError, OpaqueError,
}; };
#[tracing::instrument(skip(client_stream))] pub mod helpers;
pub async fn handle_ping(client_stream: &mut TcpStream) -> Result<(), OpaqueError> {
// --- Respond to ping packet ---
let ping_packet = Packet::parse(client_stream).await?;
match ping_packet.id.get_int() {
1 => Ok(ping_packet
.send_packet(client_stream)
.await
.map_err(|_| "Failed to send ping")?),
_ => Err(OpaqueError::create(&format!(
"Expected ping packet, got: {}",
ping_packet.id.get_int()
))),
}
}
/// small helper function for sending `status request` to client
pub async fn complete_status_request(
client_stream: &mut TcpStream,
status_struct: StatusStructNew,
) -> Result<(), OpaqueError> {
let status_res =
crate::packets::clientbound::status::StatusResponse::set_json(Box::new(status_struct))
.await;
status_res
.send_packet(client_stream)
.await
.map_err(|_| "Failed to send status packet")?;
Ok(())
}
/// Disconnects the client.
///
/// It works if the client is in the login state, and it
/// has *already* and *only* sent the **handshake** and **login_start** packet.
#[tracing::instrument(skip(client_stream))]
pub async fn send_disconnect(
client_stream: &mut TcpStream,
reason: &str,
) -> Result<(), OpaqueError> {
let disconnect_packet =
crate::packets::clientbound::login::Disconnect::set_reason(reason.to_owned())
.await
.ok_or_else(|| "failed to *create* disconnect packet")?;
disconnect_packet
.send_packet(client_stream)
.await
.map_err(|_| "failed to *send* disconnect packet")?;
client_stream.flush().await.map_err(|e| e.to_string())?;
Ok(())
}
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait MinecraftServerHandle: Send + Sync + 'static + Clone { pub trait MinecraftServerHandle: Send + Sync + 'static + Clone {
@ -71,8 +20,7 @@ pub trait MinecraftServerHandle: Send + Sync + 'static + Clone {
async fn query_status(&self) -> Result<ServerDeploymentStatus, OpaqueError>; async fn query_status(&self) -> Result<ServerDeploymentStatus, OpaqueError>;
fn get_internal_address(&self) -> &str; fn get_internal_address(&self) -> &str;
fn get_internal_id(&self) -> &str; fn get_internal_id(&self) -> &str;
fn get_join_addr(&self) -> &str; fn get_join_url(&self) -> &Url;
fn get_join_port(&self) -> &str;
fn get_motd(&self) -> Option<String>; fn get_motd(&self) -> Option<String>;
async fn query_server_connectable(&self) -> Result<TcpStream, OpaqueError> { async fn query_server_connectable(&self) -> Result<TcpStream, OpaqueError> {
@ -123,7 +71,7 @@ pub trait MinecraftServerHandle: Send + Sync + 'static + Clone {
ServerDeploymentStatus::Connectable(mut tcp_stream) => { ServerDeploymentStatus::Connectable(mut tcp_stream) => {
let handshake = crate::packets::serverbound::handshake::Handshake::create( let handshake = crate::packets::serverbound::handshake::Handshake::create(
crate::types::VarInt::from(746).ok_or("could not create VarInt WTF?")?, crate::types::VarInt::from(746).ok_or("could not create VarInt WTF?")?,
crate::types::VarString::from(self.get_join_addr().to_string()), crate::types::VarString::from(self.get_join_url().get_authority().to_string()),
crate::types::UShort::from(1234), crate::types::UShort::from(1234),
crate::types::VarInt::from(1).ok_or("could not create VarInt WTF?")?, crate::types::VarInt::from(1).ok_or("could not create VarInt WTF?")?,
) )
@ -160,7 +108,7 @@ pub trait MinecraftServerHandle: Send + Sync + 'static + Clone {
#[async_trait] #[async_trait]
pub trait MinecraftAPI<T>: Send + Sync + 'static { pub trait MinecraftAPI<T>: Send + Sync + 'static {
async fn query_server(&self, addr: &str, port: &str) -> Result<T, OpaqueError>; async fn query_server(&self, url: &Url) -> Result<T, OpaqueError>;
fn get_map(&self) -> Arc<tokio::sync::Mutex<HashMap<String, tokio::task::JoinHandle<()>>>>; fn get_map(&self) -> Arc<tokio::sync::Mutex<HashMap<String, tokio::task::JoinHandle<()>>>>;
/// This should be callable even if there is already a watcher, /// This should be callable even if there is already a watcher,
@ -180,7 +128,7 @@ pub trait MinecraftAPI<T>: Send + Sync + 'static {
return Ok(()); return Ok(());
} }
} }
let span = tracing::span!(parent: None,tracing::Level::INFO, "server_watcher", internal_id, join_addr = server.get_join_addr(), join_port = server.get_join_port()); let span = tracing::span!(parent: None,tracing::Level::INFO, "server_watcher", internal_id, join_url =% server.get_join_url());
let internal_id_clone = internal_id.clone(); let internal_id_clone = internal_id.clone();
let api = self.clone(); let api = self.clone();
@ -241,7 +189,114 @@ pub enum ServerDeploymentStatus {
Unavailable(String), Unavailable(String),
} }
/// Minecraft specific URL handler.
///
/// (I do not know if this exhaustively handles all kinds of URL's
/// supported by the minecraft client)
///
/// names are inspired by https://en.wikipedia.org/wiki/URL
#[derive(Clone, Debug)]
pub struct Url {
authority: Box<str>,
port: Port,
}
impl Url {
pub fn get_port(&self) -> Option<&str> {
match &self.port {
Port::Defaullt => None,
Port::Other(x) => Some(x.as_ref()),
}
}
/// This returns what is usually the DNS address or ip address.
pub fn get_authority(&self) -> &str {
self.authority.as_ref()
}
pub fn new(addr: &str, port: &str) -> Url {
let addr = sanitize_addr(addr);
Url {
authority: addr.to_string().into_boxed_str(),
port: Port::new(Some(port.to_string().into_boxed_str())),
}
}
}
impl FromStr for Url {
type Err = MinecraftURLParseError;
fn from_str(addr: &str) -> Result<Self, Self::Err> {
let addr = sanitize_addr(addr);
let mut iter = addr.split(":");
let authority = iter
.next()
.ok_or(MinecraftURLParseError::UnreachableIterFailed)?;
let port = iter.next().map(|str| str.to_string().into_boxed_str());
if let Some(_) = iter.next() {
return Err(MinecraftURLParseError::TooManyColons);
}
Ok(Self {
authority: authority.to_string().into_boxed_str(),
port: Port::new(port),
})
}
}
#[derive(Debug, Clone, PartialEq)]
enum Port {
Defaullt,
Other(Box<str>),
}
impl Port {
pub fn new(p: Option<Box<str>>) -> Self {
match p {
Some(p) => {
if p.as_ref() == "25565" {
Self::Defaullt
} else {
Self::Other(p)
}
}
None => Self::Defaullt,
}
}
}
#[derive(Debug)]
pub enum MinecraftURLParseError {
TooManyColons,
UnreachableIterFailed,
}
impl PartialEq<&Url> for Url {
fn eq(&self, other: &&Url) -> bool {
self.port == other.port && self.authority == other.authority
}
}
impl PartialEq<Url> for Url {
fn eq(&self, other: &Url) -> bool {
self.port == other.port && self.authority == other.authority
}
}
impl std::fmt::Display for Url {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Port::Other(p) = &self.port {
write!(f, "{}:{}", self.authority, p)
} else {
write!(f, "{}", self.authority)
}
}
}
// impl Debug for MinecraftURL<'_> {}
pub fn sanitize_addr(addr: &str) -> &str { pub fn sanitize_addr(addr: &str) -> &str {
// Modded minecraft clients send null terminated strings,
// after which they have extra data. This just removes them
// from the addr lookup
let addr = terminate_at_null(addr);
// Thanks to a buggy minecraft, when the client sends a join // Thanks to a buggy minecraft, when the client sends a join
// from a SRV DNS record, it will not use the address typed // from a SRV DNS record, it will not use the address typed
// in the game, but use the address redicted *to* by the // in the game, but use the address redicted *to* by the
@ -258,10 +313,6 @@ pub fn sanitize_addr(addr: &str) -> &str {
// (the address used in the protocol) // (the address used in the protocol)
let addr = addr.trim_end_matches("."); let addr = addr.trim_end_matches(".");
// Modded minecraft clients send null terminated strings,
// after which they have extra data. This just removes them
// from the addr lookup
let addr = terminate_at_null(addr);
addr addr
} }

View file

@ -23,8 +23,8 @@ impl fmt::Display for OpaqueError {
vec.push(metadata.name()); vec.push(metadata.name());
true true
}); });
if vec.len() > 1 { if let Some(trace) = vec.pop() {
write!(f, "trace = {}", vec.pop().unwrap())?; write!(f, "trace = {}", trace)?;
} }
vec.reverse(); vec.reverse();
for s in vec { for s in vec {

View file

@ -138,21 +138,20 @@ async fn process_connection<T: MinecraftServerHandle>(
// this is needed because of the filter // this is needed because of the filter
None => return Ok(()), None => return Ok(()),
}; };
let join_url = mc_server::Url::new(
&handshake.get_server_address(),
&handshake.server_port.get_value().to_string(),
);
let next_server_state = handshake.get_next_state(); let next_server_state = handshake.get_next_state();
match next_server_state { match next_server_state {
packets::ProtocolState::Status => { packets::ProtocolState::Status => {
handle_status(&mut client_stream, &handshake, api).await?; handle_status(&mut client_stream, &handshake, api, &join_url).await?;
} }
packets::ProtocolState::Login => { packets::ProtocolState::Login => {
// This block of packet parsing is needed here, so the span with the // This block of packet parsing is needed here, so the span with the
// username is correctly propagated due to the async nature of things // username is correctly propagated due to the async nature of things
let span = tracing::span!( let span = tracing::span!(tracing::Level::INFO, "login_username_extract", %join_url);
tracing::Level::INFO,
"login_username_extract",
join_addr = handshake.get_server_address(),
join_port = handshake.server_port.get_value()
);
let packet = Packet::parse(&mut client_stream) let packet = Packet::parse(&mut client_stream)
.instrument(span.clone()) .instrument(span.clone())
@ -161,7 +160,7 @@ async fn process_connection<T: MinecraftServerHandle>(
.instrument(span.clone()) .instrument(span.clone())
.await .await
.ok_or("Failed to parse login start packet".to_string())?; .ok_or("Failed to parse login start packet".to_string())?;
handle_login(&mut client_stream, &handshake, login_packet, api).await? handle_login(&mut client_stream, &handshake, login_packet, api, &join_url).await?
} }
packets::ProtocolState::Transfer => { packets::ProtocolState::Transfer => {
return Err(OpaqueError::create( return Err(OpaqueError::create(
@ -174,11 +173,12 @@ async fn process_connection<T: MinecraftServerHandle>(
Ok(()) Ok(())
} }
#[tracing::instrument(level = "info", fields(join_addr = handshake.get_server_address(),join_port = handshake.server_port.get_value()),skip(client_stream, handshake, api))] #[tracing::instrument(level = "info", fields(join_url =% join_url),skip(client_stream, handshake, api, join_url))]
async fn handle_status<T: MinecraftServerHandle>( async fn handle_status<T: MinecraftServerHandle>(
client_stream: &mut TcpStream, client_stream: &mut TcpStream,
handshake: &Handshake, handshake: &Handshake,
api: impl MinecraftAPI<T>, api: impl MinecraftAPI<T>,
join_url: &mc_server::Url,
) -> Result<(), OpaqueError> { ) -> Result<(), OpaqueError> {
let client_packet = Packet::parse(client_stream).await?; let client_packet = Packet::parse(client_stream).await?;
if client_packet.id.get_int() != 0 { if client_packet.id.get_int() != 0 {
@ -188,27 +188,20 @@ async fn handle_status<T: MinecraftServerHandle>(
))); )));
}; };
let join_addr = handshake.get_server_address();
let mut status_struct = StatusStructNew::create(); let mut status_struct = StatusStructNew::create();
status_struct.version.protocol = handshake.protocol_version.get_int(); status_struct.version.protocol = handshake.protocol_version.get_int();
let server = match api let server = match api.query_server(join_url).await {
.query_server(
&handshake.get_server_address(),
&handshake.server_port.get_value().to_string(),
)
.await
{
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
let span = tracing::span!(tracing::Level::INFO, "unavailable", err = e.get_kind()); let span = tracing::span!(tracing::Level::INFO, "unavailable", err = e.get_kind());
status_struct.players.max = 0; status_struct.players.max = 0;
status_struct.players.online = 0; status_struct.players.online = 0;
status_struct.description.text = format!( status_struct.description.text = format!(
"Could not find §kserver§r: §f§o{join_addr}§r\nMinecraft Ingress - {BYE_MESSAGE}" "Could not find §kserver§r: §f§o{join_url}§r\nMinecraft Ingress - {BYE_MESSAGE}"
); );
mc_server::complete_status_request(client_stream, status_struct) mc_server::helpers::complete_status_request(client_stream, status_struct)
.instrument(span.clone()) .instrument(span.clone())
.await?; .await?;
@ -261,26 +254,22 @@ async fn handle_status<T: MinecraftServerHandle>(
ServerDeploymentStatus::Unavailable(_) => unreachable!(), ServerDeploymentStatus::Unavailable(_) => unreachable!(),
}; };
mc_server::complete_status_request(client_stream, status_struct).await?; mc_server::helpers::complete_status_request(client_stream, status_struct).await?;
return mc_server::handle_ping(client_stream).await; return mc_server::helpers::handle_ping(client_stream).await;
} }
#[tracing::instrument(level = "info", fields(join_addr = handshake.get_server_address(),join_port = handshake.server_port.get_value(),username = login_start.name.get_value()),skip(client_stream, handshake, api, login_start))] #[tracing::instrument(level = "info", fields(join_url =% join_url), skip(client_stream, handshake, api, login_start, join_url))]
async fn handle_login<T: MinecraftServerHandle>( async fn handle_login<T: MinecraftServerHandle>(
client_stream: &mut TcpStream, client_stream: &mut TcpStream,
handshake: &Handshake, handshake: &Handshake,
login_start: LoginStart, login_start: LoginStart,
api: impl MinecraftAPI<T> + Send + Sync + 'static + Clone, api: impl MinecraftAPI<T> + Send + Sync + 'static + Clone,
join_url: &mc_server::Url,
) -> Result<(), OpaqueError> ) -> Result<(), OpaqueError>
where where
T: Send + Sync + 'static, T: Send + Sync + 'static,
{ {
let server = api let server = api.query_server(join_url).await;
.query_server(
&handshake.get_server_address(),
&handshake.server_port.get_value().to_string(),
)
.await;
let status = match server.as_ref() { let status = match server.as_ref() {
Ok(x) => x.query_status().await?, Ok(x) => x.query_status().await?,
@ -337,13 +326,13 @@ where
} }
ServerDeploymentStatus::PodOk | ServerDeploymentStatus::Starting => { ServerDeploymentStatus::PodOk | ServerDeploymentStatus::Starting => {
tracing::info!(?status, "server is starting... disconnecting client"); tracing::info!(?status, "server is starting... disconnecting client");
mc_server::send_disconnect(client_stream, format!("[\"\",{{\"text\":\"The server is still starting up...\n wait a bit more please ^^\n\n\"}},{{\"text\":\"{BYE_MESSAGE}\"}}]").as_str()).await?; mc_server::helpers::send_disconnect(client_stream, format!("[\"\",{{\"text\":\"The server is still starting up...\n wait a bit more please ^^\n\n\"}},{{\"text\":\"{BYE_MESSAGE}\"}}]").as_str()).await?;
} }
ServerDeploymentStatus::Offline => { ServerDeploymentStatus::Offline => {
let server = server?; let server = server?;
server.start().await?; server.start().await?;
api.start_watch(server.clone(), OFFLINE_TIMER).await?; api.start_watch(server.clone(), OFFLINE_TIMER).await?;
mc_server::send_disconnect(client_stream, format!("[\"\",{{\"text\":\"Okayy, §2starting§r the server!\n\n\"}},{{\"text\":\"{BYE_MESSAGE}\"}}]").as_str()).await?; mc_server::helpers::send_disconnect(client_stream, format!("[\"\",{{\"text\":\"Okayy, §2starting§r the server!\n\n\"}},{{\"text\":\"{BYE_MESSAGE}\"}}]").as_str()).await?;
} }
ServerDeploymentStatus::Unavailable(_) => { ServerDeploymentStatus::Unavailable(_) => {
tracing::info!(?status, "tried connecting, droppping connection"); tracing::info!(?status, "tried connecting, droppping connection");