Add server favicon to status responses

This commit is contained in:
timvisee 2021-11-18 11:35:49 +01:00
parent 0715baed8c
commit c9d7af0e3c
No known key found for this signature in database
GPG Key ID: B8DB720BC383E172
4 changed files with 55 additions and 5 deletions

11
Cargo.lock generated
View File

@ -163,6 +163,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -750,6 +756,7 @@ name = "lazymc"
version = "0.2.1"
dependencies = [
"anyhow",
"base64",
"bytes",
"chrono",
"clap",
@ -815,7 +822,7 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "minecraft-protocol"
version = "0.1.0"
source = "git+https://github.com/timvisee/rust-minecraft-protocol?rev=a14b40e#a14b40ea9d9a9ed54a6f6546b6d19bc0db1b6c8c"
source = "git+https://github.com/timvisee/rust-minecraft-protocol?rev=356ea54#356ea5424374c5a7249be2f0f13fd3e0e2db5b58"
dependencies = [
"byteorder",
"minecraft-protocol-derive",
@ -828,7 +835,7 @@ dependencies = [
[[package]]
name = "minecraft-protocol-derive"
version = "0.0.0"
source = "git+https://github.com/timvisee/rust-minecraft-protocol?rev=a14b40e#a14b40ea9d9a9ed54a6f6546b6d19bc0db1b6c8c"
source = "git+https://github.com/timvisee/rust-minecraft-protocol?rev=356ea54#356ea5424374c5a7249be2f0f13fd3e0e2db5b58"
dependencies = [
"proc-macro2",
"quote",

View File

@ -32,6 +32,7 @@ lobby = ["named-binary-tag", "quartz_nbt", "uuid"]
[dependencies]
anyhow = "1.0"
base64 = "0.13"
bytes = "1.1"
chrono = "0.4"
clap = { version = "3.0.0-beta.5", default-features = false, features = [ "std", "cargo", "color", "env", "suggestions", "unicode" ]}
@ -41,7 +42,7 @@ dotenv = "0.15"
flate2 = { version = "1.0", default-features = false, features = ["default"] }
futures = { version = "0.3", default-features = false, features = ["executor"] }
log = "0.4"
minecraft-protocol = { git = "https://github.com/timvisee/rust-minecraft-protocol", rev = "a14b40e" }
minecraft-protocol = { git = "https://github.com/timvisee/rust-minecraft-protocol", rev = "356ea54" }
notify = "4.0"
pretty_env_logger = "0.4"
rand = "0.8"
@ -49,7 +50,7 @@ serde = "1.0"
serde_json = "1.0"
shlex = "1.1"
thiserror = "1.0"
tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "io-util", "net", "macros", "time", "process", "signal", "sync"] }
tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "io-util", "net", "macros", "time", "process", "signal", "sync", "fs"] }
toml = "0.5"
version-compare = "0.1"

View File

@ -43,7 +43,7 @@ https://user-images.githubusercontent.com/856222/141378688-882082be-9efa-4cfe-81
- _Lobby: keep client in emulated server with lobby world, teleport to real server when ready ([experimental*](./docs/join-method-lobby.md))_
- Customizable MOTD and login messages
- Automatically manages `server.properties` (host, port and RCON settings)
- Automatically handle banned IPs from server within `lazymc`
- Automatically block banned IPs from server within `lazymc`
- Graceful server sleep/shutdown through RCON (with `SIGTERM` fallback on Linux/Unix)
- Restart server on crash
- Lockout mode

View File

@ -8,6 +8,7 @@ use minecraft_protocol::encoder::Encoder;
use minecraft_protocol::version::v1_14_4::handshake::Handshake;
use minecraft_protocol::version::v1_14_4::login::LoginStart;
use minecraft_protocol::version::v1_14_4::status::StatusResponse;
use tokio::fs;
use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;
@ -25,6 +26,9 @@ const BAN_MESSAGE_PREFIX: &str = "Your IP address is banned from this server.\nR
/// Default ban reason if unknown.
const DEFAULT_BAN_REASON: &str = "Banned by an operator.";
/// Server icon file path.
const SERVER_ICON_FILE: &str = "server-icon.png";
/// Proxy the given inbound stream to a target address.
// TODO: do not drop error here, return Box<dyn Error>
pub async fn serve(
@ -226,6 +230,13 @@ async fn server_status(config: &Config, server: &Server) -> ServerStatus {
}
};
// Get server favicon
let favicon = if config.motd.from_server && status.is_some() {
status.as_ref().unwrap().favicon.clone()
} else {
favicon(&config).await
};
// Build status resposne
ServerStatus {
version,
@ -235,5 +246,36 @@ async fn server_status(config: &Config, server: &Server) -> ServerStatus {
max,
sample: vec![],
},
favicon,
}
}
/// Get server status favicon.
async fn favicon(config: &Config) -> Option<String> {
// Get server dir
let dir = match config.server.directory.as_ref() {
Some(dir) => dir,
None => return None,
};
// Server icon file, ensure it exists
let path = dir.join(SERVER_ICON_FILE);
if !path.is_file() {
return None;
}
// Read icon data
let data = fs::read(path)
.await
.map_err(|err| {
error!(target: "lazymc", "Failed to read favicon from {}: {}", SERVER_ICON_FILE, err);
})
.ok()?;
// Format and return favicon
Some(format!(
"{}{}",
"data:image/png;base64,",
base64::encode(data)
))
}