diff --git a/pom.xml b/pom.xml index 0f50a3c..250aea7 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,16 @@ 4.1.82.Final provided + + org.slf4j + slf4j-api + 2.0.7 + + + org.slf4j + slf4j-simple + 2.0.7 + org.spigotmc spigot-api diff --git a/src/main/java/gg/playit/control/ChannelSetup.java b/src/main/java/gg/playit/control/ChannelSetup.java index 2b013fe..252ac27 100644 --- a/src/main/java/gg/playit/control/ChannelSetup.java +++ b/src/main/java/gg/playit/control/ChannelSetup.java @@ -6,6 +6,7 @@ import gg.playit.messages.ControlRequestWriter; import gg.playit.messages.DecodeException; import gg.playit.minecraft.utils.DecoderException; +import gg.playit.minecraft.utils.Logger; import java.io.IOException; import java.net.*; @@ -13,12 +14,11 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Comparator; -import java.util.logging.Logger; public class ChannelSetup { public static final int CONTROL_PORT = 5525; - static Logger log = Logger.getLogger(ChannelSetup.class.getName()); + static Logger log = new Logger(ChannelSetup.class.getName()); public static FindSuitableChannel start() throws UnknownHostException { InetAddress[] allByName = InetAddress.getAllByName("control.playit.gg"); @@ -155,7 +155,7 @@ public PlayitControlChannel authenticate(String secretKey) throws IOException { if (response instanceof ControlFeedReader.Error error) { if (error == ControlFeedReader.Error.RequestQueued) { - log.info("request queued, waiting 1 second before resend"); + log.debug("request queued, waiting 1 second before resend"); try { Thread.sleep(1000); diff --git a/src/main/java/gg/playit/control/PlayitControlChannel.java b/src/main/java/gg/playit/control/PlayitControlChannel.java index 8373556..03d8294 100644 --- a/src/main/java/gg/playit/control/PlayitControlChannel.java +++ b/src/main/java/gg/playit/control/PlayitControlChannel.java @@ -4,6 +4,7 @@ import gg.playit.messages.ControlFeedReader; import gg.playit.messages.ControlRequestWriter; import gg.playit.messages.DecodeException; +import gg.playit.minecraft.utils.Logger; import java.io.Closeable; import java.io.IOException; @@ -16,12 +17,11 @@ import java.time.Instant; import java.util.Arrays; import java.util.Optional; -import java.util.logging.Logger; import static gg.playit.control.ChannelSetup.CONTROL_PORT; public class PlayitControlChannel implements Closeable { - static Logger log = Logger.getLogger(ChannelSetup.class.getName()); + static Logger log = new Logger(ChannelSetup.class.getName()); ApiClient apiClient; DatagramSocket socket; @@ -57,7 +57,7 @@ public Optional update() throws IOException { var tillExpire = this.registered.expiresAt - now; if (tillExpire < 60_000 && 10_000 < now - lastKeepAlive) { - log.info("send keep alive"); + log.debug("send keep alive"); lastKeepAlive = now; this.sendKeepAlive(); diff --git a/src/main/java/gg/playit/minecraft/PlayitBukkit.java b/src/main/java/gg/playit/minecraft/PlayitBukkit.java index e9757f4..b224570 100644 --- a/src/main/java/gg/playit/minecraft/PlayitBukkit.java +++ b/src/main/java/gg/playit/minecraft/PlayitBukkit.java @@ -3,6 +3,7 @@ import gg.playit.api.ApiClient; import gg.playit.api.ApiError; import gg.playit.api.models.Notice; +import gg.playit.minecraft.utils.Logger; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import org.bukkit.Bukkit; @@ -17,13 +18,14 @@ import java.io.IOException; import java.util.List; -import java.util.logging.Logger; public final class PlayitBukkit extends JavaPlugin implements Listener { public static final String CFG_AGENT_SECRET_KEY = "agent-secret"; public static final String CFG_CONNECTION_TIMEOUT_SECONDS = "mc-timeout-sec"; + public static final String CFG_DEBUG_LOGGING = "debug-logging"; + private static boolean debugLogging = false; - static Logger log = Logger.getLogger(PlayitBukkit.class.getName()); + static Logger log = new Logger(PlayitBukkit.class.getName()); final EventLoopGroup eventGroup = new NioEventLoopGroup(); private final Object managerSync = new Object(); @@ -40,15 +42,24 @@ public void onEnable() { command.setExecutor(this); command.setTabCompleter(this); } else { - log.severe("failed to setup command /playit"); + log.error("failed to setup command /playit"); } getConfig().addDefault("agent-secret", ""); + getConfig().addDefault("debug-logging", "false"); saveDefaultConfig(); var secretKey = getConfig().getString("agent-secret"); resetConnection(secretKey); + var debugLogging = getConfig().getString(CFG_DEBUG_LOGGING); + if ("true".equals(debugLogging)) { + setDebugLogging(true); + } else if ("false".equals(debugLogging)) { + setDebugLogging(false); + } + getConfig().set(CFG_DEBUG_LOGGING, hasDebugLogging()); + try { PluginManager pm = Bukkit.getServer().getPluginManager(); pm.registerEvents(this, this); @@ -239,7 +250,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St log.warning("failed to create guest secret: " + e); sender.sendMessage("error: " + e.getMessage()); } catch (IOException e) { - log.severe("failed to create guest secret: " + e); + log.error("failed to create guest secret: " + e); } }).start(); @@ -247,6 +258,24 @@ public boolean onCommand(CommandSender sender, Command command, String label, St } } + if (args.length > 0 && args[0].equals("logging")) { + if (args.length > 1 && args[1].equals("enable")) { + getConfig().set(CFG_DEBUG_LOGGING, true); + saveConfig(); + setDebugLogging(true); + sender.sendMessage("enabled debug logging"); + return true; + } + + if (args.length > 1 && args[1].equals("disable")) { + getConfig().set(CFG_DEBUG_LOGGING, false); + saveConfig(); + setDebugLogging(false); + sender.sendMessage("disabled debug logging"); + return true; + } + } + return false; } @@ -286,7 +315,7 @@ public List onTabComplete(CommandSender sender, Command command, String } if (argCount == 0) { - return List.of("agent", "tunnel", "prop", "account"); + return List.of("agent", "tunnel", "prop", "account", "logging"); } if (args[0].equals("account")) { @@ -321,6 +350,12 @@ public List onTabComplete(CommandSender sender, Command command, String } } + if (args[0].equals("logging")) { + if (argCount == 1) { + return List.of("enable", "disable"); + } + } + return null; } @@ -331,4 +366,12 @@ public void onDisable() { playitManager = null; } } + + public static boolean hasDebugLogging() { + return debugLogging; + } + + public void setDebugLogging(boolean debugLogging) { + PlayitBukkit.debugLogging = debugLogging; + } } diff --git a/src/main/java/gg/playit/minecraft/PlayitKeysSetup.java b/src/main/java/gg/playit/minecraft/PlayitKeysSetup.java index 7bf5eec..6edb26c 100644 --- a/src/main/java/gg/playit/minecraft/PlayitKeysSetup.java +++ b/src/main/java/gg/playit/minecraft/PlayitKeysSetup.java @@ -8,15 +8,15 @@ import gg.playit.api.models.PortType; import gg.playit.api.models.TunnelType; import gg.playit.minecraft.utils.Hex; +import gg.playit.minecraft.utils.Logger; import java.io.IOException; import java.net.InetAddress; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Logger; public class PlayitKeysSetup { - private static final Logger log = Logger.getLogger(PlayitKeysSetup.class.getName()); + private static final Logger log = new Logger(PlayitKeysSetup.class.getName()); public final AtomicInteger state; public static final int STATE_INIT = 1; public static final int STATE_MISSING_SECRET = 2; @@ -55,7 +55,7 @@ public PlayitKeys progress() throws IOException { } state.compareAndSet(STATE_INIT, STATE_CHECKING_SECRET); - log.info("secret key found, checking"); + log.debug("secret key found, checking"); return null; } case STATE_MISSING_SECRET -> { @@ -63,10 +63,10 @@ public PlayitKeys progress() throws IOException { byte[] array = new byte[8]; new Random().nextBytes(array); claimCode = Hex.encodeHexString(array); - log.info("secret key not set, generate claim code: " + claimCode); + log.debug("secret key not set, generate claim code: " + claimCode); } - log.info("trying to exchange claim code for secret"); + log.debug("trying to exchange claim code for secret"); keys.secretKey = openClient.exchangeClaimForSecret(claimCode); if (keys.secretKey == null) { @@ -78,7 +78,7 @@ public PlayitKeys progress() throws IOException { return null; } case STATE_CHECKING_SECRET -> { - log.info("check secret"); + log.debug("check secret"); var api = new ApiClient(keys.secretKey); try { @@ -94,11 +94,11 @@ public PlayitKeys progress() throws IOException { } catch (ApiError e) { if (e.statusCode == 401 || e.statusCode == 400) { if (claimCode == null) { - log.info("secret key invalid, starting over"); + log.debug("secret key invalid, starting over"); state.compareAndSet(STATE_CHECKING_SECRET, STATE_MISSING_SECRET); } else { state.compareAndSet(STATE_CHECKING_SECRET, STATE_ERROR); - log.info("secret failed verification after creating, moving to error state"); + log.debug("secret failed verification after creating, moving to error state"); } return null; @@ -116,12 +116,12 @@ public PlayitKeys progress() throws IOException { for (AccountTunnel tunnel : tunnels.tunnels) { if (tunnel.tunnelType == TunnelType.MinecraftJava) { keys.tunnelAddress = tunnel.displayAddress; - log.info("found minecraft java tunnel: " + keys.tunnelAddress); + log.debug("found minecraft java tunnel: " + keys.tunnelAddress); return keys; } } - log.info("create new minecraft java tunnel"); + log.debug("create new minecraft java tunnel"); var create = new CreateTunnel(); create.localIp = "127.0.0.1"; diff --git a/src/main/java/gg/playit/minecraft/PlayitManager.java b/src/main/java/gg/playit/minecraft/PlayitManager.java index fa30346..fd4ef98 100644 --- a/src/main/java/gg/playit/minecraft/PlayitManager.java +++ b/src/main/java/gg/playit/minecraft/PlayitManager.java @@ -4,6 +4,7 @@ import gg.playit.api.models.Notice; import gg.playit.control.PlayitControlChannel; import gg.playit.messages.ControlFeedReader; +import gg.playit.minecraft.utils.Logger; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -11,10 +12,9 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Logger; public class PlayitManager implements Runnable { - static Logger log = Logger.getLogger(PlayitManager.class.getName()); + static Logger log = new Logger(PlayitManager.class.getName()); private final AtomicInteger state = new AtomicInteger(STATE_INIT); private final PlayitConnectionTracker tracker = new PlayitConnectionTracker(); @@ -86,11 +86,11 @@ public void run() { keys = setup.progress(); if (keys != null) { - log.info("keys and tunnel setup"); + log.debug("keys and tunnel setup"); break; } } catch (IOException e) { - log.severe("got error during setup: " + e); + log.error("got error during setup: " + e); try { Thread.sleep(3000); @@ -120,7 +120,7 @@ public void run() { } if (keys == null) { - log.info("shutdown reached, tunnel connection never started"); + log.debug("shutdown reached, tunnel connection never started"); return; } @@ -136,7 +136,7 @@ public void run() { try { var key = api.createGuestWebSessionKey(); var url = "https://playit.gg/login/guest-account/" + key; - log.info("setup playit.gg account: " + url); + log.debug("setup playit.gg account: " + url); if (state.get() == STATE_SHUTDOWN) { return; @@ -149,7 +149,7 @@ public void run() { } } } catch (IOException e) { - log.severe("failed to generate web session key: " + e); + log.error("failed to generate web session key: " + e); } } else if (!keys.isEmailVerified) { plugin.broadcast(ChatColor.RED + "WARNING: " + ChatColor.RESET + "email associated with playit.gg account is not verified"); @@ -174,11 +174,11 @@ public void run() { var feedMessage = messageOpt.get(); if (feedMessage instanceof ControlFeedReader.NewClient newClient) { - log.info("got new client: " + feedMessage); + log.debug("got new client: " + feedMessage); var key = newClient.peerAddr + "-" + newClient.connectAddr; if (tracker.addConnection(key)) { - log.info("starting tcp tunnel for client"); + log.debug("starting tcp tunnel for client"); new PlayitTcpTunnel( new InetSocketAddress(InetAddress.getByAddress(newClient.peerAddr.ipBytes), Short.toUnsignedInt(newClient.peerAddr.portNumber)), @@ -197,7 +197,7 @@ public void run() { } } catch (IOException e) { state.compareAndSet(STATE_ONLINE, STATE_ERROR_WAITING); - log.severe("failed when communicating with tunnel server, error: " + e); + log.error("failed when communicating with tunnel server, error: " + e); if (e.getMessage().contains("invalid authentication")) { state.set(STATE_INVALID_AUTH); @@ -209,17 +209,17 @@ public void run() { } } finally { if (state.compareAndSet(STATE_SHUTDOWN, STATE_OFFLINE)) { - log.info("control channel shutdown"); + log.debug("control channel shutdown"); } else if (state.compareAndSet(STATE_ERROR_WAITING, STATE_CONNECTING)) { - log.info("trying to connect again"); + log.debug("trying to connect again"); } else if (state.compareAndSet(STATE_ONLINE, STATE_CONNECTING)) { log.warning("unexpected state ONLINE, moving to CONNECTING"); } if (state.get() == STATE_CONNECTING) { - log.info("failed to connect, retrying"); + log.debug("failed to connect, retrying"); } if (state.get() == STATE_INVALID_AUTH) { - log.info("invalid auth, done trying"); + log.debug("invalid auth, done trying"); } } } diff --git a/src/main/java/gg/playit/minecraft/PlayitTcpTunnel.java b/src/main/java/gg/playit/minecraft/PlayitTcpTunnel.java index 0c8adcd..183ff1e 100644 --- a/src/main/java/gg/playit/minecraft/PlayitTcpTunnel.java +++ b/src/main/java/gg/playit/minecraft/PlayitTcpTunnel.java @@ -1,5 +1,6 @@ package gg.playit.minecraft; +import gg.playit.minecraft.utils.Logger; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -10,10 +11,9 @@ import org.bukkit.Server; import java.net.InetSocketAddress; -import java.util.logging.Logger; public class PlayitTcpTunnel { - static Logger log = Logger.getLogger(PlayitTcpTunnel.class.getName()); + static Logger log = new Logger(PlayitTcpTunnel.class.getName()); private final InetSocketAddress trueIp; private final EventLoopGroup group; @@ -64,7 +64,7 @@ protected void initChannel(SocketChannel socketChannel) { } }); - log.info("start connection to " + tunnelClaimAddress + " to claim client"); + log.debug("start connection to " + tunnelClaimAddress + " to claim client"); clientBootstrap.connect().addListener((ChannelFutureListener) future -> { if (!future.isSuccess()) { log.warning("failed to establish connection to tunnel claim" + tunnelClaimAddress); @@ -72,13 +72,13 @@ protected void initChannel(SocketChannel socketChannel) { return; } - log.info("connected to tunnel server, sending claim token"); + log.debug("connected to tunnel server, sending claim token"); future.channel().writeAndFlush(Unpooled.wrappedBuffer(tunnelClaimToken)).addListener(f -> { if (!f.isSuccess()) { log.warning("failed to send claim token"); } else { - log.info("claim token sent"); + log.debug("claim token sent"); } }); }); @@ -110,10 +110,10 @@ protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws E byteBuf.readBytes(confirmBytesRemaining); confirmBytesRemaining = 0; - log.info("connection to tunnel server has been established"); + log.debug("connection to tunnel server has been established"); if (addChannelToMinecraftServer()) { - log.info("added channel to minecraft server"); + log.debug("added channel to minecraft server"); return; } @@ -130,7 +130,7 @@ protected void initChannel(SocketChannel socketChannel) { } }); - log.info("connecting to minecraft server at " + minecraftServerAddress); + log.debug("connecting to minecraft server at " + minecraftServerAddress); minecraftClient.connect().addListener((ChannelFutureListener) future -> { if (!future.isSuccess()) { log.warning("failed to connect to local minecraft server"); @@ -139,7 +139,7 @@ protected void initChannel(SocketChannel socketChannel) { return; } - log.info("connected to local minecraft server"); + log.debug("connected to local minecraft server"); if (byteBuf.readableBytes() == 0) { byteBuf.release(); @@ -178,47 +178,47 @@ protected void initChannel(SocketChannel socketChannel) { private boolean addChannelToMinecraftServer() { ReflectionHelper reflect = new ReflectionHelper(); - log.info("Reflect: " + reflect); + log.debug("Reflect: " + reflect); Object minecraftServer = reflect.getMinecraftServer(server); if (minecraftServer == null) { - log.info("failed to get Minecraft server from Bukkit.getServer()"); + log.debug("failed to get Minecraft server from Bukkit.getServer()"); return false; } Object serverConnection = reflect.serverConnectionFromMCServer(minecraftServer); if (serverConnection == null) { - log.info("failed to get ServerConnection from Minecraft Server"); + log.debug("failed to get ServerConnection from Minecraft Server"); return false; } Object legacyPingHandler = reflect.newLegacyPingHandler(serverConnection); if (legacyPingHandler == null) { - log.info("legacyPingHandler is null"); + log.debug("legacyPingHandler is null"); return false; } Object packetSplitter = reflect.newPacketSplitter(); if (packetSplitter == null) { - log.info("packetSplitter is null"); + log.debug("packetSplitter is null"); return false; } Object packetDecoder = reflect.newServerBoundPacketDecoder(); if (packetDecoder == null) { - log.info("packetDecoder is null"); + log.debug("packetDecoder is null"); return false; } Object packetPrepender = reflect.newPacketPrepender(); if (packetPrepender == null) { - log.info("packetPrepender is null"); + log.debug("packetPrepender is null"); return false; } Object packetEncoder = reflect.newClientBoundPacketEncoder(); if (packetEncoder == null) { - log.info("packetEncoder is null"); + log.debug("packetEncoder is null"); return false; } @@ -237,18 +237,18 @@ private boolean addChannelToMinecraftServer() { } if (networkManager == null) { - log.info("networkManager is null"); + log.debug("networkManager is null"); return false; } Object handshakeListener = reflect.newHandshakeListener(minecraftServer, networkManager); if (handshakeListener == null) { - log.info("handshakeListener is null"); + log.debug("handshakeListener is null"); return false; } if (!reflect.networkManagerSetListener(networkManager, handshakeListener)) { - log.info("failed to set handshake listener on network manager"); + log.debug("failed to set handshake listener on network manager"); return false; } @@ -267,7 +267,7 @@ private boolean addChannelToMinecraftServer() { .addLast("packet_handler", (ChannelHandler) networkManager); if (!reflect.addToServerConnections(serverConnection, networkManager)) { - log.info("failed to add to server connections"); + log.debug("failed to add to server connections"); tunnelChannel.pipeline().remove("timeout"); tunnelChannel.pipeline().remove("legacy_query"); diff --git a/src/main/java/gg/playit/minecraft/ReflectionHelper.java b/src/main/java/gg/playit/minecraft/ReflectionHelper.java index 1e81801..58bd9f0 100644 --- a/src/main/java/gg/playit/minecraft/ReflectionHelper.java +++ b/src/main/java/gg/playit/minecraft/ReflectionHelper.java @@ -1,5 +1,6 @@ package gg.playit.minecraft; +import gg.playit.minecraft.utils.Logger; import io.netty.channel.AbstractChannel; import io.netty.channel.Channel; import org.bukkit.Server; @@ -9,10 +10,9 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.logging.Logger; public class ReflectionHelper { - static Logger log = Logger.getLogger(ReflectionHelper.class.getName()); + static Logger log = new Logger(ReflectionHelper.class.getName()); private final Class ServerConnection; private final Class LegacyPingHandler; diff --git a/src/main/java/gg/playit/minecraft/utils/Logger.java b/src/main/java/gg/playit/minecraft/utils/Logger.java new file mode 100644 index 0000000..d755d9e --- /dev/null +++ b/src/main/java/gg/playit/minecraft/utils/Logger.java @@ -0,0 +1,39 @@ +package gg.playit.minecraft.utils; + +import gg.playit.minecraft.PlayitBukkit; +import org.slf4j.LoggerFactory; + +public class Logger { + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger("playit-minecraft-plugin"); + private final ServerConfiguration serverConfig; + public final String className; + + public Logger(String className) { + this.className = className; + this.serverConfig = new ServerConfiguration(); + + serverConfig.init(); + } + + public void info(String format, Object... data) { + LOGGER.info("[" + className + "] " + format, data); + } + + public void debug(String format, Object... data) { + if (PlayitBukkit.hasDebugLogging() || serverConfig.debugModeEnabled()) { + LOGGER.info("[" + className + "] " + format, data); + } + } + + public void error(String format, Object... data) { + if (PlayitBukkit.hasDebugLogging() || serverConfig.debugModeEnabled()) { + LOGGER.error("[" + className + "] " + format, data); + } + } + + public void warning(String format, Object... data) { + if (PlayitBukkit.hasDebugLogging() || serverConfig.debugModeEnabled()) { + LOGGER.warn("[" + className + "] " + format, data); + } + } +} diff --git a/src/main/java/gg/playit/minecraft/utils/ServerConfiguration.java b/src/main/java/gg/playit/minecraft/utils/ServerConfiguration.java new file mode 100644 index 0000000..517bdc3 --- /dev/null +++ b/src/main/java/gg/playit/minecraft/utils/ServerConfiguration.java @@ -0,0 +1,32 @@ +package gg.playit.minecraft.utils; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; + +public class ServerConfiguration { + private final FileConfiguration spigotConfig; + + public ServerConfiguration() { + spigotConfig = new YamlConfiguration(); + } + + public void init() { + try { + spigotConfig.load(new File("spigot.yml")); + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + } + + public boolean debugModeEnabled() { + if (spigotConfig != null) { + return spigotConfig.getBoolean("settings.debug"); + } else { + return false; + } + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index dfbfd86..e99f250 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,2 +1,3 @@ mc-timeout-sec: 30 -agent-secret: "" \ No newline at end of file +agent-secret: "" +debug-logging: false \ No newline at end of file