Add the start of a config loader.
This commit is contained in:
parent
4ba6993039
commit
8bff34b8b6
@ -1,6 +1,7 @@
|
||||
package net.md_5.bungee.api.config;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class allows plugins to set their own configuration adapter to load
|
||||
@ -13,32 +14,26 @@ public interface ConfigurationAdapter
|
||||
* Gets an integer from the specified path.
|
||||
*
|
||||
* @param path the path to retrieve the integer from
|
||||
* @param def the default value
|
||||
* @return the retrieved integer
|
||||
*/
|
||||
public int getInt(String path);
|
||||
public int getInt(String path, int def);
|
||||
|
||||
/**
|
||||
* Gets a string from the specified path.
|
||||
*
|
||||
* @param path the path to retrieve the string from.
|
||||
* @param def the default value
|
||||
* @return the retrieved string
|
||||
*/
|
||||
public String getString(String path);
|
||||
|
||||
/**
|
||||
* Get a string list from the specified path.
|
||||
*
|
||||
* @param path the path to retrieve the list from.
|
||||
* @return the retrieved list.
|
||||
*/
|
||||
public Collection<String> getStrings(String path);
|
||||
public String getString(String path, String def);
|
||||
|
||||
/**
|
||||
* Get the configuration all servers which may be accessible via the proxy.
|
||||
*
|
||||
* @return all accessible servers
|
||||
* @return all accessible servers, keyed by name
|
||||
*/
|
||||
public Collection<ServerInfo> getServers();
|
||||
public Map<String, ServerInfo> getServers();
|
||||
|
||||
/**
|
||||
* Get information about all hosts to bind the proxy to.
|
||||
|
@ -23,4 +23,13 @@ public class ListenerInfo
|
||||
* Max amount of slots displayed on the ping page.
|
||||
*/
|
||||
private final int maxPlayers;
|
||||
/**
|
||||
* Name of the server which users will be taken to by default.
|
||||
*/
|
||||
private final String defaultServer;
|
||||
/**
|
||||
* Whether reconnect locations will be used, or else the user is simply
|
||||
* transferred to the default server on connect.
|
||||
*/
|
||||
private final boolean forceDefault;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -1,294 +0,0 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import static net.md_5.bungee.Logger.$;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
/**
|
||||
* Core configuration for the proxy.
|
||||
*/
|
||||
public class Configuration
|
||||
{
|
||||
|
||||
/**
|
||||
* Reconnect locations file.
|
||||
*/
|
||||
private transient File reconnect = new File("locations.yml");
|
||||
/**
|
||||
* Loaded reconnect locations.
|
||||
*/
|
||||
private transient Map<String, String> reconnectLocations;
|
||||
/**
|
||||
* Config file.
|
||||
*/
|
||||
private transient File file = new File("config.yml");
|
||||
/**
|
||||
* Yaml instance.
|
||||
*/
|
||||
private transient Yaml yaml;
|
||||
/**
|
||||
* Loaded config.
|
||||
*/
|
||||
private transient Map<String, Object> config;
|
||||
/**
|
||||
* Bind host.
|
||||
*/
|
||||
public String bindHost = "0.0.0.0:25577";
|
||||
/**
|
||||
* Server ping motd.
|
||||
*/
|
||||
public String motd = "BungeeCord Proxy Instance";
|
||||
/**
|
||||
* Name of default server.
|
||||
*/
|
||||
public String defaultServerName = "default";
|
||||
/**
|
||||
* Max players as displayed in list ping. Soft limit.
|
||||
*/
|
||||
public int maxPlayers = 1;
|
||||
/**
|
||||
* Tab list 1: For a tab list that is global over all server (using their
|
||||
* Minecraft name) and updating their ping frequently 2: Same as 1 but does
|
||||
* not update their ping frequently, just once, 3: Makes the individual
|
||||
* servers handle the tab list (server unique).
|
||||
*/
|
||||
public int tabList = 1;
|
||||
/**
|
||||
* Socket timeout.
|
||||
*/
|
||||
public int timeout = 15000;
|
||||
/**
|
||||
* All servers.
|
||||
*/
|
||||
public Map<String, String> servers = new HashMap<String, String>()
|
||||
{
|
||||
|
||||
{
|
||||
put(defaultServerName, "127.0.0.1:1338");
|
||||
put("pvp", "127.0.0.1:1337");
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Forced servers.
|
||||
*/
|
||||
public Map<String, String> forcedServers = new HashMap<String, String>()
|
||||
{
|
||||
|
||||
{
|
||||
put("pvp.md-5.net", "pvp");
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Proxy admins.
|
||||
*/
|
||||
public List<String> admins = new ArrayList<String>()
|
||||
{
|
||||
|
||||
{
|
||||
add("Insert Admins Here");
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Proxy moderators.
|
||||
*/
|
||||
public List<String> moderators = new ArrayList<String>()
|
||||
{
|
||||
|
||||
{
|
||||
add("Insert Moderators Here");
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Commands which will be blocked completely.
|
||||
*/
|
||||
public List<String> disabledCommands = new ArrayList<String>()
|
||||
{
|
||||
|
||||
{
|
||||
add("glist");
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Maximum number of lines to log before old ones are removed.
|
||||
*/
|
||||
public int logNumLines = 1 << 14;
|
||||
/**
|
||||
* UUID for Metrics.
|
||||
*/
|
||||
public String statsUuid = UUID.randomUUID().toString();
|
||||
public boolean metricsEnabled = true;
|
||||
public boolean forceDefaultServer = false;
|
||||
|
||||
/**
|
||||
* Load the configuration and save default values.
|
||||
*/
|
||||
public void load()
|
||||
{
|
||||
try
|
||||
{
|
||||
file.createNewFile();
|
||||
DumperOptions options = new DumperOptions();
|
||||
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
yaml = new Yaml(options);
|
||||
|
||||
try (InputStream is = new FileInputStream(file))
|
||||
{
|
||||
config = (Map) yaml.load(is);
|
||||
}
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
config = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
$().info("-------------- Loading configuration ----------------");
|
||||
for (Field field : getClass().getDeclaredFields())
|
||||
{
|
||||
if (!Modifier.isTransient(field.getModifiers()))
|
||||
{
|
||||
String name = Util.normalize(field.getName());
|
||||
try
|
||||
{
|
||||
Object def = field.get(this);
|
||||
Object value = get(name, def);
|
||||
|
||||
field.set(this, value);
|
||||
|
||||
$().info(name + ": " + value);
|
||||
} catch (IllegalAccessException ex)
|
||||
{
|
||||
$().severe("Could not get config node: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
$().info("-----------------------------------------------------");
|
||||
|
||||
if (servers.get(defaultServerName) == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Server '" + defaultServerName + "' not defined");
|
||||
}
|
||||
|
||||
if (forcedServers != null)
|
||||
{
|
||||
for (String server : forcedServers.values())
|
||||
{
|
||||
if (!servers.containsKey(server))
|
||||
{
|
||||
throw new IllegalArgumentException("Forced server " + server + " is not defined in servers");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
motd = ChatColor.translateAlternateColorCodes('&', motd);
|
||||
|
||||
reconnect.createNewFile();
|
||||
try (FileInputStream recon = new FileInputStream(reconnect))
|
||||
{
|
||||
reconnectLocations = (Map) yaml.load(recon);
|
||||
}
|
||||
if (reconnectLocations == null)
|
||||
{
|
||||
reconnectLocations = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
} catch (IOException ex)
|
||||
{
|
||||
$().severe("Could not load config!");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T get(String path, T def)
|
||||
{
|
||||
if (!config.containsKey(path))
|
||||
{
|
||||
config.put(path, def);
|
||||
save(file, config);
|
||||
}
|
||||
return (T) config.get(path);
|
||||
}
|
||||
|
||||
private void save(File fileToSave, Map toSave)
|
||||
{
|
||||
try
|
||||
{
|
||||
try (FileWriter wr = new FileWriter(fileToSave))
|
||||
{
|
||||
yaml.dump(toSave, wr);
|
||||
}
|
||||
} catch (IOException ex)
|
||||
{
|
||||
$().severe("Could not save config file " + fileToSave);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get which server a user should be connected to, taking into account their
|
||||
* name and virtual host.
|
||||
*
|
||||
* @param user to get a server for
|
||||
* @param requestedHost the host which they connected to
|
||||
* @return the name of the server which they should be connected to.
|
||||
*/
|
||||
public String getServer(String user, String requestedHost)
|
||||
{
|
||||
String server = (forcedServers == null) ? null : forcedServers.get(requestedHost);
|
||||
if (server == null)
|
||||
{
|
||||
server = reconnectLocations.get(user);
|
||||
}
|
||||
if (server == null)
|
||||
{
|
||||
server = defaultServerName;
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the last server which the user was on.
|
||||
*
|
||||
* @param user the name of the user
|
||||
* @param server which they were last on
|
||||
*/
|
||||
public void setServer(UserConnection user, String server)
|
||||
{
|
||||
reconnectLocations.put(user.name, server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the connectable address of a server defined in the configuration.
|
||||
*
|
||||
* @param name the friendly name of a server
|
||||
* @return the usable {@link InetSocketAddress} mapped to this server
|
||||
*/
|
||||
public InetSocketAddress getServer(String name)
|
||||
{
|
||||
String server = servers.get((name == null) ? defaultServerName : name);
|
||||
return (server != null) ? Util.getAddr(server) : getServer(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current mappings of users to servers.
|
||||
*/
|
||||
public void saveHosts()
|
||||
{
|
||||
save(reconnect, reconnectLocations);
|
||||
$().info("Saved reconnect locations to " + reconnect);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
|
@ -23,7 +23,7 @@ public class Logger extends java.util.logging.Logger
|
||||
super("RubberBand", null);
|
||||
try
|
||||
{
|
||||
FileHandler handler = new FileHandler("proxy.log", BungeeCord.getInstance().config.logNumLines, 1, true);
|
||||
FileHandler handler = new FileHandler("proxy.log", 1 << 14, 1, true);
|
||||
handler.setFormatter(formatter);
|
||||
addHandler(handler);
|
||||
} catch (IOException ex)
|
||||
|
@ -74,7 +74,7 @@ public class Metrics extends Thread
|
||||
{
|
||||
// Construct the post data
|
||||
final StringBuilder data = new StringBuilder();
|
||||
data.append(encode("guid")).append('=').append(encode(BungeeCord.getInstance().config.statsUuid));
|
||||
data.append(encode("guid")).append('=').append(encode(BungeeCord.getInstance().config.getUuid()));
|
||||
encodeDataPair(data, "version", ProxyServer.getInstance().getVersion());
|
||||
encodeDataPair(data, "server", "0");
|
||||
encodeDataPair(data, "players", Integer.toString(ProxyServer.getInstance().getPlayers().size()));
|
||||
|
@ -47,6 +47,7 @@ public class UserConnection extends GenericConnection implements ProxiedPlayer
|
||||
// Permissions
|
||||
private final Collection<String> groups = new HashSet<>();
|
||||
private final Map<String, Boolean> permissions = new HashMap<>();
|
||||
private final Object permMutex = new Object();
|
||||
|
||||
public UserConnection(Socket socket, PacketInputStream in, OutputStream out, Packet2Handshake handshake, List<byte[]> loginPackets)
|
||||
{
|
||||
|
@ -1,31 +0,0 @@
|
||||
package net.md_5.bungee.command;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
/**
|
||||
* Command to set a temp copy of the motd in real-time without stopping the
|
||||
* proxy.
|
||||
*/
|
||||
public class CommandMotd extends Command
|
||||
{
|
||||
|
||||
public CommandMotd()
|
||||
{
|
||||
super("bungeecord.command.motd");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args)
|
||||
{
|
||||
StringBuilder newMOTD = new StringBuilder();
|
||||
for (String s : args)
|
||||
{
|
||||
newMOTD.append(s);
|
||||
newMOTD.append(" ");
|
||||
}
|
||||
BungeeCord.getInstance().config.motd = ChatColor.translateAlternateColorCodes('&', newMOTD.substring(0, newMOTD.length() - 1));
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.tablist.GlobalPingTabList;
|
||||
import net.md_5.bungee.tablist.GlobalTabList;
|
||||
import net.md_5.bungee.tablist.ServerUniqueTabList;
|
||||
|
||||
/**
|
||||
* Core configuration for the proxy.
|
||||
*/
|
||||
@Getter
|
||||
public class Configuration
|
||||
{
|
||||
|
||||
/**
|
||||
* The default tab list options available for picking.
|
||||
*/
|
||||
private enum DefaultTabList
|
||||
{
|
||||
|
||||
GLOBAL, GLOBAL_PING, SERVER;
|
||||
}
|
||||
/**
|
||||
* Time before users are disconnected due to no network activity.
|
||||
*/
|
||||
private int timeout = 30000;
|
||||
/**
|
||||
* UUID used for metrics.
|
||||
*/
|
||||
private String uuid = UUID.randomUUID().toString();
|
||||
/**
|
||||
* Set of all listeners.
|
||||
*/
|
||||
private Collection<ListenerInfo> listeners;
|
||||
/**
|
||||
* Set of all servers.
|
||||
*/
|
||||
private Map<String, ServerInfo> servers;
|
||||
|
||||
public void load()
|
||||
{
|
||||
ConfigurationAdapter adapter = ProxyServer.getInstance().getConfigurationAdapter();
|
||||
|
||||
timeout = adapter.getInt("timeout", timeout);
|
||||
uuid = adapter.getString("stats", uuid);
|
||||
|
||||
DefaultTabList tab = DefaultTabList.valueOf(adapter.getString("tab_list", "GLOBAL_PING"));
|
||||
if (tab == null)
|
||||
{
|
||||
tab = DefaultTabList.GLOBAL_PING;
|
||||
}
|
||||
switch (tab)
|
||||
{
|
||||
case GLOBAL:
|
||||
ProxyServer.getInstance().setTabListHandler(new GlobalTabList());
|
||||
break;
|
||||
case GLOBAL_PING:
|
||||
ProxyServer.getInstance().setTabListHandler(new GlobalPingTabList());
|
||||
break;
|
||||
case SERVER:
|
||||
ProxyServer.getInstance().setTabListHandler(new ServerUniqueTabList());
|
||||
break;
|
||||
}
|
||||
|
||||
listeners = adapter.getListeners();
|
||||
Preconditions.checkArgument(listeners != null && !listeners.isEmpty(), "No listeners defined.");
|
||||
|
||||
servers = adapter.getServers();
|
||||
Preconditions.checkArgument(servers != null && !servers.isEmpty(), "No servers defined");
|
||||
|
||||
for (ListenerInfo listener : listeners)
|
||||
{
|
||||
Preconditions.checkArgument(servers.containsKey(listener.getDefaultServer()));
|
||||
}
|
||||
}
|
||||
}
|
150
proxy/src/main/java/net/md_5/bungee/config/YamlConfig.java
Normal file
150
proxy/src/main/java/net/md_5/bungee/config/YamlConfig.java
Normal file
@ -0,0 +1,150 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import net.md_5.bungee.Util;
|
||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
public class YamlConfig implements ConfigurationAdapter
|
||||
{
|
||||
|
||||
private boolean loaded;
|
||||
private Yaml yaml;
|
||||
private Map config;
|
||||
|
||||
public void load()
|
||||
{
|
||||
try
|
||||
{
|
||||
File file = new File("config.yml");
|
||||
file.createNewFile();
|
||||
DumperOptions options = new DumperOptions();
|
||||
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
yaml = new Yaml(options);
|
||||
|
||||
try (InputStream is = new FileInputStream(file))
|
||||
{
|
||||
config = (Map) yaml.load(is);
|
||||
}
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
config = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
} catch (IOException ex)
|
||||
{
|
||||
throw new RuntimeException("Could not load configuration!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T get(String path, T def)
|
||||
{
|
||||
return get(path, def, config);
|
||||
}
|
||||
|
||||
private <T> T get(String path, T def, Map submap)
|
||||
{
|
||||
if (!loaded)
|
||||
{
|
||||
load();
|
||||
}
|
||||
|
||||
int index = path.indexOf('.');
|
||||
if (index == -1)
|
||||
{
|
||||
Object val = submap.get(path);
|
||||
return (val != null) ? (T) val : def;
|
||||
} else
|
||||
{
|
||||
String first = path.substring(0, index);
|
||||
String second = path.substring(index, path.length());
|
||||
Map sub = (Map) submap.get(first);
|
||||
return (sub != null) ? get(second, def, sub) : def;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String path, int def)
|
||||
{
|
||||
return get(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String path, String def)
|
||||
{
|
||||
return get(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, ServerInfo> getServers()
|
||||
{
|
||||
Map<String, Map<String, Object>> base = get("servers", Collections.EMPTY_MAP);
|
||||
Map<String, ServerInfo> ret = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, Map<String, Object>> entry : base.entrySet())
|
||||
{
|
||||
Map<String, Object> val = entry.getValue();
|
||||
String name = get("name", null, val);
|
||||
String permission = get("permission", null, val);
|
||||
String addr = get("address", null, val);
|
||||
InetSocketAddress address = Util.getAddr(addr);
|
||||
ServerInfo info = new ServerInfo(name, address, permission);
|
||||
ret.put(name, info);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<ListenerInfo> getListeners()
|
||||
{
|
||||
Map<String, Map<String, Object>> base = get("listeners", Collections.EMPTY_MAP);
|
||||
Collection<ListenerInfo> ret = new HashSet<>();
|
||||
|
||||
for (Map.Entry<String, Map<String, Object>> entry : base.entrySet())
|
||||
{
|
||||
Map<String, Object> val = entry.getValue();
|
||||
String motd = get("motd", null, val);
|
||||
int maxPlayers = get("motd", null, val);
|
||||
String defaultServer = get("default", null, val);
|
||||
boolean forceDefault = get("force_default", null, val);
|
||||
String host = get("host", null, val);
|
||||
InetSocketAddress address = Util.getAddr(host);
|
||||
ListenerInfo info = new ListenerInfo(address, motd, maxPlayers, defaultServer, forceDefault);
|
||||
ret.add(info);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<String> getGroups(String player)
|
||||
{
|
||||
return get("groups." + player, Collections.EMPTY_SET);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<String> getPermissions(String group)
|
||||
{
|
||||
return get("permissions." + group, Collections.EMPTY_SET);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user