diff --git a/.gitignore b/.gitignore index 87ac35c..8414b8b 100644 --- a/.gitignore +++ b/.gitignore @@ -196,6 +196,7 @@ buildNumber.properties ### Waterfall Extras ### Waterfall-Proxy/ +run/ # Because Github lost their minds .idea/ diff --git a/BungeeCord-Patches/0044-Use-Log4j2-for-logging-and-TerminalConsoleAppender-f.patch b/BungeeCord-Patches/0044-Use-Log4j2-for-logging-and-TerminalConsoleAppender-f.patch new file mode 100644 index 0000000..97ec59a --- /dev/null +++ b/BungeeCord-Patches/0044-Use-Log4j2-for-logging-and-TerminalConsoleAppender-f.patch @@ -0,0 +1,529 @@ +From 51290fa75163f0f8ddcb508aa0b0aa20ffb00db1 Mon Sep 17 00:00:00 2001 +From: Minecrell +Date: Fri, 22 Sep 2017 12:46:47 +0200 +Subject: [PATCH] Use Log4j2 for logging and TerminalConsoleAppender for + console + + +diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml +index 7bc2dff7..6e8dd81e 100644 +--- a/bootstrap/pom.xml ++++ b/bootstrap/pom.xml +@@ -80,7 +80,17 @@ + + + ++ ++ ++ + ++ ++ ++ com.github.edwgiz ++ maven-shade-plugin.log4j2-cachefile-transformer ++ 2.8.1 ++ ++ + + + +diff --git a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +index ce1dd7a3..3d09b86a 100644 +--- a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java ++++ b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +@@ -56,6 +56,9 @@ public class BungeeCordLauncher + + if ( !options.has( "noconsole" ) ) + { ++ // Waterfall start - Use TerminalConsoleAppender ++ io.github.waterfallmc.waterfall.WaterfallConsole.readCommands(); ++ /* + String line; + while ( bungee.isRunning && ( line = bungee.getConsoleReader().readLine( ">" ) ) != null ) + { +@@ -64,6 +67,8 @@ public class BungeeCordLauncher + bungee.getConsole().sendMessage( ChatColor.RED + "Command not found" ); + } + } ++ */ ++ // Waterfall end + } + } + } +diff --git a/log4j/pom.xml b/log4j/pom.xml +new file mode 100644 +index 00000000..78045e1d +--- /dev/null ++++ b/log4j/pom.xml +@@ -0,0 +1,64 @@ ++ ++ 4.0.0 ++ ++ ++ io.github.waterfallmc ++ waterfall-parent ++ 1.12-SNAPSHOT ++ ../pom.xml ++ ++ ++ io.github.waterfallmc ++ waterfall-log4j ++ 1.12-SNAPSHOT ++ jar ++ ++ Waterfall-Log ++ Simplistic and performant Log4j2 based logger and console API designed for use with Waterfall and Minecraft related applications. ++ ++ ++ ++ ++ org.apache.logging.log4j ++ log4j-core ++ 2.9.1 ++ ++ ++ org.apache.logging.log4j ++ log4j-iostreams ++ 2.9.1 ++ ++ ++ org.apache.logging.log4j ++ log4j-jul ++ 2.9.1 ++ ++ ++ com.lmax ++ disruptor ++ 3.3.6 ++ runtime ++ ++ ++ ++ ++ net.minecrell ++ terminalconsoleappender ++ 1.0.0 ++ ++ ++ net.java.dev.jna ++ jna ++ 4.4.0 ++ runtime ++ ++ ++ ++ io.github.waterfallmc ++ waterfall-chat ++ ${project.version} ++ compile ++ ++ ++ +diff --git a/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/Log4JLogHandler.java b/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/Log4JLogHandler.java +new file mode 100644 +index 00000000..d5a1955b +--- /dev/null ++++ b/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/Log4JLogHandler.java +@@ -0,0 +1,55 @@ ++package io.github.waterfallmc.waterfall.log4j; ++ ++import com.google.common.base.Strings; ++import org.apache.logging.log4j.Level; ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.Logger; ++import org.apache.logging.log4j.jul.LevelTranslator; ++import org.apache.logging.log4j.message.MessageFormatMessage; ++ ++import java.util.Map; ++import java.util.MissingResourceException; ++import java.util.concurrent.ConcurrentHashMap; ++import java.util.logging.Handler; ++import java.util.logging.LogRecord; ++ ++/** ++ * A {@link Handler} that forwards all log messages to the Log4J logger. ++ * ++ *

