Archived
0

Zond: добавляем коммандную строку JLine2

Merge branch 'dev-zond-jline' into dev-zond
This commit is contained in:
2017-06-14 18:04:47 +03:00
7 changed files with 289 additions and 59 deletions

View File

@@ -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'
} }

View File

@@ -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);
}
} }
} }

View 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;
}
}

View File

@@ -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) {

View File

@@ -0,0 +1,9 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-06-14
*/
package asys.zond.shell;
public interface CommandLineHandler {
void handle(String commandLine);
}

View 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);
}
}
}

View 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) {
}
}
}