Always include favicon in status response, fall back to default icon

See https://github.com/timvisee/lazymc/issues/11#issuecomment-977814539
This commit is contained in:
timvisee 2021-11-24 13:20:49 +01:00
parent ea2dbc905c
commit 20fb6ee715
No known key found for this signature in database
GPG Key ID: B8DB720BC383E172
3 changed files with 36 additions and 21 deletions

11
src/mc/favicon.rs Normal file
View File

@ -0,0 +1,11 @@
/// Get default server status favicon.
pub fn default_favicon() -> String {
encode_favicon(include_bytes!("../../res/unknown_server_optimized.png"))
}
/// Encode favicon bytes to a string Minecraft can read.
///
/// This assumes the favicon data to be a valid PNG image.
pub fn encode_favicon(data: &[u8]) -> String {
format!("{}{}", "data:image/png;base64,", base64::encode(data))
}

View File

@ -1,4 +1,5 @@
pub mod ban; pub mod ban;
pub mod favicon;
#[cfg(feature = "rcon")] #[cfg(feature = "rcon")]
pub mod rcon; pub mod rcon;
pub mod server_properties; pub mod server_properties;

View File

@ -14,6 +14,7 @@ use tokio::net::TcpStream;
use crate::config::*; use crate::config::*;
use crate::join; use crate::join;
use crate::mc::favicon;
use crate::proto::action; use crate::proto::action;
use crate::proto::client::{Client, ClientInfo, ClientState}; use crate::proto::client::{Client, ClientInfo, ClientState};
use crate::proto::packet::{self, RawPacket}; use crate::proto::packet::{self, RawPacket};
@ -230,12 +231,14 @@ async fn server_status(config: &Config, server: &Server) -> ServerStatus {
} }
}; };
// Get server favicon // Extract favicon from real server status, load from disk, or use default
let favicon = if config.motd.from_server && status.is_some() { let mut favicon = None;
status.as_ref().unwrap().favicon.clone() if config.motd.from_server && status.is_some() {
} else { favicon = status.as_ref().unwrap().favicon.clone()
favicon(&config).await }
}; if favicon.is_none() {
favicon = Some(server_favicon(&config).await);
}
// Build status resposne // Build status resposne
ServerStatus { ServerStatus {
@ -251,31 +254,31 @@ async fn server_status(config: &Config, server: &Server) -> ServerStatus {
} }
/// Get server status favicon. /// Get server status favicon.
async fn favicon(config: &Config) -> Option<String> { ///
/// This always returns a favicon, returning the default one if none is set.
async fn server_favicon(config: &Config) -> String {
// Get server dir // Get server dir
let dir = match config.server.directory.as_ref() { let dir = match config.server.directory.as_ref() {
Some(dir) => dir, Some(dir) => dir,
None => return None, None => return favicon::default_favicon(),
}; };
// Server icon file, ensure it exists // Server icon file, ensure it exists
let path = dir.join(SERVER_ICON_FILE); let path = dir.join(SERVER_ICON_FILE);
if !path.is_file() { if !path.is_file() {
return None; return favicon::default_favicon();
} }
// Read icon data // Read icon data
let data = fs::read(path) let data = match fs::read(path).await.map_err(|err| {
.await error!(target: "lazymc", "Failed to read favicon from {}: {}", SERVER_ICON_FILE, err);
.map_err(|err| { }) {
error!(target: "lazymc", "Failed to read favicon from {}: {}", SERVER_ICON_FILE, err); Ok(data) => data,
}) Err(err) => {
.ok()?; error!(target: "lazymc::status", "Failed to load server icon from disk, using default: {:?}", err);
return favicon::default_favicon();
}
};
// Format and return favicon favicon::encode_favicon(&data)
Some(format!(
"{}{}",
"data:image/png;base64,",
base64::encode(data)
))
} }