We don't use Log4J's custom JUL LogManager currently, because it breaks ++ * adding custom handlers to JUL loggers. Some plugins may depend on that ++ * functionality...

++ */ ++class Log4JLogHandler extends Handler { ++ ++ private final Map cache = new ConcurrentHashMap<>(); ++ ++ @Override ++ public void publish(LogRecord record) { ++ Logger logger = cache.computeIfAbsent(Strings.nullToEmpty(record.getLoggerName()), LogManager::getLogger); ++ ++ String message = record.getMessage(); ++ if (record.getResourceBundle() != null) { ++ try { ++ message = record.getResourceBundle().getString(message); ++ } catch (MissingResourceException ignored) { ++ } ++ } ++ ++ final Level level = LevelTranslator.toLevel(record.getLevel()); ++ if (record.getParameters() != null && record.getParameters().length > 0) { ++ logger.log(level, new MessageFormatMessage(message, record.getParameters()), record.getThrown()); ++ } else { ++ logger.log(level, message, record.getThrown()); ++ } ++ } ++ ++ @Override ++ public void flush() { ++ } ++ ++ @Override ++ public void close() { ++ } ++ ++} +diff --git a/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/WaterfallLogger.java b/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/WaterfallLogger.java +new file mode 100644 +index 00000000..a0f7ed01 +--- /dev/null ++++ b/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/WaterfallLogger.java +@@ -0,0 +1,33 @@ ++package io.github.waterfallmc.waterfall.log4j; ++ ++import org.apache.logging.log4j.Level; ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.io.IoBuilder; ++import java.util.logging.Handler; ++import java.util.logging.Logger; ++ ++public final class WaterfallLogger { ++ ++ private WaterfallLogger() { ++ } ++ ++ public static Logger create() { ++ org.apache.logging.log4j.Logger redirect = LogManager.getRootLogger(); ++ System.setOut(IoBuilder.forLogger(redirect).setLevel(Level.INFO).buildPrintStream()); ++ System.setErr(IoBuilder.forLogger(redirect).setLevel(Level.ERROR).buildPrintStream()); ++ ++ Logger root = Logger.getLogger(""); ++ root.setUseParentHandlers(false); ++ ++ // Remove existing handlers ++ for (Handler handler : root.getHandlers()) { ++ root.removeHandler(handler); ++ } ++ ++ // Setup forward log handler ++ root.addHandler(new Log4JLogHandler()); ++ ++ return Logger.getLogger("BungeeCord"); ++ } ++ ++} +diff --git a/log4j/src/main/resources/log4j2.xml b/log4j/src/main/resources/log4j2.xml +new file mode 100644 +index 00000000..d4a81199 +--- /dev/null ++++ b/log4j/src/main/resources/log4j2.xml +@@ -0,0 +1,22 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/pom.xml b/pom.xml +index ecc35560..576944c3 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -56,6 +56,7 @@ + config + event + log ++ log4j + module + protocol + proxy +diff --git a/proxy/pom.xml b/proxy/pom.xml +index 1a5d036d..78326e6c 100644 +--- a/proxy/pom.xml ++++ b/proxy/pom.xml +@@ -70,7 +70,7 @@ + + + io.github.waterfallmc +- waterfall-log ++ waterfall-log4j + ${project.version} + compile + +diff --git a/proxy/src/main/java/Test.java b/proxy/src/main/java/Test.java +index 446dfe2f..7e7841a3 100644 +--- a/proxy/src/main/java/Test.java ++++ b/proxy/src/main/java/Test.java +@@ -22,6 +22,9 @@ public class Test + bungee.getLogger().info( "Enabled Waterfall version " + bungee.getVersion() ); + bungee.start(); + ++ // Waterfall start - Use TerminalConsoleAppender ++ io.github.waterfallmc.waterfall.WaterfallConsole.readCommands(); ++ /* + while ( bungee.isRunning ) + { + String line = bungee.getConsoleReader().readLine( ">" ); +@@ -32,6 +35,7 @@ public class Test + bungee.getConsole().sendMessage( ChatColor.RED + "Command not found" ); + } + } +- } ++ }*/ ++ // Waterfall end + } + } +diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/WaterfallConsole.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/WaterfallConsole.java +new file mode 100644 +index 00000000..ed33462e +--- /dev/null ++++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/WaterfallConsole.java +@@ -0,0 +1,95 @@ ++package io.github.waterfallmc.waterfall; ++ ++import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import net.md_5.bungee.BungeeCord; ++import net.md_5.bungee.ConsoleCommandCompleter; ++import net.md_5.bungee.api.ChatColor; ++import net.md_5.bungee.api.ProxyServer; ++import net.minecrell.terminalconsole.TerminalConsoleAppender; ++import org.jline.reader.EndOfFileException; ++import org.jline.reader.LineReader; ++import org.jline.reader.LineReaderBuilder; ++import org.jline.reader.UserInterruptException; ++import org.jline.terminal.Terminal; ++ ++import java.io.BufferedReader; ++import java.io.IOException; ++import java.io.InputStream; ++import java.io.InputStreamReader; ++import java.util.concurrent.Executor; ++import java.util.concurrent.Executors; ++ ++public final class WaterfallConsole { ++ ++ private static final Executor executor = Executors.newSingleThreadExecutor( ++ new ThreadFactoryBuilder().setNameFormat( "Console Command Thread #%d" ).build()); ++ ++ public static void readCommands() throws IOException { ++ Terminal terminal = TerminalConsoleAppender.getTerminal(); ++ if (terminal != null) { ++ readCommands(terminal); ++ } else { ++ readCommands(System.in); ++ } ++ } ++ ++ private static void runCommand(String input) { ++ final String command = input.trim(); ++ if (command.isEmpty()) { ++ return; ++ } ++ ++ executor.execute(() -> { ++ ProxyServer proxy = ProxyServer.getInstance(); ++ if (!proxy.getPluginManager().dispatchCommand(proxy.getConsole(), command)) { ++ proxy.getConsole().sendMessage(ChatColor.RED + "Command not found"); ++ } ++ }); ++ } ++ ++ private static void readCommands(Terminal terminal) throws IOException { ++ final BungeeCord bungee = BungeeCord.getInstance(); ++ final LineReader reader = LineReaderBuilder.builder() ++ .appName(ProxyServer.getInstance().getName()) ++ .terminal(terminal) ++ .completer(new ConsoleCommandCompleter(bungee)) ++ .build(); ++ ++ reader.unsetOpt(LineReader.Option.INSERT_TAB); ++ ++ TerminalConsoleAppender.setReader(reader); ++ ++ try { ++ String line; ++ while (bungee.isRunning) { ++ try { ++ line = reader.readLine("> "); ++ } catch (EndOfFileException ignored) { ++ // Continue reading after EOT ++ continue; ++ } ++ ++ if (line == null) { ++ break; ++ } ++ ++ runCommand(line); ++ } ++ } catch (UserInterruptException e) { ++ ProxyServer.getInstance().stop(); ++ } finally { ++ TerminalConsoleAppender.setReader(null); ++ } ++ } ++ ++ private static void readCommands(InputStream in) throws IOException { ++ final BungeeCord bungee = BungeeCord.getInstance(); ++ try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { ++ String line; ++ while (bungee.isRunning && (line = reader.readLine()) != null) { ++ runCommand(line); ++ } ++ } ++ } ++ ++} +diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +index 5e9484b7..b5d81439 100644 +--- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java ++++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +@@ -45,7 +45,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; + import java.util.logging.Handler; + import java.util.logging.Level; + import java.util.logging.Logger; +-import jline.console.ConsoleReader; + import lombok.Getter; + import lombok.Setter; + import lombok.Synchronized; +@@ -77,8 +76,6 @@ import net.md_5.bungee.compress.CompressFactory; + import net.md_5.bungee.conf.Configuration; + import net.md_5.bungee.conf.YamlConfig; + import net.md_5.bungee.forge.ForgeConstants; +-import net.md_5.bungee.log.BungeeLogger; +-import net.md_5.bungee.log.LoggingOutputStream; + import net.md_5.bungee.module.ModuleManager; + import net.md_5.bungee.netty.PipelineUtils; + import net.md_5.bungee.protocol.DefinedPacket; +@@ -88,7 +85,6 @@ import net.md_5.bungee.protocol.packet.PluginMessage; + import net.md_5.bungee.query.RemoteQuery; + import net.md_5.bungee.scheduler.BungeeScheduler; + import net.md_5.bungee.util.CaseInsensitiveMap; +-import org.fusesource.jansi.AnsiConsole; + + /** + * Main BungeeCord proxy class. +@@ -144,8 +140,12 @@ public class BungeeCord extends ProxyServer + private final File pluginsFolder = new File( "plugins" ); + @Getter + private final BungeeScheduler scheduler = new BungeeScheduler(); ++ // Waterfall start - Remove ConsoleReader for JLine 3 update ++ /* + @Getter + private final ConsoleReader consoleReader; ++ */ ++ // Waterfall end + @Getter + private final Logger logger; + public final Gson gson = new GsonBuilder() +@@ -197,6 +197,8 @@ public class BungeeCord extends ProxyServer + } + } + ++ // Waterfall start - Use TerminalConsoleAppender and Log4J ++ /* + // This is a workaround for quite possibly the weirdest bug I have ever encountered in my life! + // When jansi attempts to extract its natives, by default it tries to extract a specific version, + // using the loading class's implementation version. Normally this works completely fine, +@@ -215,6 +217,9 @@ public class BungeeCord extends ProxyServer + logger = new BungeeLogger( "BungeeCord", System.getProperty("bungee.log-file", "proxy.log"), consoleReader ); + System.setErr( new PrintStream( new LoggingOutputStream( logger, Level.SEVERE ), true ) ); + System.setOut( new PrintStream( new LoggingOutputStream( logger, Level.INFO ), true ) ); ++ */ ++ logger = io.github.waterfallmc.waterfall.log4j.WaterfallLogger.create(); ++ // Waterfall end + + if ( !Boolean.getBoolean( "net.md_5.bungee.native.disable" ) ) + { +diff --git a/proxy/src/main/java/net/md_5/bungee/ConsoleCommandCompleter.java b/proxy/src/main/java/net/md_5/bungee/ConsoleCommandCompleter.java +index 455b0787..9b57fc48 100644 +--- a/proxy/src/main/java/net/md_5/bungee/ConsoleCommandCompleter.java ++++ b/proxy/src/main/java/net/md_5/bungee/ConsoleCommandCompleter.java +@@ -2,7 +2,7 @@ package net.md_5.bungee; + + import com.google.common.collect.Iterables; + import com.google.common.util.concurrent.ThreadFactoryBuilder; +-import jline.console.completer.Completer; ++import org.jline.reader.Completer; // Waterfall - Update to JLine 3 + import net.md_5.bungee.api.ProxyServer; + + import java.util.ArrayList; +@@ -28,8 +28,9 @@ public class ConsoleCommandCompleter implements Completer + } + + @Override +- public int complete( String buffer, int cursor, List candidates ) ++ public void complete( org.jline.reader.LineReader reader, org.jline.reader.ParsedLine line, List candidates ) // Waterfall + { ++ final String buffer = line.line(); // Waterfall + Future> future = executor.submit( new Callable>() + { + @Override +@@ -44,6 +45,11 @@ public class ConsoleCommandCompleter implements Completer + try + { + Iterable offers = future.get(); ++ // Waterfall start - Update to JLine 3 ++ for (String completion : offers) { ++ candidates.add(new org.jline.reader.Candidate(completion)); ++ } ++ /* + if ( offers == null ) + { + return cursor; +@@ -59,6 +65,8 @@ public class ConsoleCommandCompleter implements Completer + { + return cursor - ( buffer.length() - lastSpace - 1 ); + } ++ */ ++ // Waterfall end + } catch ( ExecutionException ex ) + { + proxy.getLogger().log( Level.WARNING, "Unhandled exception when tab completing", ex ); +@@ -67,6 +75,6 @@ public class ConsoleCommandCompleter implements Completer + Thread.currentThread().interrupt(); + } + +- return cursor; ++ //return cursor; // Waterfall + } + } +diff --git a/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java b/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java +index 901fc5a3..8bb88bd4 100644 +--- a/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java ++++ b/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java +@@ -42,7 +42,7 @@ public class ModuleManager + ModuleVersion bungeeVersion = ModuleVersion.parse( proxy.getVersion() ); + if ( bungeeVersion == null ) + { +- System.out.println( "Couldn't detect bungee version. Custom build?" ); ++ proxy.getLogger().warning( "Couldn't detect bungee version. Custom build?" ); // Waterfall - Use logger + return; + } + +-- +2.14.1 +