Add option to automatically rewrite server.properties file

This tries to fiend the server.properties file of the Minecraft server,
and sets the correct IP and port as configured within lazymc. This is
enabled by default.
This commit is contained in:
timvisee
2021-11-08 19:10:50 +01:00
parent a5fbdc8d30
commit a7a182fbcb
6 changed files with 199 additions and 3 deletions

View File

@@ -38,3 +38,7 @@ motd_starting = "§2☻ Server is starting...\n§7⌛ Please wait..."
# Login (kick) message when server is starting.
login_starting = "Server is starting... §c♥§r\n\nThis may take some time.\n\nPlease try to reconnect in a minute."
[advanced]
# Automatically set internal IP and port in Minecraft server.properties file.
rewrite_server_properties = true

View File

@@ -1,8 +1,10 @@
use std::collections::HashMap;
use std::sync::Arc;
use clap::ArgMatches;
use crate::config;
use crate::config::{self, Config};
use crate::mc::server_properties;
use crate::service;
/// Start lazymc.
@@ -10,7 +12,37 @@ pub async fn invoke(matches: &ArgMatches) -> Result<(), ()> {
// Load config
let config = Arc::new(config::load(matches));
// Rewrite server server.properties file
rewrite_server_properties(&config);
// Start server service
// TODO: start tokio runtime here?
service::server::service(config).await
}
/// Rewrite server server.properties file with correct internal IP and port.
fn rewrite_server_properties(config: &Config) {
// Rewrite must be enabled
if !config.advanced.rewrite_server_properties {
return;
}
// Ensure server directory is set, it must exist
let dir = match &config.server.directory {
Some(dir) => dir,
None => {
warn!(target: "lazymc", "Not rewriting {} file, server directory not configured (server.directory)", server_properties::FILE);
return;
}
};
// Build list of changes
let changes = HashMap::from([
("server-ip", config.server.address.ip().to_string()),
("server-port", config.server.address.port().to_string()),
("query.port", config.server.address.port().to_string()),
]);
// Rewrite file
server_properties::rewrite_dir(dir, changes)
}

View File

@@ -68,6 +68,9 @@ pub struct Config {
/// Messages, shown to the user.
pub messages: Messages,
/// Advanced configuration.
pub advanced: Advanced,
}
impl Config {
@@ -101,6 +104,7 @@ pub struct Server {
pub address: SocketAddr,
/// Immediately wake server when starting lazymc.
#[serde(default)]
pub wake_on_start: bool,
}
@@ -111,12 +115,11 @@ pub struct Time {
pub sleep_after: u32,
/// Minimum time in seconds to stay online when server is started.
// TODO: implement this
#[serde(default, alias = "minimum_online_time")]
pub min_online_time: u32,
}
/// Messages.
/// Message configuration.
#[derive(Debug, Deserialize)]
pub struct Messages {
/// MOTD when server is sleeping.
@@ -128,3 +131,10 @@ pub struct Messages {
/// Login message when server is starting.
pub login_starting: String,
}
/// Advanced configuration.
#[derive(Debug, Deserialize)]
pub struct Advanced {
/// Rewrite server.properties.
pub rewrite_server_properties: bool,
}

View File

@@ -10,6 +10,7 @@ extern crate log;
pub(crate) mod action;
pub(crate) mod cli;
pub(crate) mod config;
pub(crate) mod mc;
pub(crate) mod monitor;
pub(crate) mod proto;
pub(crate) mod proxy;

1
src/mc/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub mod server_properties;

148
src/mc/server_properties.rs Normal file
View File

@@ -0,0 +1,148 @@
use std::collections::HashMap;
use std::fs;
use std::path::Path;
/// File name.
pub const FILE: &str = "server.properties";
/// EOL in server.properties file.
const EOL: &str = "\r\n";
/// Try to rewrite changes in server.properties file in dir.
///
/// Prints an error and stops on failure.
pub fn rewrite_dir(dir: &Path, changes: HashMap<&str, String>) {
if changes.is_empty() {
return;
}
// Ensure directory exists
if !dir.is_dir() {
warn!(target: "lazymc",
"Not rewriting {} file, configured server directory doesn't exist: {}",
FILE,
dir.to_str().unwrap_or("?")
);
return;
}
// Rewrite file
rewrite_file(&dir.join(FILE), changes)
}
/// Try to rewrite changes in server.properties file.
///
/// Prints an error and stops on failure.
pub fn rewrite_file(file: &Path, changes: HashMap<&str, String>) {
if changes.is_empty() {
return;
}
// File must exist
if !file.is_file() {
warn!(target: "lazymc",
"Not writing {} file, not found at: {}",
FILE,
file.to_str().unwrap_or("?"),
);
return;
}
// Read contents
let contents = match fs::read_to_string(&file) {
Ok(contents) => contents,
Err(err) => {
error!(target: "lazymc",
"Failed to rewrite {} file, could not load: {}",
FILE,
err,
);
return;
}
};
// Rewrite file contents, return if nothing changed
let contents = match rewrite_contents(contents, changes) {
Some(contents) => contents,
None => {
debug!(target: "lazymc",
"Not rewriting {} file, no changes to apply",
FILE,
);
return;
}
};
// Write changes
match fs::write(file, contents) {
Ok(_) => {
info!(target: "lazymc",
"Rewritten {} file with correct IP and port",
FILE,
);
}
Err(err) => {
error!(target: "lazymc",
"Failed to rewrite {} file, could not save changes: {}",
FILE,
err,
);
return;
}
};
}
/// Rewrite file contents with new properties.
///
/// Returns new file contents if anything has changed.
fn rewrite_contents(contents: String, mut changes: HashMap<&str, String>) -> Option<String> {
if changes.is_empty() {
return None;
}
let mut changed = false;
// Build new file
let mut new_contents: String = contents
.lines()
.map(|line| {
let mut line = line.to_owned();
// Skip comments or empty lines
let trim = line.trim();
if trim.starts_with("#") || trim.is_empty() {
return line;
}
// Try to split property
let (key, value) = match line.split_once("=") {
Some(result) => result,
None => return line,
};
// Take any new value, and update it
if let Some((_, new)) = changes.remove_entry(key.trim().to_lowercase().as_str()) {
if value != new {
line = format!("{}={}", key, new);
changed = true;
}
}
line
})
.collect::<Vec<_>>()
.join(EOL);
// Append any missed changes
for (key, value) in changes {
new_contents += &format!("{}{}={}", EOL, key, value);
changed = true;
}
// Return new contents if changed
if changed {
Some(new_contents)
} else {
None
}
}