From fd8d417915cc4a2f8d0629818a59ef76cc287bc1 Mon Sep 17 00:00:00 2001 From: Mattie Date: Tue, 9 Jul 2024 00:46:36 -0400 Subject: [PATCH] Add support for configuration file + environment variables --- README.md | 35 ++- .../bedrockconnect/BedrockConnect.java | 243 +++++++++++------- 2 files changed, 171 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index e383da1..635c6ae 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Table of contents * [FAQ](#faq) * [Publicly available BedrockConnect instances](#publicly-available-bedrockconnect-instances) * [Hosting your own serverlist server](#hosting-your-own-serverlist-server) + * [Configuration](#configuration) * [Defining your own custom servers](#defining-your-own-custom-servers) * [Change wording of serverlist](#change-wording-of-serverlist) * [Using your own DNS server](#using-your-own-dns-server) @@ -90,9 +91,29 @@ java -jar BedrockConnect-1.0-SNAPSHOT.jar nodb=true ``` (```nodb=true``` allows the software to run without a database. If you want to use a database, remove this argument) -The following arguments can be placed in the startup command to ajust settings: +Alternatively, BedrockConnect can also be ran on Docker through the public image ```pugmatt/bedrock-connect``` -| Argument | Description | Default Value | +``` +docker run -p 19132:19132/udp pugmatt/bedrock-connect +``` + +# Configuration + +BedrockConnect can be configured through three ways: + +- Through startup arguments (e.g. ```java -jar BedrockConnect-1.0-SNAPSHOT.jar nodb=true user_servers=false server_limit=100```) + +- Configuration file, by adding the file ```config.yml``` to the root directory where your BedrockConnect jar is present, containing settings in YAML format. Example: +``` +user_servers: false +server_limit: 100 +``` + +- Environment variables. Any setting can be defined through an environment variable, as long as it's prefixed with ```BC_``` (e.g. ```BC_USER_SERVERS```, ```BC_SERVER_LIMIT```, etc) + +The following is the full list of settings available: + +| Setting | Description | Default Value | | ------------- | ------------- | ------------- | | mysql_host | MySQL Host | localhost | | mysql_db | MySQL Database Name | bedrock-connect | @@ -115,11 +136,6 @@ The following arguments can be placed in the startup command to ajust settings: | packet_limit | Number of datagram packets each address can send within one tick (10ms) | 200 | | global_packet_limit | Number of all datagrams that will be handled within one tick (10ms) before server starts dropping any incoming data. | 100000 | -MySQL example: -``` -java -jar BedrockConnect-1.0-SNAPSHOT.jar mysql_pass=test123 server_limit=10 -``` - # Defining your own custom servers When hosting your own serverlist server, you add your own custom servers to the top of the serverlist for all players. To get started, create a JSON file and follow this format: @@ -170,8 +186,7 @@ You can also specify groups, such as the following format: ] ``` - -Then, add this argument to your startup script: `custom_servers=[path to json file]` +Then, set ```custom_servers``` in your BedrockConnect [configuration](#configuration) to the path of the json file. (e.g. Setting through an argument to your startup script: `custom_servers=[path to json file]`) The icon URL is not required, if omitted it will show the default icon. @@ -194,7 +209,7 @@ Example custom language file: } ``` -Once finished, you include it in your server by adding the following arguement to your startup command: ```language=my_lang.json``` (Replace "my_lang" with the name of your file") +Then, set ```language``` in your BedrockConnect [configuration](#configuration) to the path of the json file. (e.g. Setting through an argument to your startup script: `language=my_lang.json` Replace "my_lang" with the name of your file") # Using your own DNS server diff --git a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/BedrockConnect.java b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/BedrockConnect.java index 19a444d..049192f 100644 --- a/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/BedrockConnect.java +++ b/serverlist-server/src/main/com/pyratron/pugmatt/bedrockconnect/BedrockConnect.java @@ -1,5 +1,7 @@ package main.com.pyratron.pugmatt.bedrockconnect; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import main.com.pyratron.pugmatt.bedrockconnect.config.Language; import main.com.pyratron.pugmatt.bedrockconnect.sql.Data; import main.com.pyratron.pugmatt.bedrockconnect.sql.MySQL; @@ -10,6 +12,7 @@ import java.io.*; import java.net.*; +import java.security.Security; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; @@ -43,7 +46,7 @@ public class BedrockConnect { public static int globalPacketLimit = RakConstants.DEFAULT_GLOBAL_PACKET_LIMIT; - public static String release = "1.45"; + public static String release = "1.46"; public static HashMap featuredServerIps; @@ -65,107 +68,153 @@ public static void main(String[] args) { String languageFile = null; + HashMap settings = new HashMap<>(); + + // Find any settings in startup arguments for(String str : args) { - if(str.startsWith("mysql_host=")) - hostname = getArgValue(str, "mysql_host"); - if(str.startsWith("mysql_db=")) - database = getArgValue(str, "mysql_db"); - if(str.startsWith("mysql_user=")) - username = getArgValue(str, "mysql_user"); - if(str.startsWith("mysql_pass=")) - password = getArgValue(str, "mysql_pass"); - if(str.startsWith("server_limit=")) - serverLimit = getArgValue(str, "server_limit"); - if(str.startsWith("port=")) - port = getArgValue(str, "port"); - if(str.startsWith("nodb=")) - noDB = getArgValue(str, "nodb").toLowerCase().equals("true"); - if(str.startsWith("custom_servers=")) - customServers = getArgValue(str, "custom_servers"); - if(str.startsWith("generatedns=")) { - String ip; - try { - Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); - - System.out.println("Local IPv4 IPs:"); - while (interfaces.hasMoreElements()) { - NetworkInterface iface = interfaces.nextElement(); - - if (iface.isLoopback() || !iface.isUp() || iface.isVirtual() || iface.isPointToPoint()) - continue; - - Enumeration addresses = iface.getInetAddresses(); - while(addresses.hasMoreElements()) { - InetAddress addr = addresses.nextElement(); - - if(!(addr instanceof Inet4Address)) continue; - - ip = addr.getHostAddress(); - System.out.println(iface.getDisplayName() + ": " + ip); - } - } + if(str.indexOf("=") != -1 && str.indexOf("=") < str.length() - 1) { + settings.put(str.substring(0, str.indexOf("=")), str.substring(str.indexOf("=") + 1)); + } + } - Scanner reader = new Scanner(System.in); // Reading from System.in - System.out.print("\nWhich IP should be used for the DNS records: "); - String selectedIP = reader.next().replaceAll("\\s+",""); - reader.close(); - - BufferedWriter br = new BufferedWriter(new FileWriter(new File("bc_dns.conf"))); - br.write("\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""); - br.close(); - } catch (SocketException e) { - throw new RuntimeException(e); + // Find any settings in configuration file + File configFile = new File("config.yml"); + if(configFile.exists() && !configFile.isDirectory()) { + try { + ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); + Map config = mapper.readValue(configFile, Map.class); + for (String configKey : config.keySet()) { + settings.put(configKey.toLowerCase(), config.get(configKey).toString()); } + } catch(Exception e) { + System.out.println("Issue parsing configuration file"); + throw new RuntimeException(e); } - if(str.startsWith("kick_inactive=")) { - kickInactive = getArgValue(str, "kick_inactive").toLowerCase().equals("true"); - } - if(str.startsWith("user_servers=")) { - userServers = getArgValue(str, "user_servers").toLowerCase().equals("true"); - } - if (str.startsWith("featured_servers=")) { - featuredServers = getArgValue(str, "featured_servers").toLowerCase().equals("true"); - } - if (str.startsWith("fetch_featured_ips=")) { - fetchFeaturedIps = getArgValue(str, "fetch_featured_ips").toLowerCase().equals("true"); - } - if (str.startsWith("fetch_ips=")) { - fetchIps = getArgValue(str, "fetch_ips").toLowerCase().equals("true"); - } - if (str.startsWith("whitelist=")) { - try { - whitelistfile = new File(getArgValue(str, "whitelist")); - Whitelist.loadWhitelist(whitelistfile); - } - catch(Exception e) { - System.out.println("Unable to load whitelist file: " + whitelistfile.getName()); - e.printStackTrace(); - } - } - if (str.startsWith("language=")) { - languageFile = getArgValue(str, "language"); - } - if (str.startsWith("bindip=")) { - bindIp = getArgValue(str, "bindip"); - } - if (str.startsWith("store_display_names=")) { - storeDisplayNames = getArgValue(str, "store_display_names").toLowerCase().equals("true"); - } - if (str.startsWith("packet_limit=")) { - packetLimit = Integer.parseInt(getArgValue(str, "packet_limit")); + } + + // Find any settings in environment variables + try { + Map env = System.getenv(); + for (String envName : env.keySet()) { + if (envName.toLowerCase().startsWith("bc_")) { + settings.put(envName.toLowerCase().replace("bc_", ""), env.get(envName)); + } } - if (str.startsWith("global_packet_limit=")) { - globalPacketLimit = Integer.parseInt(getArgValue(str, "global_packet_limit")); + } catch(SecurityException e) {} + + for (Map.Entry setting : settings.entrySet()) { + switch(setting.getKey().toLowerCase()) { + case "mysql_host": + hostname = setting.getValue(); + break; + case "mysql_db": + database = setting.getValue(); + break; + case "mysql_user": + username = setting.getValue(); + break; + case "mysql_pass": + password = setting.getValue(); + break; + case "server_limit": + serverLimit = setting.getValue(); + break; + case "port": + port = setting.getValue(); + break; + case "nodb": + noDB = setting.getValue().equalsIgnoreCase("true"); + break; + case "custom_servers": + customServers = setting.getValue(); + break; + case "generatedns": + if(setting.getValue().equalsIgnoreCase("true")) { + String ip; + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + + System.out.println("Local IPv4 IPs:"); + while (interfaces.hasMoreElements()) { + NetworkInterface iface = interfaces.nextElement(); + + if (iface.isLoopback() || !iface.isUp() || iface.isVirtual() || iface.isPointToPoint()) + continue; + + Enumeration addresses = iface.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress addr = addresses.nextElement(); + + if (!(addr instanceof Inet4Address)) continue; + + ip = addr.getHostAddress(); + System.out.println(iface.getDisplayName() + ": " + ip); + } + } + + Scanner reader = new Scanner(System.in); // Reading from System.in + System.out.print("\nWhich IP should be used for the DNS records: "); + String selectedIP = reader.next().replaceAll("\\s+", ""); + reader.close(); + + BufferedWriter br = new BufferedWriter(new FileWriter(new File("bc_dns.conf"))); + br.write("\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""); + br.close(); + } catch (SocketException e) { + throw new RuntimeException(e); + } + } + break; + case "kick_inactive": + kickInactive = setting.getValue().equalsIgnoreCase("true"); + break; + case "user_servers": + userServers = setting.getValue().equalsIgnoreCase("true"); + break; + case "featured_servers": + featuredServers = setting.getValue().equalsIgnoreCase("true"); + break; + case "fetch_featured_ips": + fetchFeaturedIps = setting.getValue().equalsIgnoreCase("true"); + break; + case "fetch_ips": + fetchIps = setting.getValue().equalsIgnoreCase("true"); + break; + case "whitelist": + try { + whitelistfile = new File(setting.getValue()); + Whitelist.loadWhitelist(whitelistfile); + } + catch(Exception e) { + System.out.println("Unable to load whitelist file: " + whitelistfile.getName()); + e.printStackTrace(); + } + break; + case "language": + languageFile = setting.getValue(); + break; + case "bindip": + bindIp = setting.getValue(); + break; + case "store_display_names": + storeDisplayNames = setting.getValue().equalsIgnoreCase("true"); + break; + case "packet_limit": + packetLimit = Integer.parseInt(setting.getValue()); + break; + case "global_packet_limit": + globalPacketLimit = Integer.parseInt(setting.getValue()); + break; } }