如何回答标准输出模糊的标准输入?

时间:2015-01-02 12:49:12

标签: java io console nonblocking

我想要的是一个交互式控制台,它既可以打印日志消息,也可以同时接收命令。 Minecraft服务器的终端版本(不是GUI版本)完成了我想做的事情。

我几乎让我的交互式控制台处理了一个问题(这恰好将此问题与其他相关问题完全不同而不是重复):当服务器将消息记录到控制台时,那么输入到该控制台的任何内容都会迷路了。

更具体地说,Log.log方法使用回车符\r来覆盖当前行,该行恰好是在控制台中键入命令的行。虽然Log.log方法通过打印控制台字符>来补偿覆盖的命令行,但是在该控制台中输入的任何内容都会显示为已消失。更糟糕的是Scanner变量仍然存在于键盘命令中,键盘无法修改或删除。

我希望控制台能够保存输入该控制台的所有内容并同时打印出日志消息。

到目前为止我做了什么:

我一直在使用两个课程:LogCommandLog在服务器运行时输出日志消息并处理客户端。 Command解释由admin键入的命令,并根据switch块对其进行评估。虽然Log在主线程上运行,但Command在单独的线程上运行。

样本输出

假设我想启动服务器。如果我想启动它,我必须在控制台中输入命令start(服务器在启动时默认自动启动)。

[02/01/2015 9:40:19 PM] INFO - Server: version 0.1
> start


按下返回键后,输出应如下所示:

[02/01/2015 9:40:19 PM] INFO - Server: version 0.1
[02/01/2015 9:40:35 PM] INFO - Server: Starting server...
[02/01/2015 9:40:40 PM] INFO - Server: Server is now running at localhost:54555
> 

现在让我说我(错误)在控制台中输入一个命令。

[02/01/2015 9:40:19 PM] INFO - Server: version 0.1
[02/01/2015 9:40:35 PM] INFO - Server: Starting server...
[02/01/2015 9:40:40 PM] INFO - Server: Server is now running at localhost:54555
> stopp

在我意识到我在键入stop命令时出现拼写错误之前,服务器会打印出一条日志消息。

[02/01/2015 9:40:19 PM] INFO - Server: version 0.1
[02/01/2015 9:40:35 PM] INFO - Server: Starting server...
[02/01/2015 9:40:40 PM] INFO - Server: Server is now running at localhost:54555
[02/01/2015 9:41:02 PM] INFO - Server: Client connected with username user824294
> 

如上所述,无法将命令更改为其他内容(或者在这种情况下,修复stop命令的拼写错误。)

一些代码:

入口点

public static void main(String[] args) {
    Log.setup();

    // Set log level
    Log.setLogLevel(Log.DEBUG);

    Command.setup();

    //setupServer();
    //startServer();
}

Log.java

public class Log {
    public static BufferedWriter writer;

    public static final int VERBOSE = 0;
    public static final int DEBUG = 1;
    public static final int INFO = 2;
    public static final int WARNING = 3;
    public static final int ERROR = 4;

    private static int logLevel = 0;

    private static boolean showedLogLevel = false;

    public static void setup() {
        writer = new BufferedWriter(new OutputStreamWriter(System.out));
    }

    public static void log(String type, String key, String value) {
        if (!showedLogLevel && logLevel <= VERBOSE) {
            showedLogLevel = true;
            v("Log", "Log level is currently set to verbose.");
            v("Log", "Use Log.setLogLevel method to stop showing verbose messages such as this one.");
            v("Log", "Options (accessed by Log.*): VERBOSE, DEBUG, INFO, WARNING, ERROR");
        }


        String output = "[" + DateFormat.getDateTimeInstance().format(System.currentTimeMillis()) + "] "
                + type + " - "
                + key + ": "
                + value
                + "\n";

        // Since printing the log message would effectively destroy the console cursor, we need
        // to print the console cursor character again on a new line.
        if (Command.consoleCursor) {
            output += Command.consoleCursorCharacter;
        }

        try {
            writer.write("\r");
            writer.write(output);
            writer.flush();
        } catch (IOException e) {
            System.out.println("FATAL: Unable to log. Exiting...");
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static void v(String key, String value) {
        if (logLevel > VERBOSE) return;
        log("VERBOSE", key, value);
    }

    public static void d(String key, String value) {
        if (logLevel > DEBUG) return;
        log("DEBUG", key, value);
    }

    public static void i(String key, String value) {
        if (logLevel > INFO) return;
        log("INFO", key, value);
    }

    public static void w(String key, String value) {
        if (logLevel > WARNING) return;
        log("WARNING", key, value);
    }

    public static void e(String key, String value) {
        if (logLevel > ERROR) return;
        log("ERROR", key, value);
    }

    public static void setLogLevel(int _logLevel) {
        logLevel = _logLevel;
    }
}

Command.java

public class Command {
    public static Scanner inputConsole;
    public static boolean consoleCursor = false;
    public static String consoleCursorCharacter = "> ";

    public static void logHelp() {
        String helpStr = "Commands: start, stop, help, exit";
        Log.i("Help", helpStr);
    }

    public static void setup() {
        inputConsole = new Scanner(System.in);

        new Thread() {
            public void run() {
                String s;

                while (true) {
                    System.out.print(consoleCursorCharacter);
                    consoleCursor = true;
                    s = inputConsole.nextLine();
                    consoleCursor = false;
                    Command.evaluate(s);
                }
            }
        }.start();
    }

    public static void evaluate(String command) {
        String[] arguments = command.split(" ");

        if (arguments[0].isEmpty()) {
            return;
        }

        switch (arguments[0]) {
            case "start":
                Log.i("Server", "Starting server...");
                // Main.startServer();

                break;
            case "stop":
                Log.i("Server", "Stopping server...");
                // Main.stopServer();
                break;
            case "help":
                logHelp();
                break;
            case "exit":
                // Main.stopServer();
                System.exit(0);
                break;
            default:
                Log.e("Command", "Invalid command.");
                logHelp();
                break;
        }
    }
}

0 个答案:

没有答案