Zond: добавляем коммандную строку JLine2
Merge branch 'dev-zond-jline' into dev-zond
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
group = 'asys'
|
group = 'asys'
|
||||||
version = '0.5.6-SNAPSHOT'
|
version = '0.6-SNAPSHOT'
|
||||||
|
|
||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
|
|
||||||
@@ -46,4 +46,5 @@ dependencies {
|
|||||||
includedEx group: 'org.apache.commons', name: 'commons-exec', version: '1.3'
|
includedEx group: 'org.apache.commons', name: 'commons-exec', version: '1.3'
|
||||||
included group: 'io.netty', name: 'netty-codec', version: nettyVersion
|
included group: 'io.netty', name: 'netty-codec', version: nettyVersion
|
||||||
included group: 'com.google.guava', name: 'guava', version: '21.0'
|
included group: 'com.google.guava', name: 'guava', version: '21.0'
|
||||||
|
included group: 'jline', name: 'jline', version: '2.13'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,8 @@
|
|||||||
package asys.zond;
|
package asys.zond;
|
||||||
|
|
||||||
import asys.zond.proxy.Connector;
|
import asys.zond.proxy.Connector;
|
||||||
import org.apache.commons.exec.CommandLine;
|
import asys.zond.shell.Shell;
|
||||||
import org.apache.commons.exec.DefaultExecutor;
|
import org.apache.commons.exec.*;
|
||||||
import org.apache.commons.exec.ExecuteException;
|
|
||||||
import org.apache.commons.exec.PumpStreamHandler;
|
|
||||||
import org.fusesource.jansi.Ansi;
|
import org.fusesource.jansi.Ansi;
|
||||||
import org.fusesource.jansi.Ansi.Color;
|
import org.fusesource.jansi.Ansi.Color;
|
||||||
import org.fusesource.jansi.AnsiConsole;
|
import org.fusesource.jansi.AnsiConsole;
|
||||||
@@ -19,6 +17,8 @@ import java.util.Arrays;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
private static ExecuteWatchdog watchdog;
|
||||||
|
|
||||||
private static void printLogo() {
|
private static void printLogo() {
|
||||||
System.out.println(
|
System.out.println(
|
||||||
Ansi.ansi().reset()
|
Ansi.ansi().reset()
|
||||||
@@ -28,11 +28,14 @@ public class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void log(String message){
|
public static void log(String message){
|
||||||
System.out.println(
|
String msg = Ansi.ansi().reset()
|
||||||
Ansi.ansi().reset()
|
|
||||||
.bg(Color.BLUE).fg(Color.WHITE).a("[ASys Zond] ")
|
.bg(Color.BLUE).fg(Color.WHITE).a("[ASys Zond] ")
|
||||||
.a(message).reset()
|
.a(message).reset().toString();
|
||||||
);
|
if (Shell.getInstance().isActive()) {
|
||||||
|
Shell.getInstance().getOutput().println(msg);
|
||||||
|
} else {
|
||||||
|
System.out.println(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
@@ -49,32 +52,32 @@ public class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
|
PipeInputStream pipeInputStream = new PipeInputStream();
|
||||||
|
Shell.getInstance().start(System.in, commandLine -> {
|
||||||
|
if (commandLine.equalsIgnoreCase(":exit")) {
|
||||||
|
log("force exit");
|
||||||
|
watchdog.destroyProcess();
|
||||||
|
Shell.getInstance().shutdown();
|
||||||
|
Main.shutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pipeInputStream.write(commandLine+"\r\n");
|
||||||
|
});
|
||||||
Connector.getInstance().startReconnect();
|
Connector.getInstance().startReconnect();
|
||||||
|
executeProcess(args, Shell.getInstance().getOutput(), pipeInputStream);
|
||||||
int resultCode = executeProcess(args);
|
|
||||||
|
|
||||||
Connector.getInstance().setNeedReconnect(false);
|
|
||||||
Connector.getInstance().stopReconnect();
|
|
||||||
Connector.getInstance().disconnect();
|
|
||||||
|
|
||||||
System.out.println(
|
|
||||||
Ansi.ansi().reset().newline()
|
|
||||||
.fg(Color.GREEN).a("Process Finished. Code: ")
|
|
||||||
.bold().fg(Color.WHITE).a(resultCode).reset()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int executeProcess(String[] args) {
|
private static void executeProcess(String[] args, PrintStream printStream, InputStream stdin) throws IOException {
|
||||||
String cmdLine = Arrays.stream(args).collect(Collectors.joining(" "));
|
String cmdLine = Arrays.stream(args).collect(Collectors.joining(" "));
|
||||||
CommandLine commandLine = CommandLine.parse(cmdLine);
|
CommandLine commandLine = CommandLine.parse(cmdLine);
|
||||||
DefaultExecutor executor = new DefaultExecutor();
|
DefaultExecutor executor = new DefaultExecutor();
|
||||||
|
|
||||||
PrintStream proxySysOut = new ProxySysOut(System.out);
|
PumpStreamHandler psh = new PumpStreamHandler(printStream, printStream, stdin);
|
||||||
InputStream proxySysIn = new ProxySysIn();
|
|
||||||
|
|
||||||
PumpStreamHandler psh = new PumpStreamHandler(proxySysOut, proxySysOut, proxySysIn);
|
|
||||||
psh.setStopTimeout(-1999); //hack: по-умолчанию в Apache Exec добавляется еще 2000L милисекунд
|
psh.setStopTimeout(-1999); //hack: по-умолчанию в Apache Exec добавляется еще 2000L милисекунд
|
||||||
executor.setStreamHandler(psh);
|
executor.setStreamHandler(psh);
|
||||||
|
watchdog = new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT);
|
||||||
|
executor.setWatchdog(watchdog);
|
||||||
|
|
||||||
int resultCode = 0;
|
int resultCode = 0;
|
||||||
try {
|
try {
|
||||||
@@ -85,7 +88,8 @@ public class Main {
|
|||||||
resultCode = -1;
|
resultCode = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultCode;
|
watchdog = null;
|
||||||
|
log("Process finished. Code: " + resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadConfig() throws IOException {
|
private static void loadConfig() throws IOException {
|
||||||
@@ -107,32 +111,9 @@ public class Main {
|
|||||||
fis.close();
|
fis.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ProxySysOut extends PrintStream {
|
private static void shutdown() {
|
||||||
ProxySysOut(OutputStream out) {
|
Connector.getInstance().setNeedReconnect(false);
|
||||||
super(out);
|
Connector.getInstance().stopReconnect();
|
||||||
}
|
Connector.getInstance().shutdown();
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(byte[] buf, int off, int len) {
|
|
||||||
super.write(buf, off, len);
|
|
||||||
Connector.getInstance().sendMessage(new String(buf, off, len));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ProxySysIn extends InputStream {
|
|
||||||
@Override
|
|
||||||
public int read() throws IOException {
|
|
||||||
return System.in.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] b) throws IOException {
|
|
||||||
return System.in.read(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] b, int off, int len) throws IOException {
|
|
||||||
return System.in.read(b, off, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
88
zond/src/main/java/asys/zond/PipeInputStream.java
Normal file
88
zond/src/main/java/asys/zond/PipeInputStream.java
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <dimon550@gmail.com>
|
||||||
|
* 2017-06-14
|
||||||
|
*/
|
||||||
|
package asys.zond;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class PipeInputStream extends InputStream {
|
||||||
|
private byte[] buffer = new byte[1024];
|
||||||
|
private int lastWritePos = 0,
|
||||||
|
lastReadPos = 0,
|
||||||
|
wallPos = buffer.length-1;
|
||||||
|
|
||||||
|
public synchronized void write(String s) {
|
||||||
|
byte[] strBytes = s.getBytes();
|
||||||
|
|
||||||
|
while ((lastWritePos < lastReadPos) && ((lastReadPos - lastWritePos) >= strBytes.length)) {
|
||||||
|
try {
|
||||||
|
wait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((lastWritePos + strBytes.length) >= 1024) {
|
||||||
|
wallPos = lastWritePos;
|
||||||
|
lastWritePos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.arraycopy(strBytes, 0, this.buffer, lastWritePos, strBytes.length);
|
||||||
|
lastWritePos += strBytes.length;
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized int read() throws IOException {
|
||||||
|
if (lastReadPos == lastWritePos) {
|
||||||
|
try {
|
||||||
|
wait();
|
||||||
|
} catch (InterruptedException ignore) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastReadPos == wallPos) {
|
||||||
|
lastReadPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.buffer[lastReadPos++];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b) throws IOException {
|
||||||
|
return this.read(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized int read(byte[] buffOut, int off, int len) throws IOException {
|
||||||
|
if (lastReadPos == lastWritePos) {
|
||||||
|
try {
|
||||||
|
wait();
|
||||||
|
} catch (InterruptedException ignore) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int actualLen = len;
|
||||||
|
|
||||||
|
if (lastReadPos > lastWritePos) {
|
||||||
|
if ((lastReadPos + len) > wallPos) {
|
||||||
|
actualLen = (wallPos - lastReadPos);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((lastReadPos + len) > lastWritePos) {
|
||||||
|
actualLen = (lastWritePos - lastReadPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.arraycopy(this.buffer, lastReadPos, buffOut, off, actualLen);
|
||||||
|
lastReadPos += actualLen;
|
||||||
|
if (lastReadPos == wallPos) {
|
||||||
|
lastReadPos = 0;
|
||||||
|
}
|
||||||
|
notify();
|
||||||
|
return actualLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,11 +54,9 @@ public class Connector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void shutdown() {
|
||||||
if (client.isConnected()) {
|
log("Disconnect...");
|
||||||
log("Disconnect...");
|
client.disconnect();
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChannel(Channel channel) {
|
public void setChannel(Channel channel) {
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <dimon550@gmail.com>
|
||||||
|
* 2017-06-14
|
||||||
|
*/
|
||||||
|
package asys.zond.shell;
|
||||||
|
|
||||||
|
public interface CommandLineHandler {
|
||||||
|
void handle(String commandLine);
|
||||||
|
}
|
||||||
84
zond/src/main/java/asys/zond/shell/JlineProxySysOut.java
Normal file
84
zond/src/main/java/asys/zond/shell/JlineProxySysOut.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <dimon550@gmail.com>
|
||||||
|
* 2017-06-14
|
||||||
|
*/
|
||||||
|
package asys.zond.shell;
|
||||||
|
|
||||||
|
import jline.console.ConsoleReader;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class JlineProxySysOut extends PrintStream {
|
||||||
|
private ConsoleReader consoleReader;
|
||||||
|
private PrintWriter writer;
|
||||||
|
|
||||||
|
public JlineProxySysOut(OutputStream out) {
|
||||||
|
super(out, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConsoleReader(ConsoleReader consoleReader) {
|
||||||
|
this.consoleReader = consoleReader;
|
||||||
|
if (consoleReader != null) {
|
||||||
|
this.writer = new PrintWriter(consoleReader.getOutput());
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
super.out.write('\r');
|
||||||
|
super.out.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _print(String s) {
|
||||||
|
writer.print(ConsoleReader.RESET_LINE);
|
||||||
|
writer.print(s);
|
||||||
|
cleanTrashLine(s);
|
||||||
|
writer.println();
|
||||||
|
try {
|
||||||
|
consoleReader.drawLine();
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
}
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Очистка печатной строки от мусора
|
||||||
|
*/
|
||||||
|
private void cleanTrashLine(String string) {
|
||||||
|
// очищает полностью строку
|
||||||
|
if (consoleReader.getCursorBuffer().buffer.length() + consoleReader.getPrompt().length() > string.length()) {
|
||||||
|
for (int i = string.length(); i <= consoleReader.getCursorBuffer().buffer.length() + 2; i++) {
|
||||||
|
writer.print(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] buf, int off, int len) {
|
||||||
|
if (consoleReader != null) {
|
||||||
|
if ((char) buf[len - 1] == '\n') len--; //TODO проверить в windows
|
||||||
|
_print(new String(buf, off, len));
|
||||||
|
} else {
|
||||||
|
super.write(buf, off, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(String x) {
|
||||||
|
if (consoleReader != null) {
|
||||||
|
_print(x);
|
||||||
|
} else {
|
||||||
|
super.print(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(String x) {
|
||||||
|
if (consoleReader != null) {
|
||||||
|
_print(x);
|
||||||
|
} else {
|
||||||
|
super.println(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
zond/src/main/java/asys/zond/shell/Shell.java
Normal file
69
zond/src/main/java/asys/zond/shell/Shell.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <dimon550@gmail.com>
|
||||||
|
* 2017-06-14
|
||||||
|
*/
|
||||||
|
package asys.zond.shell;
|
||||||
|
|
||||||
|
import jline.console.ConsoleReader;
|
||||||
|
import jline.internal.Ansi;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class Shell {
|
||||||
|
private static Shell instance = new Shell();
|
||||||
|
private boolean active = false;
|
||||||
|
private ConsoleReader console;
|
||||||
|
private JlineProxySysOut proxySysOut;
|
||||||
|
private Thread threadCommandHandler;
|
||||||
|
|
||||||
|
public static Shell getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Shell() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(final InputStream inputStream, final CommandLineHandler commandLineHandler) throws IOException {
|
||||||
|
proxySysOut = new JlineProxySysOut(System.out);
|
||||||
|
console = new ConsoleReader(inputStream, proxySysOut);
|
||||||
|
proxySysOut.setConsoleReader(console);
|
||||||
|
console.setPrompt(ConsoleReader.RESET_LINE + ":");
|
||||||
|
|
||||||
|
threadCommandHandler = new Thread(() -> {
|
||||||
|
Thread current = Thread.currentThread();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String line;
|
||||||
|
while (!current.isInterrupted() && ((line = console.readLine()) != null)) {
|
||||||
|
commandLineHandler.handle(line);
|
||||||
|
}
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
console.shutdown();
|
||||||
|
}, "Shell: command handler");
|
||||||
|
active = true;
|
||||||
|
threadCommandHandler.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
threadCommandHandler.interrupt();
|
||||||
|
active = false;
|
||||||
|
proxySysOut.setConsoleReader(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JlineProxySysOut getOutput() {
|
||||||
|
return proxySysOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void safeSleep() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
} catch (InterruptedException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user