1
0
mirror of https://github.com/GeyserMC/Floodgate.git synced 2025-12-19 14:59:20 +00:00

Started using plugin messages internally. Started subcommand refactor

This commit is contained in:
Tim203
2022-06-19 23:00:18 +02:00
parent 6e2c19f118
commit 69aacfa91b
19 changed files with 298 additions and 134 deletions

View File

@@ -34,6 +34,7 @@ object Versions {
const val snakeyamlVersion = "1.28" const val snakeyamlVersion = "1.28"
const val cloudVersion = "1.5.0" const val cloudVersion = "1.5.0"
const val bstatsVersion = "3.0.0" const val bstatsVersion = "3.0.0"
const val mbassadorVersion = "1.3.2"
const val javaWebsocketVersion = "1.5.2" const val javaWebsocketVersion = "1.5.2"

View File

@@ -15,6 +15,7 @@ dependencies {
api("cloud.commandframework", "cloud-core", Versions.cloudVersion) api("cloud.commandframework", "cloud-core", Versions.cloudVersion)
api("org.yaml", "snakeyaml", Versions.snakeyamlVersion) api("org.yaml", "snakeyaml", Versions.snakeyamlVersion)
api("org.bstats", "bstats-base", Versions.bstatsVersion) api("org.bstats", "bstats-base", Versions.bstatsVersion)
api("net.engio", "mbassador", Versions.mbassadorVersion)
} }
// present on all platforms // present on all platforms

View File

