From 8d4ebbcc8999f166b3a9e7174ffb654a56cd3a2d Mon Sep 17 00:00:00 2001 From: Troy Frew Date: Wed, 29 Jun 2016 04:29:25 +0200 Subject: [PATCH] Add dynamic server addition/removal api. The provided methods will not move a player if a server is removed or the server ip/port is changed, however the methods return the old ServerInfo object for you to handle that yourself if needed. Thanks to Overcast for the idea diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java index 5a49050..f04e2bf 100644 --- a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java +++ b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java @@ -32,9 +32,83 @@ public interface ProxyConfig /** * Set of all servers. + * + * @deprecated The returned map may be modified concurrently by the proxy. + * The safe alternative is {@link #getServersCopy()}. */ + @Deprecated // Waterfall Map getServers(); + // Waterfall start - Dynamic server addition/removal api + /** + * Return all servers registered to this proxy, keyed by name. The returned map + * is an immutable snapshot of the actual server collection. It cannot be modified, + * and it will not change. + * + * @return all registered remote server destinations + */ + Map getServersCopy(); + + /** + * Gets the server info of a server. + * + * @param name the name of the configured server + * @return the server info belonging to the specified server + */ + ServerInfo getServerInfo(String name); + + /** + * Register the given server to the proxy. + * Any currently registered server with the same name will be replaced. + * This change is not saved to config.yml + * + * @return the previously registered server with the same name, or null if there was no such server. + */ + ServerInfo addServer(ServerInfo server); + + /** + * Register all of the given servers to the proxy. + * This change is not saved to config.yml + * + * @return true if any servers were added or replaced. + */ + boolean addServers(Collection servers); + + /** + * Un-register the server with the given name from the proxy. + * This change is not saved to config.yml + * + * @return the server that was removed, or null if there is no server with the given name. + */ + ServerInfo removeServerNamed(String name); + + /** + * Un-register the given server from the proxy. + * The server is matched by name only, other fields in the given {@link ServerInfo} are ignored. + * This change is not saved to config.yml + * + * @return the server that was removed, or null if there is no server with a matching name. + */ + ServerInfo removeServer(ServerInfo server); + + /** + * Un-register servers with any of the given names from the proxy. + * This change is not saved to config.yml + * + * @return true if any servers were removed. + */ + boolean removeServersNamed(Collection names); + + /** + * Un-register all of the given servers from the proxy. + * The servers are matched by name only, other fields in the given {@link ServerInfo} are ignored. + * This change is not saved to config.yml + * + * @return true if any servers were removed. + */ + boolean removeServers(Collection servers); + // Waterfall end + /** * Does the server authenticate with mojang */ diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java index 11c5b68..1c011d0 100644 --- a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java +++ b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java @@ -93,9 +93,25 @@ public abstract class ProxyServer * return a fresh map each time. * * @return all registered remote server destinations + * + * @deprecated The returned map is part of the proxy's internal state, + * and may be modified concurrently by the proxy. + * The safe alternative is {@link #getServersCopy()}. */ + @Deprecated // Waterfall public abstract Map getServers(); + // Waterfall begin - Cloned servers map + /** + * Return all servers registered to this proxy, keyed by name. The returned map + * is an immutable snapshot of the actual server collection. It cannot be modified, + * and it will not change. + * + * @return all registered remote server destinations + */ + public abstract Map getServersCopy(); + // Waterfall end + /** * Gets the server info of a server. * diff --git a/config/src/main/java/net/md_5/bungee/config/Configuration.java b/config/src/main/java/net/md_5/bungee/config/Configuration.java index 967a1b2..08aa698 100644 --- a/config/src/main/java/net/md_5/bungee/config/Configuration.java +++ b/config/src/main/java/net/md_5/bungee/config/Configuration.java @@ -44,6 +44,13 @@ public final class Configuration } } + // Waterfall start - Allow configuration objects to be cloned + public Configuration(Configuration values, Configuration defaults) + { + this( values.self, defaults ); + } + // Waterfall end + private Configuration getSectionFor(String path) { int index = path.indexOf( SEPARATOR ); diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 60a0cb4..f04e9c1 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -563,10 +563,18 @@ public class BungeeCord extends ProxyServer return config.getServers(); } + // Waterfall start + @Override + public Map getServersCopy() + { + return config.getServersCopy(); + } + // Waterfall end + @Override public ServerInfo getServerInfo(String name) { - return getServers().get( name ); + return config.getServerInfo( name ); // Waterfall } @Override diff --git a/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java b/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java index db9ebbd..4d16fa3 100644 --- a/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java +++ b/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java @@ -1,6 +1,7 @@ package net.md_5.bungee.conf; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; // Waterfall import gnu.trove.map.TMap; import java.io.File; import java.io.IOException; @@ -11,6 +12,7 @@ import java.util.UUID; import java.util.logging.Level; import javax.imageio.ImageIO; import lombok.Getter; +import lombok.Synchronized; // Waterfall import net.md_5.bungee.BungeeCord; import net.md_5.bungee.api.Favicon; @@ -42,6 +44,7 @@ public abstract class Configuration implements ProxyConfig * Set of all listeners. */ private Collection listeners; + private final Object serversLock = new Object(); // Waterfall /** * Set of all servers. */ @@ -61,6 +64,7 @@ public abstract class Configuration implements ProxyConfig private Favicon favicon; private int compressionThreshold = 256; + @Synchronized("serversLock") // Waterfall public void load() { ConfigurationAdapter adapter = ProxyServer.getInstance().getConfigurationAdapter(); @@ -100,7 +104,7 @@ public abstract class Configuration implements ProxyConfig servers = new CaseInsensitiveMap<>( newServers ); } else { - Map oldServers = this.servers; + Map oldServers = getServersCopy(); this.servers = new CaseInsensitiveMap<>(newServers); for ( ServerInfo oldServer : oldServers.values() ) @@ -158,4 +162,71 @@ public abstract class Configuration implements ProxyConfig { return favicon; } + + // Waterfall start + @Override + @Synchronized("serversLock") + public Map getServersCopy() { + return ImmutableMap.copyOf( servers ); + } + + @Override + @Synchronized("serversLock") + public ServerInfo getServerInfo(String name) + { + return this.servers.get( name ); + } + + @Override + @Synchronized("serversLock") + public ServerInfo addServer(ServerInfo server) + { + return this.servers.put( server.getName(), server ); + } + + @Override + @Synchronized("serversLock") + public boolean addServers(Collection servers) + { + boolean changed = false; + for ( ServerInfo server : servers ) + { + if ( server != this.servers.put( server.getName(), server ) ) changed = true; + } + return changed; + } + + @Override + @Synchronized("serversLock") + public ServerInfo removeServerNamed(String name) + { + return this.servers.remove( name ); + } + + @Override + @Synchronized("serversLock") + public ServerInfo removeServer(ServerInfo server) + { + return this.servers.remove( server.getName() ); + } + + @Override + @Synchronized("serversLock") + public boolean removeServersNamed(Collection names) + { + return this.servers.keySet().removeAll( names ); + } + + @Override + @Synchronized("serversLock") + public boolean removeServers(Collection servers) + { + boolean changed = false; + for ( ServerInfo server : servers ) + { + if ( null != this.servers.remove( server.getName() ) ) changed = true; + } + return changed; + } + // Waterfall end } -- 2.10.0