From 8685b047720280fb646e5c5e57dea86b8fb74b3c Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 19 Nov 2018 23:46:22 -0500 Subject: [PATCH 01/11] Initial reload command support. What is missing: - Changing/removing servers "in-flight" - Query stuff - A way to preserve existing user connections while closing the old port --- .../api/event/proxy/ProxyReloadEvent.java | 12 ++++++ .../velocitypowered/proxy/VelocityServer.java | 33 +++++++++++++++ .../proxy/command/VelocityCommand.java | 40 ++++++++++++++++++- 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 api/src/main/java/com/velocitypowered/api/event/proxy/ProxyReloadEvent.java diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyReloadEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyReloadEvent.java new file mode 100644 index 000000000..8341fb941 --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyReloadEvent.java @@ -0,0 +1,12 @@ +package com.velocitypowered.api.event.proxy; + +/** + * This event is fired when the proxy is reloaded by the user using {@code /velocity reload}. + */ +public class ProxyReloadEvent { + + @Override + public String toString() { + return "ProxyInitializeEvent"; + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 52a850e53..2216982a9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -7,6 +7,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; +import com.velocitypowered.api.event.proxy.ProxyReloadEvent; import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.plugin.PluginManager; @@ -40,6 +41,7 @@ import com.velocitypowered.proxy.util.VelocityChannelRegistrar; import com.velocitypowered.proxy.util.ratelimit.Ratelimiter; import com.velocitypowered.proxy.util.ratelimit.Ratelimiters; import io.netty.bootstrap.Bootstrap; +import java.io.IOException; import java.net.InetSocketAddress; import java.nio.file.Files; import java.nio.file.Path; @@ -232,6 +234,37 @@ public class VelocityServer implements ProxyServer { return shutdown; } + public boolean reloadConfiguration() throws IOException { + Path configPath = Paths.get("velocity.toml"); + VelocityConfiguration newConfiguration = VelocityConfiguration.read(configPath); + + if (!newConfiguration.validate()) { + return false; + } + + // If we have a new bind address, bind to it + if (!configuration.getBind().equals(newConfiguration.getBind())) { + this.cm.bind(newConfiguration.getBind()); + } + + // Re-register servers + for (Map.Entry entry : newConfiguration.getServers().entrySet()) { + ServerInfo newInfo = + new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue())); + Optional rs = servers.getServer(entry.getKey()); + if (!rs.isPresent()) { + servers.register(newInfo); + } else if (!rs.get().getServerInfo().equals(newInfo)) { + throw new IllegalStateException("Unable to replace servers in flight!"); + } + } + + ipAttemptLimiter = Ratelimiters.createWithMilliseconds(newConfiguration.getLoginRatelimit()); + this.configuration = newConfiguration; + eventManager.fireAndForget(new ProxyReloadEvent()); + return true; + } + public void shutdown(boolean explicitExit) { if (eventManager == null || pluginManager == null || cm == null || scheduler == null) { throw new AssertionError(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java index d5c9f7a85..c6c9a99aa 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommand.java @@ -10,6 +10,8 @@ import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.plugin.PluginDescription; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.util.ProxyVersion; +import com.velocitypowered.proxy.VelocityServer; +import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -22,6 +24,8 @@ import net.kyori.text.event.HoverEvent; import net.kyori.text.event.HoverEvent.Action; import net.kyori.text.format.TextColor; import net.kyori.text.format.TextDecoration; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.NonNull; public class VelocityCommand implements Command { @@ -32,10 +36,11 @@ public class VelocityCommand implements Command { * Initializes the command object for /velocity. * @param server the Velocity server */ - public VelocityCommand(ProxyServer server) { + public VelocityCommand(VelocityServer server) { this.subcommands = ImmutableMap.builder() .put("version", new Info(server)) .put("plugins", new Plugins(server)) + .put("reload", new Reload(server)) .build(); } @@ -103,6 +108,39 @@ public class VelocityCommand implements Command { return command.hasPermission(source, actualArgs); } + private static class Reload implements Command { + + private static final Logger logger = LogManager.getLogger(Reload.class); + private final VelocityServer server; + + private Reload(VelocityServer server) { + this.server = server; + } + + @Override + public void execute(CommandSource source, String @NonNull [] args) { + try { + if (server.reloadConfiguration()) { + source.sendMessage(TextComponent.of("Configuration reloaded.", TextColor.GREEN)); + } else { + source.sendMessage(TextComponent.of( + "Unable to reload your configuration. Check the console for more details.", + TextColor.RED)); + } + } catch (Exception e) { + logger.error("Unable to reload configuration", e); + source.sendMessage(TextComponent.of( + "Unable to reload your configuration. Check the console for more details.", + TextColor.RED)); + } + } + + @Override + public boolean hasPermission(CommandSource source, String @NonNull [] args) { + return source.getPermissionValue("velocity.command.reload") == Tristate.TRUE; + } + } + private static class Info implements Command { private final ProxyServer server; From 99960e5dd932bab520ca46d028631f6a912d71a6 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 20 Nov 2018 00:50:16 -0500 Subject: [PATCH 02/11] Forgot this --- .../com/velocitypowered/api/event/proxy/ProxyReloadEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyReloadEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyReloadEvent.java index 8341fb941..ec1ed1ad0 100644 --- a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyReloadEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyReloadEvent.java @@ -7,6 +7,6 @@ public class ProxyReloadEvent { @Override public String toString() { - return "ProxyInitializeEvent"; + return "ProxyReloadEvent"; } } From 0d94080c743c64949e7716b8b875a2b563d64099 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 20 Nov 2018 12:23:28 -0500 Subject: [PATCH 03/11] Remove unneeded null checks --- .../velocitypowered/proxy/VelocityServer.java | 55 +++++-------------- 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 2216982a9..ba7a982e9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -72,24 +72,33 @@ public class VelocityServer implements ProxyServer { .registerTypeHierarchyAdapter(GameProfile.class, new GameProfileSerializer()) .create(); - private @MonotonicNonNull ConnectionManager cm; + private ConnectionManager cm; private @MonotonicNonNull VelocityConfiguration configuration; private @MonotonicNonNull NettyHttpClient httpClient; private @MonotonicNonNull KeyPair serverKeyPair; - private @MonotonicNonNull ServerMap servers; + private ServerMap servers; private final VelocityCommandManager commandManager = new VelocityCommandManager(); private final AtomicBoolean shutdownInProgress = new AtomicBoolean(false); private boolean shutdown = false; - private @MonotonicNonNull VelocityPluginManager pluginManager; + private VelocityPluginManager pluginManager; private final Map connectionsByUuid = new ConcurrentHashMap<>(); private final Map connectionsByName = new ConcurrentHashMap<>(); - private @MonotonicNonNull VelocityConsole console; + private VelocityConsole console; private @MonotonicNonNull Ratelimiter ipAttemptLimiter; - private @MonotonicNonNull VelocityEventManager eventManager; - private @MonotonicNonNull VelocityScheduler scheduler; + private VelocityEventManager eventManager; + private VelocityScheduler scheduler; private final VelocityChannelRegistrar channelRegistrar = new VelocityChannelRegistrar(); + VelocityServer() { + pluginManager = new VelocityPluginManager(this); + eventManager = new VelocityEventManager(pluginManager); + scheduler = new VelocityScheduler(pluginManager); + console = new VelocityConsole(this); + cm = new ConnectionManager(this); + servers = new ServerMap(this); + } + public KeyPair getServerKeyPair() { if (serverKeyPair == null) { throw new AssertionError(); @@ -135,12 +144,6 @@ public class VelocityServer implements ProxyServer { logger.info("Booting up {} {}...", getVersion().getName(), getVersion().getVersion()); serverKeyPair = EncryptionUtils.createRsaKeyPair(1024); - pluginManager = new VelocityPluginManager(this); - eventManager = new VelocityEventManager(pluginManager); - scheduler = new VelocityScheduler(pluginManager); - console = new VelocityConsole(this); - cm = new ConnectionManager(this); - servers = new ServerMap(this); cm.logChannelInformation(); @@ -224,9 +227,6 @@ public class VelocityServer implements ProxyServer { } public Bootstrap initializeGenericBootstrap() { - if (cm == null) { - throw new IllegalStateException("Server did not initialize properly."); - } return this.cm.createWorker(); } @@ -362,66 +362,41 @@ public class VelocityServer implements ProxyServer { @Override public Optional getServer(String name) { - Preconditions.checkNotNull(name, "name"); - if (servers == null) { - throw new IllegalStateException("Server did not initialize properly."); - } return servers.getServer(name); } @Override public Collection getAllServers() { - if (servers == null) { - throw new IllegalStateException("Server did not initialize properly."); - } return servers.getAllServers(); } @Override public RegisteredServer registerServer(ServerInfo server) { - if (servers == null) { - throw new IllegalStateException("Server did not initialize properly."); - } return servers.register(server); } @Override public void unregisterServer(ServerInfo server) { - if (servers == null) { - throw new IllegalStateException("Server did not initialize properly."); - } servers.unregister(server); } @Override public VelocityConsole getConsoleCommandSource() { - if (console == null) { - throw new IllegalStateException("Server did not initialize properly."); - } return console; } @Override public PluginManager getPluginManager() { - if (pluginManager == null) { - throw new IllegalStateException("Server did not initialize properly."); - } return pluginManager; } @Override public EventManager getEventManager() { - if (eventManager == null) { - throw new IllegalStateException("Server did not initialize properly."); - } return eventManager; } @Override public VelocityScheduler getScheduler() { - if (scheduler == null) { - throw new IllegalStateException("Server did not initialize properly."); - } return scheduler; } From 01503be4fa8c18c6de8d73b255f6728d13cdbee1 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Tue, 20 Nov 2018 22:30:52 -0500 Subject: [PATCH 04/11] Handle switching bind (MC and GS4). --- .../velocitypowered/proxy/VelocityServer.java | 22 ++++++++++++++----- .../proxy/network/ConnectionManager.java | 21 +++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index ba7a982e9..78b327cef 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -242,11 +242,6 @@ public class VelocityServer implements ProxyServer { return false; } - // If we have a new bind address, bind to it - if (!configuration.getBind().equals(newConfiguration.getBind())) { - this.cm.bind(newConfiguration.getBind()); - } - // Re-register servers for (Map.Entry entry : newConfiguration.getServers().entrySet()) { ServerInfo newInfo = @@ -259,6 +254,23 @@ public class VelocityServer implements ProxyServer { } } + // If we have a new bind address, bind to it + if (!configuration.getBind().equals(newConfiguration.getBind())) { + this.cm.bind(newConfiguration.getBind()); + this.cm.shutdown(configuration.getBind()); + } + + if (configuration.isQueryEnabled() && (!newConfiguration.isQueryEnabled() + || newConfiguration.getQueryPort() != configuration.getQueryPort())) { + this.cm.shutdown(new InetSocketAddress( + configuration.getBind().getHostString(), configuration.getQueryPort())); + } + + if (newConfiguration.isQueryEnabled()) { + this.cm.queryBind(newConfiguration.getBind().getHostString(), + newConfiguration.getQueryPort()); + } + ipAttemptLimiter = Ratelimiters.createWithMilliseconds(newConfiguration.getLoginRatelimit()); this.configuration = newConfiguration; eventManager.fireAndForget(new ProxyReloadEvent()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java index 92d5a657d..26296a2bc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -1,5 +1,6 @@ package com.velocitypowered.proxy.network; +import com.google.common.base.Preconditions; import com.velocitypowered.natives.util.Natives; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.protocol.netty.GS4QueryHandler; @@ -11,7 +12,9 @@ import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.WriteBufferWaterMark; import java.net.InetSocketAddress; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -21,7 +24,7 @@ public final class ConnectionManager { private static final WriteBufferWaterMark SERVER_WRITE_MARK = new WriteBufferWaterMark(1 << 16, 1 << 18); private static final Logger LOGGER = LogManager.getLogger(ConnectionManager.class); - private final Set endpoints = new HashSet<>(); + private final Map endpoints = new HashMap<>(); private final TransportType transportType; private final EventLoopGroup bossGroup; private final EventLoopGroup workerGroup; @@ -55,7 +58,7 @@ public final class ConnectionManager { .addListener((ChannelFutureListener) future -> { final Channel channel = future.channel(); if (future.isSuccess()) { - this.endpoints.add(channel); + this.endpoints.put(address, channel); LOGGER.info("Listening on {}", channel.localAddress()); } else { LOGGER.error("Can't bind to {}", address, future.cause()); @@ -64,16 +67,17 @@ public final class ConnectionManager { } public void queryBind(final String hostname, final int port) { + InetSocketAddress address = new InetSocketAddress(hostname, port); final Bootstrap bootstrap = new Bootstrap() .channel(this.transportType.datagramChannelClass) .group(this.workerGroup) .handler(new GS4QueryHandler(this.server)) - .localAddress(hostname, port); + .localAddress(address); bootstrap.bind() .addListener((ChannelFutureListener) future -> { final Channel channel = future.channel(); if (future.isSuccess()) { - this.endpoints.add(channel); + this.endpoints.put(address, channel); LOGGER.info("Listening for GS4 query on {}", channel.localAddress()); } else { LOGGER.error("Can't bind to {}", bootstrap.config().localAddress(), future.cause()); @@ -90,8 +94,15 @@ public final class ConnectionManager { this.server.getConfiguration().getConnectTimeout()); } + public void shutdown(InetSocketAddress oldBind) { + Channel serverChannel = endpoints.remove(oldBind); + Preconditions.checkState(serverChannel != null, "Endpoint %s not registered", oldBind); + LOGGER.info("Closing endpoint {}", serverChannel.localAddress()); + serverChannel.close().syncUninterruptibly(); + } + public void shutdown() { - for (final Channel endpoint : this.endpoints) { + for (final Channel endpoint : this.endpoints.values()) { try { LOGGER.info("Closing endpoint {}", endpoint.localAddress()); endpoint.close().sync(); From 402398010edef47df6377b971e175c9a1ddde3b9 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 21 Nov 2018 15:57:21 -0500 Subject: [PATCH 05/11] Handle changing server addresses in config (not tested). --- .../velocitypowered/proxy/VelocityServer.java | 41 ++++++++++++++++++- .../connection/client/ConnectedPlayer.java | 2 +- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 78b327cef..49c69c190 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -3,6 +3,7 @@ package com.velocitypowered.proxy; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.velocitypowered.api.event.EventManager; @@ -47,13 +48,16 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyPair; +import java.util.ArrayList; import java.util.Collection; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import net.kyori.text.Component; import net.kyori.text.TextComponent; import net.kyori.text.serializer.GsonComponentSerializer; @@ -242,7 +246,8 @@ public class VelocityServer implements ProxyServer { return false; } - // Re-register servers + // Re-register servers. If we are replacing a server, we must evacuate players. + Collection evacuate = new ArrayList<>(); for (Map.Entry entry : newConfiguration.getServers().entrySet()) { ServerInfo newInfo = new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue())); @@ -250,10 +255,42 @@ public class VelocityServer implements ProxyServer { if (!rs.isPresent()) { servers.register(newInfo); } else if (!rs.get().getServerInfo().equals(newInfo)) { - throw new IllegalStateException("Unable to replace servers in flight!"); + for (Player player : rs.get().getPlayersConnected()) { + if (!(player instanceof ConnectedPlayer)) { + throw new IllegalStateException("ConnectedPlayer not found for player " + player + + " in server " + rs.get().getServerInfo().getName()); + } + evacuate.add((ConnectedPlayer) player); + } + servers.unregister(rs.get().getServerInfo()); + servers.register(newInfo); } } + CountDownLatch latch = new CountDownLatch(evacuate.size()); + for (ConnectedPlayer player : evacuate) { + Optional next = player.getNextServerToTry(); + if (next.isPresent()) { + player.createConnectionRequest(next.get()).connectWithIndication() + .whenComplete((success, ex) -> { + if (ex != null || success == null || !success) { + player.disconnect(TextComponent.of("Your server has been changed, but we could " + + "not move you to any fallback servers.")); + } + latch.countDown(); + }); + } else { + player.disconnect(TextComponent.of("Your server has been changed, but we could " + + "not move you to any fallback servers.")); + } + } + try { + latch.await(); + } catch (InterruptedException e) { + logger.error("Interrupted whilst moving players", e); + Thread.currentThread().interrupt(); + } + // If we have a new bind address, bind to it if (!configuration.getBind().equals(newConfiguration.getBind())) { this.cm.bind(newConfiguration.getBind()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index e06cdacfa..2c568da64 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -375,7 +375,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { } } - Optional getNextServerToTry() { + public Optional getNextServerToTry() { if (serversToTry == null) { String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString).orElse(""); serversToTry = server.getConfiguration().getForcedHosts() From 904e1367a26ceca4c526222a50efa906ae20341a Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 21 Nov 2018 16:01:58 -0500 Subject: [PATCH 06/11] Must count down here. --- .../src/main/java/com/velocitypowered/proxy/VelocityServer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 49c69c190..04248c702 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -280,6 +280,7 @@ public class VelocityServer implements ProxyServer { latch.countDown(); }); } else { + latch.countDown(); player.disconnect(TextComponent.of("Your server has been changed, but we could " + "not move you to any fallback servers.")); } From 1515c5069b1db628d55358a13a202fb848e9cdb5 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Wed, 21 Nov 2018 23:36:47 -0500 Subject: [PATCH 07/11] Fix up some stuff --- .../velocitypowered/proxy/VelocityServer.java | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 04248c702..3aea20f4e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -246,7 +246,8 @@ public class VelocityServer implements ProxyServer { return false; } - // Re-register servers. If we are replacing a server, we must evacuate players. + // Re-register servers. If a server is being replaced, make sure to note what players need to + // move back to a fallback server. Collection evacuate = new ArrayList<>(); for (Map.Entry entry : newConfiguration.getServers().entrySet()) { ServerInfo newInfo = @@ -267,29 +268,32 @@ public class VelocityServer implements ProxyServer { } } - CountDownLatch latch = new CountDownLatch(evacuate.size()); - for (ConnectedPlayer player : evacuate) { - Optional next = player.getNextServerToTry(); - if (next.isPresent()) { - player.createConnectionRequest(next.get()).connectWithIndication() - .whenComplete((success, ex) -> { - if (ex != null || success == null || !success) { - player.disconnect(TextComponent.of("Your server has been changed, but we could " - + "not move you to any fallback servers.")); - } - latch.countDown(); - }); - } else { - latch.countDown(); - player.disconnect(TextComponent.of("Your server has been changed, but we could " - + "not move you to any fallback servers.")); + // If we had any players to evacuate, let's move them now. Wait until they are all moved off. + if (!evacuate.isEmpty()) { + CountDownLatch latch = new CountDownLatch(evacuate.size()); + for (ConnectedPlayer player : evacuate) { + Optional next = player.getNextServerToTry(); + if (next.isPresent()) { + player.createConnectionRequest(next.get()).connectWithIndication() + .whenComplete((success, ex) -> { + if (ex != null || success == null || !success) { + player.disconnect(TextComponent.of("Your server has been changed, but we could " + + "not move you to any fallback servers.")); + } + latch.countDown(); + }); + } else { + latch.countDown(); + player.disconnect(TextComponent.of("Your server has been changed, but we could " + + "not move you to any fallback servers.")); + } + } + try { + latch.await(); + } catch (InterruptedException e) { + logger.error("Interrupted whilst moving players", e); + Thread.currentThread().interrupt(); } - } - try { - latch.await(); - } catch (InterruptedException e) { - logger.error("Interrupted whilst moving players", e); - Thread.currentThread().interrupt(); } // If we have a new bind address, bind to it From 9a9b6f9ab39b77354d618c545c28795be641bb6d Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 24 Nov 2018 21:38:26 -0500 Subject: [PATCH 08/11] Rename ConnectionManager#shutdown(ISA) -> ConnectionManager#close(ISA) --- .../main/java/com/velocitypowered/proxy/VelocityServer.java | 6 ++---- .../velocitypowered/proxy/network/ConnectionManager.java | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 3aea20f4e..b9d061ba5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -3,7 +3,6 @@ package com.velocitypowered.proxy; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.velocitypowered.api.event.EventManager; @@ -57,7 +56,6 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import net.kyori.text.Component; import net.kyori.text.TextComponent; import net.kyori.text.serializer.GsonComponentSerializer; @@ -299,12 +297,12 @@ public class VelocityServer implements ProxyServer { // If we have a new bind address, bind to it if (!configuration.getBind().equals(newConfiguration.getBind())) { this.cm.bind(newConfiguration.getBind()); - this.cm.shutdown(configuration.getBind()); + this.cm.close(configuration.getBind()); } if (configuration.isQueryEnabled() && (!newConfiguration.isQueryEnabled() || newConfiguration.getQueryPort() != configuration.getQueryPort())) { - this.cm.shutdown(new InetSocketAddress( + this.cm.close(new InetSocketAddress( configuration.getBind().getHostString(), configuration.getQueryPort())); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java index 26296a2bc..a0ff135c1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -94,7 +94,7 @@ public final class ConnectionManager { this.server.getConfiguration().getConnectTimeout()); } - public void shutdown(InetSocketAddress oldBind) { + public void close(InetSocketAddress oldBind) { Channel serverChannel = endpoints.remove(oldBind); Preconditions.checkState(serverChannel != null, "Endpoint %s not registered", oldBind); LOGGER.info("Closing endpoint {}", serverChannel.localAddress()); From 5eeca16f7efdcc04f2c4ed9f7f9241e0cb9668ef Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 24 Nov 2018 21:42:08 -0500 Subject: [PATCH 09/11] Apply final modifier --- .../com/velocitypowered/proxy/VelocityServer.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index c803e2ff1..821e0e4ea 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -74,24 +74,23 @@ public class VelocityServer implements ProxyServer { .registerTypeHierarchyAdapter(GameProfile.class, new GameProfileSerializer()) .create(); - private ConnectionManager cm; + private final ConnectionManager cm; private final ProxyOptions options; - private @MonotonicNonNull ConnectionManager cm; private @MonotonicNonNull VelocityConfiguration configuration; private @MonotonicNonNull NettyHttpClient httpClient; private @MonotonicNonNull KeyPair serverKeyPair; - private ServerMap servers; + private final ServerMap servers; private final VelocityCommandManager commandManager = new VelocityCommandManager(); private final AtomicBoolean shutdownInProgress = new AtomicBoolean(false); private boolean shutdown = false; - private VelocityPluginManager pluginManager; + private final VelocityPluginManager pluginManager; private final Map connectionsByUuid = new ConcurrentHashMap<>(); private final Map connectionsByName = new ConcurrentHashMap<>(); - private VelocityConsole console; + private final VelocityConsole console; private @MonotonicNonNull Ratelimiter ipAttemptLimiter; - private VelocityEventManager eventManager; - private VelocityScheduler scheduler; + private final VelocityEventManager eventManager; + private final VelocityScheduler scheduler; private final VelocityChannelRegistrar channelRegistrar = new VelocityChannelRegistrar(); VelocityServer(final ProxyOptions options) { From 2ac185586842b32d1b659b87006acc4f396d1894 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sun, 25 Nov 2018 00:43:14 -0500 Subject: [PATCH 10/11] Update Netty to 4.1.31.Final. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ec2d00c2b..65b0e6341 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ allprojects { junitVersion = '5.3.0-M1' slf4jVersion = '1.7.25' log4jVersion = '2.11.1' - nettyVersion = '4.1.30.Final' + nettyVersion = '4.1.31.Final' guavaVersion = '25.1-jre' checkerFrameworkVersion = '2.5.6' From 458d2e4d746265891b367b9bb4f8e4a112da71f1 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Sat, 1 Dec 2018 17:56:45 -0500 Subject: [PATCH 11/11] Netty 4.1.32.Final --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 65b0e6341..6a86013d9 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ allprojects { junitVersion = '5.3.0-M1' slf4jVersion = '1.7.25' log4jVersion = '2.11.1' - nettyVersion = '4.1.31.Final' + nettyVersion = '4.1.32.Final' guavaVersion = '25.1-jre' checkerFrameworkVersion = '2.5.6'