Implement super sexy console to close #315
This commit is contained in:
parent
3c1a5aabfd
commit
f0f1e71c93
@ -28,7 +28,7 @@
|
||||
<dependency>
|
||||
<groupId>com.ning</groupId>
|
||||
<artifactId>async-http-client</artifactId>
|
||||
<version>1.7.14</version>
|
||||
<version>1.7.17</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -31,6 +31,12 @@
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
<version>2.11</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-protocol</artifactId>
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import net.md_5.bungee.log.BungeeLogger;
|
||||
import net.md_5.bungee.reconnect.SQLReconnectHandler;
|
||||
import net.md_5.bungee.scheduler.BungeeScheduler;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
@ -16,9 +17,9 @@ import io.netty.channel.MultithreadEventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
@ -35,9 +36,11 @@ import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import jline.console.ConsoleReader;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.Synchronized;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.ReconnectHandler;
|
||||
@ -50,6 +53,7 @@ import net.md_5.bungee.api.plugin.PluginManager;
|
||||
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
||||
import net.md_5.bungee.command.*;
|
||||
import net.md_5.bungee.config.YamlConfig;
|
||||
import net.md_5.bungee.log.LoggingOutputStream;
|
||||
import net.md_5.bungee.netty.PipelineUtils;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
||||
@ -116,6 +120,10 @@ public class BungeeCord extends ProxyServer
|
||||
new NettyAsyncHttpProvider(
|
||||
new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(
|
||||
new NettyAsyncHttpProviderConfig().addProperty( NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE, executors ) ).setExecutorService( executors ).build() ) );
|
||||
@Getter
|
||||
private final ConsoleReader consoleReader;
|
||||
@Getter
|
||||
private final Logger logger;
|
||||
|
||||
|
||||
{
|
||||
@ -139,6 +147,28 @@ public class BungeeCord extends ProxyServer
|
||||
return (BungeeCord) ProxyServer.getInstance();
|
||||
}
|
||||
|
||||
public BungeeCord() throws IOException
|
||||
{
|
||||
consoleReader = new ConsoleReader();
|
||||
Runtime.getRuntime().addShutdownHook( new Thread( "JLine Cleanup Thread" )
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
consoleReader.getTerminal().restore();
|
||||
} catch ( Exception ex )
|
||||
{
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
logger = new BungeeLogger( this );
|
||||
System.setErr( new PrintStream( new LoggingOutputStream( logger, Level.SEVERE ), true ) );
|
||||
System.setOut( new PrintStream( new LoggingOutputStream( logger, Level.INFO ), true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new instance of BungeeCord.
|
||||
*
|
||||
@ -163,16 +193,14 @@ public class BungeeCord extends ProxyServer
|
||||
bungee.getLogger().info( "Enabled BungeeCord version " + bungee.getVersion() );
|
||||
bungee.start();
|
||||
|
||||
BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
|
||||
while ( bungee.isRunning )
|
||||
{
|
||||
String line = br.readLine();
|
||||
String line = bungee.getConsoleReader().readLine( ">" );
|
||||
if ( line != null )
|
||||
{
|
||||
boolean handled = getInstance().getPluginManager().dispatchCommand( ConsoleCommandSender.getInstance(), line );
|
||||
if ( !handled )
|
||||
if ( !bungee.getPluginManager().dispatchCommand( ConsoleCommandSender.getInstance(), line ) )
|
||||
{
|
||||
System.err.println( "Command not found" );
|
||||
bungee.getConsole().sendMessage( ChatColor.RED + "Command not found" );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -359,12 +387,6 @@ public class BungeeCord extends ProxyServer
|
||||
return translation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger()
|
||||
{
|
||||
return BungeeLogger.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<ProxiedPlayer> getPlayers()
|
||||
|
@ -1,99 +0,0 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Logger to handle formatting and storage of the proxy's logger.
|
||||
*/
|
||||
public class BungeeLogger extends Logger
|
||||
{
|
||||
|
||||
private static final Formatter formatter = new ConsoleLogFormatter();
|
||||
static final BungeeLogger instance = new BungeeLogger();
|
||||
|
||||
public BungeeLogger()
|
||||
{
|
||||
super( "BungeeCord", null );
|
||||
try
|
||||
{
|
||||
FileHandler handler = new FileHandler( "proxy.log", 1 << 24, 8, true );
|
||||
handler.setFormatter( formatter );
|
||||
addHandler( handler );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
System.err.println( "Could not register logger!" );
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogRecord record)
|
||||
{
|
||||
super.log( record );
|
||||
String message = formatter.format( record );
|
||||
if ( record.getLevel() == Level.SEVERE || record.getLevel() == Level.WARNING )
|
||||
{
|
||||
System.err.print( message );
|
||||
} else
|
||||
{
|
||||
System.out.print( message );
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConsoleLogFormatter extends Formatter
|
||||
{
|
||||
|
||||
private SimpleDateFormat formatter = new SimpleDateFormat( "HH:mm:ss" );
|
||||
|
||||
@Override
|
||||
public String format(LogRecord logrecord)
|
||||
{
|
||||
StringBuilder formatted = new StringBuilder();
|
||||
|
||||
formatted.append( formatter.format( logrecord.getMillis() ) );
|
||||
Level level = logrecord.getLevel();
|
||||
|
||||
if ( level == Level.FINEST )
|
||||
{
|
||||
formatted.append( " [FINEST] " );
|
||||
} else if ( level == Level.FINER )
|
||||
{
|
||||
formatted.append( " [FINER] " );
|
||||
} else if ( level == Level.FINE )
|
||||
{
|
||||
formatted.append( " [FINE] " );
|
||||
} else if ( level == Level.INFO )
|
||||
{
|
||||
formatted.append( " [INFO] " );
|
||||
} else if ( level == Level.WARNING )
|
||||
{
|
||||
formatted.append( " [WARNING] " );
|
||||
} else if ( level == Level.SEVERE )
|
||||
{
|
||||
formatted.append( " [SEVERE] " );
|
||||
}
|
||||
|
||||
formatted.append( formatMessage( logrecord ) );
|
||||
formatted.append( '\n' );
|
||||
Throwable throwable = logrecord.getThrown();
|
||||
|
||||
if ( throwable != null )
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
throwable.printStackTrace( new PrintWriter( writer ) );
|
||||
formatted.append( writer );
|
||||
}
|
||||
|
||||
return formatted.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,8 +3,8 @@ package net.md_5.bungee.command;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
|
||||
/**
|
||||
* Command sender representing the proxy console.
|
||||
@ -22,7 +22,7 @@ public class ConsoleCommandSender implements CommandSender
|
||||
@Override
|
||||
public void sendMessage(String message)
|
||||
{
|
||||
System.out.println( ChatColor.stripColor( message ) );
|
||||
ProxyServer.getInstance().getLogger().info( message );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
48
proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java
Normal file
48
proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java
Normal file
@ -0,0 +1,48 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
|
||||
public class BungeeLogger extends Logger
|
||||
{
|
||||
|
||||
private final BungeeCord bungee;
|
||||
private final ColouredWriter writer;
|
||||
private final Formatter formatter = new ConciseFormatter();
|
||||
private final LogDispatcher dispatcher = new LogDispatcher( this );
|
||||
|
||||
public BungeeLogger(BungeeCord bungee)
|
||||
{
|
||||
super( "BungeeCord", null );
|
||||
this.bungee = bungee;
|
||||
this.writer = new ColouredWriter( bungee.getConsoleReader() );
|
||||
|
||||
try
|
||||
{
|
||||
FileHandler handler = new FileHandler( "proxy.log", 1 << 24, 8, true );
|
||||
handler.setFormatter( formatter );
|
||||
addHandler( handler );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
System.err.println( "Could not register logger!" );
|
||||
ex.printStackTrace();
|
||||
}
|
||||
dispatcher.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogRecord record)
|
||||
{
|
||||
dispatcher.queue( record );
|
||||
}
|
||||
|
||||
void doLog(LogRecord record)
|
||||
{
|
||||
super.log( record );
|
||||
writer.print( formatter.format( record ) );
|
||||
}
|
||||
}
|
60
proxy/src/main/java/net/md_5/bungee/log/ColouredWriter.java
Normal file
60
proxy/src/main/java/net/md_5/bungee/log/ColouredWriter.java
Normal file
@ -0,0 +1,60 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import jline.console.ConsoleReader;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
public class ColouredWriter
|
||||
{
|
||||
|
||||
private final Map<ChatColor, String> replacements = new EnumMap<>( ChatColor.class );
|
||||
private final ChatColor[] colors = ChatColor.values();
|
||||
private final ConsoleReader console;
|
||||
|
||||
public ColouredWriter(ConsoleReader console)
|
||||
{
|
||||
this.console = console;
|
||||
|
||||
replacements.put( ChatColor.BLACK, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLACK ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_BLUE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLUE ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_GREEN, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.GREEN ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_AQUA, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.CYAN ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_RED, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.RED ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_PURPLE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.MAGENTA ).boldOff().toString() );
|
||||
replacements.put( ChatColor.GOLD, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.YELLOW ).boldOff().toString() );
|
||||
replacements.put( ChatColor.GRAY, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.WHITE ).boldOff().toString() );
|
||||
replacements.put( ChatColor.DARK_GRAY, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLACK ).bold().toString() );
|
||||
replacements.put( ChatColor.BLUE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.BLUE ).bold().toString() );
|
||||
replacements.put( ChatColor.GREEN, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.GREEN ).bold().toString() );
|
||||
replacements.put( ChatColor.AQUA, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.CYAN ).bold().toString() );
|
||||
replacements.put( ChatColor.RED, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.RED ).bold().toString() );
|
||||
replacements.put( ChatColor.LIGHT_PURPLE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.MAGENTA ).bold().toString() );
|
||||
replacements.put( ChatColor.YELLOW, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.YELLOW ).bold().toString() );
|
||||
replacements.put( ChatColor.WHITE, Ansi.ansi().a( Ansi.Attribute.RESET ).fg( Ansi.Color.WHITE ).bold().toString() );
|
||||
replacements.put( ChatColor.MAGIC, Ansi.ansi().a( Ansi.Attribute.BLINK_SLOW ).toString() );
|
||||
replacements.put( ChatColor.BOLD, Ansi.ansi().a( Ansi.Attribute.UNDERLINE_DOUBLE ).toString() );
|
||||
replacements.put( ChatColor.STRIKETHROUGH, Ansi.ansi().a( Ansi.Attribute.STRIKETHROUGH_ON ).toString() );
|
||||
replacements.put( ChatColor.UNDERLINE, Ansi.ansi().a( Ansi.Attribute.UNDERLINE ).toString() );
|
||||
replacements.put( ChatColor.ITALIC, Ansi.ansi().a( Ansi.Attribute.ITALIC ).toString() );
|
||||
replacements.put( ChatColor.RESET, Ansi.ansi().a( Ansi.Attribute.RESET ).toString() );
|
||||
}
|
||||
|
||||
public void print(String s)
|
||||
{
|
||||
for ( ChatColor color : colors )
|
||||
{
|
||||
s = s.replaceAll( "(?i)" + color.toString(), replacements.get( color ) );
|
||||
}
|
||||
try
|
||||
{
|
||||
console.print( ConsoleReader.RESET_LINE + s + Ansi.ansi().reset().toString() );
|
||||
console.drawLine();
|
||||
console.flush();
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
public class ConciseFormatter extends Formatter
|
||||
{
|
||||
|
||||
private final DateFormat date = new SimpleDateFormat( "HH:mm:ss" );
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record)
|
||||
{
|
||||
StringBuilder formatted = new StringBuilder();
|
||||
|
||||
formatted.append( date.format( record.getMillis() ) );
|
||||
formatted.append( " [" );
|
||||
formatted.append( record.getLevel().getLocalizedName() );
|
||||
formatted.append( "] " );
|
||||
formatted.append( formatMessage( record ) );
|
||||
formatted.append( '\n' );
|
||||
if ( record.getThrown() != null )
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
record.getThrown().printStackTrace( new PrintWriter( writer ) );
|
||||
formatted.append( writer );
|
||||
}
|
||||
|
||||
return formatted.toString();
|
||||
}
|
||||
}
|
48
proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java
Normal file
48
proxy/src/main/java/net/md_5/bungee/log/LogDispatcher.java
Normal file
@ -0,0 +1,48 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
public class LogDispatcher extends Thread
|
||||
{
|
||||
|
||||
private final BungeeLogger logger;
|
||||
private final BlockingQueue<LogRecord> queue = new LinkedBlockingQueue<>();
|
||||
|
||||
public LogDispatcher(BungeeLogger logger)
|
||||
{
|
||||
super( "BungeeCord Logger Thread - " + logger );
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
while ( !isInterrupted() )
|
||||
{
|
||||
LogRecord record;
|
||||
try
|
||||
{
|
||||
record = queue.take();
|
||||
} catch ( InterruptedException ex )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.doLog( record );
|
||||
}
|
||||
for ( LogRecord record : queue )
|
||||
{
|
||||
logger.doLog( record );
|
||||
}
|
||||
}
|
||||
|
||||
public void queue(LogRecord record)
|
||||
{
|
||||
if ( !isInterrupted() )
|
||||
{
|
||||
queue.add( record );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class LoggingOutputStream extends ByteArrayOutputStream
|
||||
{
|
||||
|
||||
private static final String separator = System.getProperty( "line.separator" );
|
||||
/*========================================================================*/
|
||||
private final Logger logger;
|
||||
private final Level level;
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException
|
||||
{
|
||||
String contents = toString();
|
||||
super.reset();
|
||||
if ( !contents.isEmpty() && !contents.equals( separator ) )
|
||||
{
|
||||
logger.logp( level, "", "", contents );
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user