@@ -33,6 +33,7 @@ import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.UUID; import java.util.UUID;
import net.engio.mbassy.bus.common.PubSubSupport;
import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.InstanceHolder; import org.geysermc.floodgate.api.InstanceHolder;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
@@ -43,6 +44,7 @@ import org.geysermc.floodgate.api.packet.PacketHandlers;
import org.geysermc.floodgate.config.ConfigLoader; import org.geysermc.floodgate.config.ConfigLoader;
import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.config.FloodgateConfigHolder; import org.geysermc.floodgate.config.FloodgateConfigHolder;
import org.geysermc.floodgate.event.ShutdownEvent;
import org.geysermc.floodgate.link.PlayerLinkLoader; import org.geysermc.floodgate.link.PlayerLinkLoader;
import org.geysermc.floodgate.module.ConfigLoadedModule; import org.geysermc.floodgate.module.ConfigLoadedModule;
import org.geysermc.floodgate.module.PostInitializeModule; import org.geysermc.floodgate.module.PostInitializeModule;
@@ -130,6 +132,8 @@ public class FloodgatePlatform {
} }
public boolean disable() { public boolean disable() {
guice.getInstance(PubSubSupport.class).publish(new ShutdownEvent());
if (injector != null && injector.canRemoveInjection()) { if (injector != null && injector.canRemoveInjection()) {
try { try {
if (!injector.removeInjection()) { if (!injector.removeInjection()) {
@@ -139,9 +143,6 @@ public class FloodgatePlatform {
logger.error("Failed to remove the injection!", exception); logger.error("Failed to remove the injection!", exception);
} }
} }
guice.getInstance(NewsChecker.class).shutdown();
api.getPlayerLink().stop();
return true; return true;
} }

View File

@@ -25,24 +25,14 @@
package org.geysermc.floodgate.api; package org.geysermc.floodgate.api;
import com.google.inject.Inject;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfigHolder;
import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
import org.geysermc.floodgate.util.BedrockData; import org.geysermc.floodgate.util.BedrockData;
public final class ProxyFloodgateApi extends SimpleFloodgateApi { public final class ProxyFloodgateApi extends SimpleFloodgateApi {
private final FloodgateCipher cipher; @Inject
private FloodgateCipher cipher;
public ProxyFloodgateApi(
PluginMessageManager pluginMessageManager,
FloodgateConfigHolder configHolder,
FloodgateLogger logger,
FloodgateCipher cipher) {
super(pluginMessageManager, configHolder, logger);
this.cipher = cipher;
}
public byte[] createEncryptedData(BedrockData bedrockData) { public byte[] createEncryptedData(BedrockData bedrockData) {
try { try {

View File

@@ -30,13 +30,13 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.inject.Inject;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.cumulus.form.util.FormBuilder;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
@@ -47,10 +47,9 @@ import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
import org.geysermc.floodgate.pluginmessage.channel.FormChannel; import org.geysermc.floodgate.pluginmessage.channel.FormChannel;
import org.geysermc.floodgate.pluginmessage.channel.TransferChannel; import org.geysermc.floodgate.pluginmessage.channel.TransferChannel;
import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.HttpUtils; import org.geysermc.floodgate.util.HttpClient;
import org.geysermc.floodgate.util.Utils; import org.geysermc.floodgate.util.Utils;
@RequiredArgsConstructor
public class SimpleFloodgateApi implements FloodgateApi { public class SimpleFloodgateApi implements FloodgateApi {
private final Map<UUID, FloodgatePlayer> players = new HashMap<>(); private final Map<UUID, FloodgatePlayer> players = new HashMap<>();
private final Cache<UUID, FloodgatePlayer> pendingRemove = private final Cache<UUID, FloodgatePlayer> pendingRemove =
@@ -58,9 +57,10 @@ public class SimpleFloodgateApi implements FloodgateApi {
.expireAfterWrite(20, TimeUnit.SECONDS) .expireAfterWrite(20, TimeUnit.SECONDS)
.build(); .build();
private final PluginMessageManager pluginMessageManager; @Inject private PluginMessageManager pluginMessageManager;
private final FloodgateConfigHolder configHolder; @Inject private FloodgateConfigHolder configHolder;
private final FloodgateLogger logger; @Inject private HttpClient httpClient;
@Inject private FloodgateLogger logger;
@Override @Override
public String getPlayerPrefix() { public String getPlayerPrefix() {
@@ -148,7 +148,7 @@ public class SimpleFloodgateApi implements FloodgateApi {
return Utils.failedFuture(new IllegalStateException("Received an invalid gamertag")); return Utils.failedFuture(new IllegalStateException("Received an invalid gamertag"));
} }
return HttpUtils.asyncGet(Constants.GET_XUID_URL + gamertag) return httpClient.asyncGet(Constants.GET_XUID_URL + gamertag)
.thenApply(result -> { .thenApply(result -> {
JsonObject response = result.getResponse(); JsonObject response = result.getResponse();
@@ -163,7 +163,7 @@ public class SimpleFloodgateApi implements FloodgateApi {
@Override @Override
public CompletableFuture<String> getGamertagFor(long xuid) { public CompletableFuture<String> getGamertagFor(long xuid) {
return HttpUtils.asyncGet(Constants.GET_GAMERTAG_URL + xuid) return httpClient.asyncGet(Constants.GET_GAMERTAG_URL + xuid)
.thenApply(result -> { .thenApply(result -> {
JsonObject response = result.getResponse(); JsonObject response = result.getResponse();

View File

@@ -49,10 +49,11 @@ import org.geysermc.floodgate.player.UserAudience;
import org.geysermc.floodgate.player.audience.ProfileAudience; import org.geysermc.floodgate.player.audience.ProfileAudience;
import org.geysermc.floodgate.player.audience.ProfileAudienceArgument; import org.geysermc.floodgate.player.audience.ProfileAudienceArgument;
import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.HttpUtils; import org.geysermc.floodgate.util.HttpClient;
public class WhitelistCommand implements FloodgateCommand { public class WhitelistCommand implements FloodgateCommand {
@Inject private FloodgateConfig config; @Inject private FloodgateConfig config;
@Inject private HttpClient httpClient;
@Inject private FloodgateLogger logger; @Inject private FloodgateLogger logger;
@Override @Override
@@ -128,7 +129,7 @@ public class WhitelistCommand implements FloodgateCommand {
final String strippedName = name; final String strippedName = name;
// We need to get the UUID of the player if it's not manually specified // We need to get the UUID of the player if it's not manually specified
HttpUtils.asyncGet(Constants.GET_XUID_URL + name) httpClient.asyncGet(Constants.GET_XUID_URL + name)
.whenComplete((result, error) -> { .whenComplete((result, error) -> {
if (error != null) { if (error != null) {
sender.sendMessage(Message.API_UNAVAILABLE); sender.sendMessage(Message.API_UNAVAILABLE);

View File

@@ -29,20 +29,40 @@ import static org.geysermc.floodgate.util.Constants.COLOR_CHAR;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.inject.Inject;
import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.Pair;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import org.geysermc.floodgate.command.util.Permission;
import org.geysermc.floodgate.platform.command.FloodgateSubCommand;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.HttpUtils; import org.geysermc.floodgate.util.HttpClient;
import org.geysermc.floodgate.util.HttpUtils.HttpResponse; import org.geysermc.floodgate.util.HttpClient.HttpResponse;
import org.geysermc.floodgate.util.Utils; import org.geysermc.floodgate.util.Utils;
final class FirewallCheckSubcommand { final class FirewallCheckSubcommand extends FloodgateSubCommand {
private FirewallCheckSubcommand() {} @Inject
private HttpClient httpClient;
static void executeFirewall(CommandContext<UserAudience> context) { @Override
public String name() {
return "firewall";
}
@Override
public String description() {
return "Check if your outgoing firewall allows Floodgate to work properly";
}
@Override
public Permission permission() {
return Permission.COMMAND_MAIN_FIREWALL;
}
@Override
public void execute(CommandContext<UserAudience> context) {
UserAudience sender = context.getSender(); UserAudience sender = context.getSender();
executeChecks( executeChecks(
globalApiCheck(sender) globalApiCheck(sender)
@@ -54,12 +74,12 @@ final class FirewallCheckSubcommand {
); );
} }
private static BooleanSupplier globalApiCheck(UserAudience sender) { private BooleanSupplier globalApiCheck(UserAudience sender) {
return executeFirewallText( return executeFirewallText(
sender, "global api", sender, "global api",
() -> { () -> {
HttpResponse<JsonElement> response = HttpResponse<JsonElement> response =
HttpUtils.get(Constants.HEALTH_URL, JsonElement.class); httpClient.get(Constants.HEALTH_URL, JsonElement.class);
if (!response.isCodeOk()) { if (!response.isCodeOk()) {
throw new IllegalStateException(String.format( throw new IllegalStateException(String.format(
@@ -70,7 +90,7 @@ final class FirewallCheckSubcommand {
}); });
} }
private static BooleanSupplier executeFirewallText( private BooleanSupplier executeFirewallText(
UserAudience sender, String name, Runnable runnable) { UserAudience sender, String name, Runnable runnable) {
return () -> { return () -> {
sender.sendMessage(COLOR_CHAR + "eTesting " + name + "..."); sender.sendMessage(COLOR_CHAR + "eTesting " + name + "...");
@@ -86,9 +106,7 @@ final class FirewallCheckSubcommand {
}; };
} }
private static CompletableFuture<Pair<Integer, Integer>> executeChecks( private CompletableFuture<Pair<Integer, Integer>> executeChecks(BooleanSupplier... checks) {
BooleanSupplier... checks) {
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
AtomicInteger okCount = new AtomicInteger(); AtomicInteger okCount = new AtomicInteger();
AtomicInteger failCount = new AtomicInteger(); AtomicInteger failCount = new AtomicInteger();

View File

@@ -32,14 +32,25 @@ import cloud.commandframework.Command;
import cloud.commandframework.Command.Builder; import cloud.commandframework.Command.Builder;
import cloud.commandframework.CommandManager; import cloud.commandframework.CommandManager;
import cloud.commandframework.context.CommandContext; import cloud.commandframework.context.CommandContext;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.function.Consumer;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.command.util.Permission; import org.geysermc.floodgate.command.util.Permission;
import org.geysermc.floodgate.platform.command.FloodgateCommand; import org.geysermc.floodgate.platform.command.FloodgateCommand;
import org.geysermc.floodgate.platform.command.FloodgateSubCommand;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
public final class MainCommand implements FloodgateCommand { public final class MainCommand implements FloodgateCommand {
private final List<FloodgateSubCommand> subCommands = new ArrayList<>();
@Inject
public void createSubCommands(FirewallCheckSubcommand firewallCheckSubcommand) {
//todo move subcommand logic to a separate class
subCommands.clear();
subCommands.add(firewallCheckSubcommand);
}
@Override @Override
public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) { public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) {
Builder<UserAudience> builder = commandManager.commandBuilder( Builder<UserAudience> builder = commandManager.commandBuilder(
@@ -49,11 +60,11 @@ public final class MainCommand implements FloodgateCommand {
.permission(Permission.COMMAND_MAIN.get()) .permission(Permission.COMMAND_MAIN.get())
.handler(this::execute); .handler(this::execute);
for (SubCommand subCommand : SubCommand.VALUES) { for (FloodgateSubCommand subCommand : subCommands) {
commandManager.command(builder commandManager.command(builder
.literal(subCommand.name().toLowerCase(Locale.ROOT), subCommand.description) .literal(subCommand.name().toLowerCase(Locale.ROOT), subCommand.description())
.permission(subCommand.permission.get()) .permission(subCommand.permission().get())
.handler(subCommand.executor::accept) .handler(subCommand::execute)
); );
} }
@@ -65,27 +76,15 @@ public final class MainCommand implements FloodgateCommand {
public void execute(CommandContext<UserAudience> context) { public void execute(CommandContext<UserAudience> context) {
StringBuilder helpMessage = new StringBuilder("Available subcommands are:\n"); StringBuilder helpMessage = new StringBuilder("Available subcommands are:\n");
for (SubCommand subCommand : SubCommand.VALUES) { for (FloodgateSubCommand subCommand : subCommands) {
if (context.getSender().hasPermission(subCommand.permission.get())) { if (context.getSender().hasPermission(subCommand.permission().get())) {
helpMessage.append('\n').append(COLOR_CHAR).append('b') helpMessage.append('\n').append(COLOR_CHAR).append('b')
.append(subCommand.name().toLowerCase(Locale.ROOT)) .append(subCommand.name().toLowerCase(Locale.ROOT))
.append(COLOR_CHAR).append("f - ").append(COLOR_CHAR).append('7') .append(COLOR_CHAR).append("f - ").append(COLOR_CHAR).append('7')
.append(subCommand.description); .append(subCommand.description());
} }
} }
context.getSender().sendMessage(helpMessage.toString()); context.getSender().sendMessage(helpMessage.toString());
} }
@RequiredArgsConstructor
enum SubCommand {
FIREWALL("Check if your outgoing firewall allows Floodgate to work properly",
Permission.COMMAND_MAIN_FIREWALL, FirewallCheckSubcommand::executeFirewall);
static final SubCommand[] VALUES = values();
final String description;
final Permission permission;
final Consumer<CommandContext<UserAudience>> executor;
}
} }

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.event;
public class ShutdownEvent {
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.event.util;
import com.google.inject.TypeLiteral;
import com.google.inject.matcher.AbstractMatcher;
import net.engio.mbassy.listener.Listener;
public class ListenerAnnotationMatcher extends AbstractMatcher<TypeLiteral<?>> {
@Override
public boolean matches(TypeLiteral<?> typeLiteral) {
Class<?> rawType = typeLiteral.getRawType();
return rawType.isAnnotationPresent(Listener.class);
}
}

View File

@@ -34,6 +34,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import net.engio.mbassy.listener.Handler;
import net.engio.mbassy.listener.Listener;
import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.link.LinkRequest; import org.geysermc.floodgate.api.link.LinkRequest;
import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.link.PlayerLink;
@@ -41,8 +43,10 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.database.config.DatabaseConfig; import org.geysermc.floodgate.database.config.DatabaseConfig;
import org.geysermc.floodgate.database.config.DatabaseConfigLoader; import org.geysermc.floodgate.database.config.DatabaseConfigLoader;
import org.geysermc.floodgate.event.ShutdownEvent;
import org.geysermc.floodgate.util.InjectorHolder; import org.geysermc.floodgate.util.InjectorHolder;
@Listener
public abstract class CommonPlayerLink implements PlayerLink { public abstract class CommonPlayerLink implements PlayerLink {
@Getter(AccessLevel.PROTECTED) @Getter(AccessLevel.PROTECTED)
private final ExecutorService executorService = Executors.newFixedThreadPool(11); private final ExecutorService executorService = Executors.newFixedThreadPool(11);
@@ -102,4 +106,9 @@ public abstract class CommonPlayerLink implements PlayerLink {
public void stop() { public void stop() {
executorService.shutdown(); executorService.shutdown();
} }
@Handler
public void onShutdown(ShutdownEvent ignored) {
stop();
}
} }

View File

@@ -29,19 +29,23 @@ import static org.geysermc.floodgate.util.Constants.GET_BEDROCK_LINK;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.inject.Inject;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import lombok.Getter; import lombok.Getter;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.api.link.LinkRequestResult; import org.geysermc.floodgate.api.link.LinkRequestResult;
import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.util.HttpUtils; import org.geysermc.floodgate.util.HttpClient;
import org.geysermc.floodgate.util.HttpUtils.DefaultHttpResponse; import org.geysermc.floodgate.util.HttpClient.DefaultHttpResponse;
import org.geysermc.floodgate.util.LinkedPlayer; import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.floodgate.util.Utils; import org.geysermc.floodgate.util.Utils;
@Getter @Getter
public class GlobalPlayerLinking extends CommonPlayerLink { public class GlobalPlayerLinking extends CommonPlayerLink {
@Inject
private HttpClient httpClient;
private PlayerLink databaseImpl; private PlayerLink databaseImpl;
public void setDatabaseImpl(PlayerLink databaseImpl) { public void setDatabaseImpl(PlayerLink databaseImpl) {
@@ -94,7 +98,7 @@ public class GlobalPlayerLinking extends CommonPlayerLink {
return CompletableFuture.supplyAsync( return CompletableFuture.supplyAsync(
() -> { () -> {
DefaultHttpResponse response = DefaultHttpResponse response =
HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits()); httpClient.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
// either the global api is down or it failed to return link // either the global api is down or it failed to return link
if (!response.isCodeOk()) { if (!response.isCodeOk()) {
@@ -144,7 +148,7 @@ public class GlobalPlayerLinking extends CommonPlayerLink {
return CompletableFuture.supplyAsync( return CompletableFuture.supplyAsync(
() -> { () -> {
DefaultHttpResponse response = DefaultHttpResponse response =
HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits()); httpClient.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
if (!response.isCodeOk()) { if (!response.isCodeOk()) {
getLogger().error( getLogger().error(

View File

@@ -28,10 +28,17 @@ package org.geysermc.floodgate.module;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import java.nio.file.Path; import java.nio.file.Path;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.engio.mbassy.bus.MBassador;
import net.engio.mbassy.bus.common.PubSubSupport;
import net.engio.mbassy.bus.error.IPublicationErrorHandler.ConsoleLogger;
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl; import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.api.SimpleFloodgateApi;
@@ -48,29 +55,46 @@ import org.geysermc.floodgate.crypto.AesKeyProducer;
import org.geysermc.floodgate.crypto.Base64Topping; import org.geysermc.floodgate.crypto.Base64Topping;
import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.crypto.KeyProducer; import org.geysermc.floodgate.crypto.KeyProducer;
import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher;
import org.geysermc.floodgate.inject.CommonPlatformInjector; import org.geysermc.floodgate.inject.CommonPlatformInjector;
import org.geysermc.floodgate.news.NewsChecker; import org.geysermc.floodgate.news.NewsChecker;
import org.geysermc.floodgate.packet.PacketHandlersImpl; import org.geysermc.floodgate.packet.PacketHandlersImpl;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler; import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.pluginmessage.PluginMessageManager; import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.skin.SkinApplier;
import org.geysermc.floodgate.skin.SkinUploadManager; import org.geysermc.floodgate.skin.SkinUploadManager;
import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.HttpClient;
import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.LanguageManager;
@RequiredArgsConstructor @RequiredArgsConstructor
public class CommonModule extends AbstractModule { public class CommonModule extends AbstractModule {
private final PubSubSupport<Object> eventBus = new MBassador<>(new ConsoleLogger(true));
private final Path dataDirectory; private final Path dataDirectory;
@Override @Override
protected void configure() { protected void configure() {
bind(PubSubSupport.class).toInstance(eventBus);
// register every class that has the Listener annotation
bindListener(new ListenerAnnotationMatcher(), new TypeListener() {
@Override
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
encounter.register((InjectionListener<I>) eventBus::subscribe);
}
});
bind(HttpClient.class).in(Singleton.class);
bind(FloodgateApi.class).to(SimpleFloodgateApi.class); bind(FloodgateApi.class).to(SimpleFloodgateApi.class);
bind(PlatformInjector.class).to(CommonPlatformInjector.class); bind(PlatformInjector.class).to(CommonPlatformInjector.class);
bind(HandshakeHandlers.class).to(HandshakeHandlersImpl.class); bind(HandshakeHandlers.class).to(HandshakeHandlersImpl.class);
bind(HandshakeHandlersImpl.class).in(Singleton.class);
bind(PacketHandlers.class).to(PacketHandlersImpl.class); bind(PacketHandlers.class).to(PacketHandlersImpl.class);
bind(PacketHandlersImpl.class).asEagerSingleton(); bind(PacketHandlersImpl.class).asEagerSingleton();
bind(NewsChecker.class).in(Singleton.class);
} }
@Provides @Provides
@@ -116,12 +140,6 @@ public class CommonModule extends AbstractModule {
return new LanguageManager(configHolder, logger); return new LanguageManager(configHolder, logger);
} }
@Provides
@Singleton
public HandshakeHandlersImpl handshakeHandlers() {
return new HandshakeHandlersImpl();
}
@Provides @Provides
@Singleton @Singleton
public FloodgateHandshakeHandler handshakeHandler( public FloodgateHandshakeHandler handshakeHandler(
@@ -154,8 +172,16 @@ public class CommonModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
public NewsChecker newsChecker(CommandUtil commandUtil, FloodgateLogger logger) { @Named("gitBranch")
return new NewsChecker(commandUtil, logger, Constants.GIT_BRANCH, Constants.BUILD_NUMBER); public String gitBranch() {
return Constants.GIT_BRANCH;
}
@Provides
@Singleton
@Named("buildNumber")
public int buildNumber() {
return Constants.BUILD_NUMBER;
} }
@Provides @Provides

View File

@@ -31,12 +31,8 @@ import com.google.inject.name.Named;
import java.nio.file.Path; import java.nio.file.Path;
import org.geysermc.floodgate.api.ProxyFloodgateApi; import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.config.FloodgateConfigHolder;
import org.geysermc.floodgate.config.ProxyFloodgateConfig; import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
public final class ProxyCommonModule extends CommonModule { public final class ProxyCommonModule extends CommonModule {
public ProxyCommonModule(Path dataDirectory) { public ProxyCommonModule(Path dataDirectory) {
@@ -46,7 +42,9 @@ public final class ProxyCommonModule extends CommonModule {
@Override @Override
protected void configure() { protected void configure() {
super.configure(); super.configure();
bind(SimpleFloodgateApi.class).to(ProxyFloodgateApi.class); bind(SimpleFloodgateApi.class).to(ProxyFloodgateApi.class);
bind(ProxyFloodgateApi.class).in(Singleton.class);
} }
@Provides @Provides
@@ -55,14 +53,4 @@ public final class ProxyCommonModule extends CommonModule {
public Class<? extends FloodgateConfig> floodgateConfigClass() { public Class<? extends FloodgateConfig> floodgateConfigClass() {
return ProxyFloodgateConfig.class; return ProxyFloodgateConfig.class;
} }
@Provides
@Singleton
public ProxyFloodgateApi proxyFloodgateApi(
PluginMessageManager pluginMessageManager,
FloodgateConfigHolder configHolder,
FloodgateLogger logger,
FloodgateCipher cipher) {
return new ProxyFloodgateApi(pluginMessageManager, configHolder, logger, cipher);
}
} }

View File

@@ -30,29 +30,22 @@ import com.google.inject.Singleton;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import java.nio.file.Path; import java.nio.file.Path;
import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.config.FloodgateConfigHolder;
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
public final class ServerCommonModule extends CommonModule { public final class ServerCommonModule extends CommonModule {
public ServerCommonModule(Path dataDirectory) { public ServerCommonModule(Path dataDirectory) {
super(dataDirectory); super(dataDirectory);
} }
@Override
protected void configure() {
bind(SimpleFloodgateApi.class).in(Singleton.class);
}
@Provides @Provides
@Singleton @Singleton
@Named("configClass") @Named("configClass")
public Class<? extends FloodgateConfig> floodgateConfigClass() { public Class<? extends FloodgateConfig> floodgateConfigClass() {
return FloodgateConfig.class; return FloodgateConfig.class;
} }
@Provides
@Singleton
public SimpleFloodgateApi floodgateApi(
PluginMessageManager pluginMessageManager,
FloodgateConfigHolder configHolder,
FloodgateLogger logger) {
return new SimpleFloodgateApi(pluginMessageManager, configHolder, logger);
}
} }

View File

@@ -27,6 +27,8 @@ package org.geysermc.floodgate.news;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@@ -35,34 +37,40 @@ import java.util.Map;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import net.engio.mbassy.listener.Handler;
import net.engio.mbassy.listener.Listener;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.command.util.Permission;
import org.geysermc.floodgate.event.ShutdownEvent;
import org.geysermc.floodgate.news.data.AnnouncementData; import org.geysermc.floodgate.news.data.AnnouncementData;
import org.geysermc.floodgate.news.data.BuildSpecificData; import org.geysermc.floodgate.news.data.BuildSpecificData;
import org.geysermc.floodgate.news.data.CheckAfterData; import org.geysermc.floodgate.news.data.CheckAfterData;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.HttpUtils; import org.geysermc.floodgate.util.HttpClient;
import org.geysermc.floodgate.util.HttpUtils.HttpResponse; import org.geysermc.floodgate.util.HttpClient.HttpResponse;
import org.geysermc.floodgate.command.util.Permission;
@Listener
public class NewsChecker { public class NewsChecker {
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
private final CommandUtil commandUtil;
private final FloodgateLogger logger;
private final Map<Integer, NewsItem> activeNewsItems = new HashMap<>(); private final Map<Integer, NewsItem> activeNewsItems = new HashMap<>();
private final String branch;
private final int build; @Inject
private CommandUtil commandUtil;
@Inject
private HttpClient httpClient;
@Inject
private FloodgateLogger logger;
@Inject
@Named("gitBranch")
private String branch;
@Inject
@Named("buildNumber")
private int build;
private boolean firstCheck; private boolean firstCheck;
public NewsChecker(CommandUtil commandUtil, FloodgateLogger logger, String branch, int build) {
this.commandUtil = commandUtil;
this.logger = logger;
this.branch = branch;
this.build = build;
}
public void start() { public void start() {
executorService.scheduleWithFixedDelay(this::checkNews, 0, 30, TimeUnit.MINUTES); executorService.scheduleWithFixedDelay(this::checkNews, 0, 30, TimeUnit.MINUTES);
} }
@@ -72,10 +80,10 @@ public class NewsChecker {
} }
private void checkNews() { private void checkNews() {
HttpResponse<JsonArray> response = HttpResponse<JsonArray> response = httpClient.getSilent(
HttpUtils.getSilent(
Constants.NEWS_OVERVIEW_URL + Constants.NEWS_PROJECT_NAME, Constants.NEWS_OVERVIEW_URL + Constants.NEWS_PROJECT_NAME,
JsonArray.class); JsonArray.class
);
JsonArray array = response.getResponse(); JsonArray array = response.getResponse();
@@ -197,4 +205,9 @@ public class NewsChecker {
public void shutdown() { public void shutdown() {
executorService.shutdown(); executorService.shutdown();
} }
@Handler
public void onShutdown(ShutdownEvent ignored) {
shutdown();
}
} }

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.platform.command;
import cloud.commandframework.context.CommandContext;
import org.geysermc.floodgate.command.util.Permission;
import org.geysermc.floodgate.player.UserAudience;
public abstract class FloodgateSubCommand {
public abstract String name();
public abstract String description();
public abstract Permission permission();
public abstract void execute(CommandContext<UserAudience> context);
}

View File

@@ -37,34 +37,38 @@ import java.util.concurrent.Executors;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import net.engio.mbassy.listener.Handler;
import net.engio.mbassy.listener.Listener;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.floodgate.event.ShutdownEvent;
// resources are properly closed and ignoring the original stack trace is intended // resources are properly closed and ignoring the original stack trace is intended
@SuppressWarnings({"PMD.CloseResource", "PMD.PreserveStackTrace"}) @SuppressWarnings({"PMD.CloseResource", "PMD.PreserveStackTrace"})
public class HttpUtils { @Listener
private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); public class HttpClient {
private static final Gson GSON = new Gson();
private static final String USER_AGENT = "GeyserMC/Floodgate"; private static final String USER_AGENT = "GeyserMC/Floodgate";
public static CompletableFuture<DefaultHttpResponse> asyncGet(String urlString) { private final ExecutorService executorService = Executors.newSingleThreadExecutor();
return CompletableFuture.supplyAsync(() -> get(urlString), EXECUTOR_SERVICE); private final Gson gson = new Gson();
public CompletableFuture<DefaultHttpResponse> asyncGet(String urlString) {
return CompletableFuture.supplyAsync(() -> get(urlString), executorService);
} }
public static DefaultHttpResponse get(String urlString) { public DefaultHttpResponse get(String urlString) {
return readDefaultResponse(request(urlString)); return readDefaultResponse(request(urlString));
} }
public static <T> HttpResponse<T> get(String urlString, Class<T> clazz) { public <T> HttpResponse<T> get(String urlString, Class<T> clazz) {
return readResponse(request(urlString), clazz); return readResponse(request(urlString), clazz);
} }
public static <T> HttpResponse<T> getSilent(String urlString, Class<T> clazz) { public <T> HttpResponse<T> getSilent(String urlString, Class<T> clazz) {
return readResponseSilent(request(urlString), clazz); return readResponseSilent(request(urlString), clazz);
} }
private static HttpURLConnection request(String urlString) { private HttpURLConnection request(String urlString) {
HttpURLConnection connection; HttpURLConnection connection;
try { try {
@@ -88,7 +92,7 @@ public class HttpUtils {
} }
@NonNull @NonNull
private static <T> HttpResponse<T> readResponse(HttpURLConnection connection, Class<T> clazz) { private <T> HttpResponse<T> readResponse(HttpURLConnection connection, Class<T> clazz) {
InputStreamReader streamReader = createReader(connection); InputStreamReader streamReader = createReader(connection);
if (streamReader == null) { if (streamReader == null) {
return new HttpResponse<>(-1, null); return new HttpResponse<>(-1, null);
@@ -96,7 +100,7 @@ public class HttpUtils {
try { try {
int responseCode = connection.getResponseCode(); int responseCode = connection.getResponseCode();
T response = GSON.fromJson(streamReader, clazz); T response = gson.fromJson(streamReader, clazz);
return new HttpResponse<>(responseCode, response); return new HttpResponse<>(responseCode, response);
} catch (Exception ignored) { } catch (Exception ignored) {
return new HttpResponse<>(-1, null); return new HttpResponse<>(-1, null);
@@ -109,9 +113,7 @@ public class HttpUtils {
} }
@NonNull @NonNull
private static <T> HttpResponse<T> readResponseSilent( private <T> HttpResponse<T> readResponseSilent(HttpURLConnection connection, Class<T> clazz) {
HttpURLConnection connection,
Class<T> clazz) {
try { try {
return readResponse(connection, clazz); return readResponse(connection, clazz);
} catch (Exception ignored) { } catch (Exception ignored) {
@@ -120,7 +122,7 @@ public class HttpUtils {
} }
@NonNull @NonNull
private static DefaultHttpResponse readDefaultResponse(HttpURLConnection connection) { private DefaultHttpResponse readDefaultResponse(HttpURLConnection connection) {
InputStreamReader streamReader = createReader(connection); InputStreamReader streamReader = createReader(connection);
if (streamReader == null) { if (streamReader == null) {
return new DefaultHttpResponse(-1, null); return new DefaultHttpResponse(-1, null);
@@ -128,7 +130,7 @@ public class HttpUtils {
try { try {
int responseCode = connection.getResponseCode(); int responseCode = connection.getResponseCode();
JsonObject response = GSON.fromJson(streamReader, JsonObject.class); JsonObject response = gson.fromJson(streamReader, JsonObject.class);
return new DefaultHttpResponse(responseCode, response); return new DefaultHttpResponse(responseCode, response);
} catch (Exception exception) { } catch (Exception exception) {
throw new RuntimeException("Failed to read response", exception); throw new RuntimeException("Failed to read response", exception);
@@ -141,7 +143,7 @@ public class HttpUtils {
} }
@Nullable @Nullable
private static InputStreamReader createReader(HttpURLConnection connection) { private InputStreamReader createReader(HttpURLConnection connection) {
InputStream stream; InputStream stream;
try { try {
stream = connection.getInputStream(); stream = connection.getInputStream();
@@ -160,6 +162,11 @@ public class HttpUtils {
return null; return null;
} }
@Handler
public void onShutdown(ShutdownEvent ignored) {
executorService.shutdown();
}
@Getter @Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE)
public static class HttpResponse<T> { public static class HttpResponse<T> {

View File

@@ -29,6 +29,7 @@ import com.google.inject.Inject;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.plugin.annotation.DataDirectory;
import java.nio.file.Path; import java.nio.file.Path;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
@@ -69,4 +70,9 @@ public final class VelocityPlugin {
new PluginMessageModule() new PluginMessageModule()
); );
} }
@Subscribe
public void onProxyShutdown(ProxyShutdownEvent event) {
platform.disable();
}
} }