Zond: clear
This commit is contained in:
@@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <d.mihailov@samson-rus.com>
|
|
||||||
* 2017-06-08
|
|
||||||
*/
|
|
||||||
package asys.zond;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
public class Config {
|
|
||||||
private static Properties properties = new Properties();
|
|
||||||
|
|
||||||
private Config(){
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void load(InputStream inputStream) throws IOException {
|
|
||||||
properties.load(inputStream);
|
|
||||||
if (properties.size() == 0) {
|
|
||||||
throw new IOException("Config empty!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getString(String key) {
|
|
||||||
return properties.getProperty(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getInt(String key) {
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(properties.getProperty(key));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,115 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
package asys.zond;
|
package asys.zond;
|
||||||
|
|
||||||
import asys.zond.proxy.Connector;
|
|
||||||
import asys.zond.shell.Shell;
|
|
||||||
import org.apache.commons.exec.*;
|
|
||||||
import org.fusesource.jansi.Ansi;
|
|
||||||
import org.fusesource.jansi.Ansi.Color;
|
|
||||||
import org.fusesource.jansi.AnsiConsole;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
private static ExecuteWatchdog watchdog;
|
public static void main(String[] args) {
|
||||||
|
|
||||||
private static void printLogo() {
|
|
||||||
System.out.println(
|
|
||||||
Ansi.ansi().reset()
|
|
||||||
.bold().fg(Color.WHITE).a("ASys").boldOff().a(":// ")
|
|
||||||
.fg(Color.BLACK).bg(Color.RED).a("Zond").reset().newline()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void log(String message){
|
|
||||||
String msg = Ansi.ansi().reset()
|
|
||||||
.bg(Color.BLUE).fg(Color.WHITE).a("[ASys Zond] ")
|
|
||||||
.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 {
|
|
||||||
if (Boolean.getBoolean("ansi.install")) {
|
|
||||||
AnsiConsole.systemInstall();
|
|
||||||
}
|
|
||||||
|
|
||||||
printLogo();
|
|
||||||
|
|
||||||
if (args.length == 0) {
|
|
||||||
System.out.println("no args");
|
|
||||||
System.exit(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
executeProcess(args, Shell.getInstance().getOutput(), pipeInputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void executeProcess(String[] args, PrintStream printStream, InputStream stdin) throws IOException {
|
|
||||||
String cmdLine = Arrays.stream(args).collect(Collectors.joining(" "));
|
|
||||||
CommandLine commandLine = CommandLine.parse(cmdLine);
|
|
||||||
DefaultExecutor executor = new DefaultExecutor();
|
|
||||||
|
|
||||||
PumpStreamHandler psh = new PumpStreamHandler(printStream, printStream, stdin);
|
|
||||||
psh.setStopTimeout(-1999); //hack: по-умолчанию в Apache Exec добавляется еще 2000L милисекунд
|
|
||||||
executor.setStreamHandler(psh);
|
|
||||||
watchdog = new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT);
|
|
||||||
executor.setWatchdog(watchdog);
|
|
||||||
|
|
||||||
int resultCode = 0;
|
|
||||||
try {
|
|
||||||
resultCode = executor.execute(commandLine);
|
|
||||||
} catch (ExecuteException ignore) {
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
resultCode = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
watchdog = null;
|
|
||||||
log("Process finished. Code: " + resultCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void loadConfig() throws IOException {
|
|
||||||
File zondPropertiesFile = new File("zond.properties");
|
|
||||||
if (!zondPropertiesFile.exists()) {
|
|
||||||
InputStream stream = Main.class.getResourceAsStream("/zond.properties");
|
|
||||||
FileOutputStream fos = new FileOutputStream(zondPropertiesFile);
|
|
||||||
byte[] buff = new byte[65536];
|
|
||||||
int len;
|
|
||||||
while ((len = stream.read(buff)) > 0) {
|
|
||||||
fos.write(buff, 0, len);
|
|
||||||
}
|
|
||||||
fos.flush();
|
|
||||||
fos.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
FileInputStream fis = new FileInputStream(zondPropertiesFile);
|
|
||||||
Config.load(fis);
|
|
||||||
fis.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void shutdown() {
|
|
||||||
Connector.getInstance().setNeedReconnect(false);
|
|
||||||
Connector.getInstance().stopReconnect();
|
|
||||||
Connector.getInstance().shutdown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <d.mihailov@samson-rus.com>
|
|
||||||
* 2017-06-08
|
|
||||||
*/
|
|
||||||
package asys.zond.proxy;
|
|
||||||
|
|
||||||
import asys.mcsmanager.packets.codec.PacketDecoder;
|
|
||||||
import asys.mcsmanager.packets.codec.PacketEncoder;
|
|
||||||
import asys.mcsmanager.packets.codec.PacketHandler;
|
|
||||||
import io.netty.bootstrap.Bootstrap;
|
|
||||||
import io.netty.channel.ChannelFuture;
|
|
||||||
import io.netty.channel.ChannelInitializer;
|
|
||||||
import io.netty.channel.EventLoopGroup;
|
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
|
||||||
import io.netty.channel.socket.SocketChannel;
|
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
|
||||||
|
|
||||||
public class Client {
|
|
||||||
private EventLoopGroup group;
|
|
||||||
private Bootstrap bootstrap;
|
|
||||||
private ChannelFuture channelFuture;
|
|
||||||
|
|
||||||
public void connect(String host, int port) {
|
|
||||||
if (group == null || bootstrap == null) {
|
|
||||||
group = new NioEventLoopGroup();
|
|
||||||
bootstrap = createBootstrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
channelFuture = bootstrap.connect(host, port);
|
|
||||||
channelFuture.awaitUninterruptibly(5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConnected() {
|
|
||||||
return (channelFuture != null && channelFuture.isSuccess());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnect() {
|
|
||||||
group.shutdownGracefully();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bootstrap createBootstrap() {
|
|
||||||
Bootstrap bootstrap = new Bootstrap();
|
|
||||||
bootstrap.group(group)
|
|
||||||
.channel(NioSocketChannel.class)
|
|
||||||
.handler(createChannelInitializer());
|
|
||||||
|
|
||||||
return bootstrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChannelInitializer createChannelInitializer() {
|
|
||||||
return new ChannelInitializer<SocketChannel>() {
|
|
||||||
@Override
|
|
||||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
|
||||||
socketChannel.pipeline().addLast(
|
|
||||||
new PacketEncoder(),
|
|
||||||
new PacketDecoder(),
|
|
||||||
new PacketHandler(),
|
|
||||||
new ClientPacketHandler()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <d.mihailov@samson-rus.com>
|
|
||||||
* 2017-06-08
|
|
||||||
*/
|
|
||||||
package asys.zond.proxy;
|
|
||||||
|
|
||||||
import asys.mcsmanager.packets.*;
|
|
||||||
import asys.zond.Config;
|
|
||||||
import asys.zond.Main;
|
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import com.google.common.collect.ImmutableBiMap;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static asys.mcsmanager.packets.codec.Params.KNOWN_HANDLERS;
|
|
||||||
import static asys.mcsmanager.packets.codec.Params.KNOWN_PACKETS;
|
|
||||||
import static asys.zond.Main.log;
|
|
||||||
|
|
||||||
public class ClientPacketHandler extends ChannelInboundHandlerAdapter implements IPacketHandler {
|
|
||||||
private static final BiMap<Integer, Class<? extends Packet>> handshakePackets = ImmutableBiMap.of(
|
|
||||||
1, CS_Handshake.class,
|
|
||||||
2, SC_HandshakeResult.class
|
|
||||||
);
|
|
||||||
private static Map<Class<? extends Packet>, IPacketHandler> handshakeHandlers;
|
|
||||||
|
|
||||||
private static final BiMap<Integer, Class<? extends Packet>> knownPackets = ImmutableBiMap.of(
|
|
||||||
3, CS_Ping.class,
|
|
||||||
4, CS_ConsoleMessage.class
|
|
||||||
);
|
|
||||||
|
|
||||||
ClientPacketHandler() {
|
|
||||||
if (handshakeHandlers == null) {
|
|
||||||
handshakeHandlers = ImmutableMap.of(
|
|
||||||
SC_HandshakeResult.class, this
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
log("channelActive");
|
|
||||||
ctx.channel().attr(KNOWN_PACKETS).set(handshakePackets);
|
|
||||||
ctx.channel().attr(KNOWN_HANDLERS).set(handshakeHandlers);
|
|
||||||
|
|
||||||
CS_Handshake packet = new CS_Handshake(
|
|
||||||
Config.getString("clientId"),
|
|
||||||
Config.getString("passcode"));
|
|
||||||
log("send Handshake packet...");
|
|
||||||
ctx.channel().writeAndFlush(packet);
|
|
||||||
|
|
||||||
super.channelActive(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
Connector.getInstance().setChannel(null);
|
|
||||||
if (Connector.getInstance().isNeedReconnect()) {
|
|
||||||
log("Lost connection! Try reconnect...");
|
|
||||||
Connector.getInstance().startReconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.channel().attr(KNOWN_PACKETS).remove();
|
|
||||||
ctx.channel().attr(KNOWN_HANDLERS).remove();
|
|
||||||
super.channelInactive(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(Packet packet, ChannelHandlerContext context) {
|
|
||||||
log("handle : " + packet.getClass().getSimpleName());
|
|
||||||
SC_HandshakeResult pkt = (SC_HandshakeResult) packet;
|
|
||||||
if (pkt.getErrorCode() != 0) {
|
|
||||||
log(String.format("Handshake: #%d %s", pkt.getErrorCode(), pkt.getMessage()));
|
|
||||||
} else {
|
|
||||||
context.channel().attr(KNOWN_PACKETS).set(knownPackets);
|
|
||||||
Connector.getInstance().setChannel(context.channel());
|
|
||||||
log("Handshake: OK");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2017-06-14
|
|
||||||
*/
|
|
||||||
package asys.zond.proxy;
|
|
||||||
|
|
||||||
import asys.mcsmanager.packets.CS_ConsoleMessage;
|
|
||||||
import asys.zond.Config;
|
|
||||||
import io.netty.channel.Channel;
|
|
||||||
|
|
||||||
import static asys.zond.Main.log;
|
|
||||||
|
|
||||||
public class Connector {
|
|
||||||
private static Connector instance = new Connector();
|
|
||||||
private Client client;
|
|
||||||
private TaskTicker connectTicker;
|
|
||||||
private int tryConnect = 0;
|
|
||||||
private boolean needReconnect = true;
|
|
||||||
private Channel channel;
|
|
||||||
|
|
||||||
public static Connector getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Connector(){
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startReconnect() {
|
|
||||||
client = new Client();
|
|
||||||
connectTicker = new TaskTicker().setStepTimeMs(5000L);
|
|
||||||
connectTicker.setTask(() -> {
|
|
||||||
log(String.format("Connect(%d) to ASys...", ++tryConnect));
|
|
||||||
client.connect(Config.getString("host"), Config.getInt("port"));
|
|
||||||
if (client.isConnected()) {
|
|
||||||
stopReconnect();
|
|
||||||
} else {
|
|
||||||
log(String.format("Connection(%d) fail. Try reconnect...", tryConnect));
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNeedReconnect() {
|
|
||||||
return needReconnect;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNeedReconnect(boolean value) {
|
|
||||||
this.needReconnect = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopReconnect() {
|
|
||||||
if (connectTicker != null) {
|
|
||||||
connectTicker.stop();
|
|
||||||
tryConnect = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown() {
|
|
||||||
log("Disconnect...");
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setChannel(Channel channel) {
|
|
||||||
this.channel = channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendMessage(String message) {
|
|
||||||
if (channel != null) {
|
|
||||||
channel.writeAndFlush(new CS_ConsoleMessage(
|
|
||||||
System.currentTimeMillis(),0,"L",message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <d.mihailov@samson-rus.com>
|
|
||||||
* 2017-05-18
|
|
||||||
*/
|
|
||||||
package asys.zond.proxy;
|
|
||||||
|
|
||||||
public class TaskTicker implements Runnable {
|
|
||||||
private Runnable task;
|
|
||||||
private long stepTimeMs = 1000L;
|
|
||||||
private Thread thread;
|
|
||||||
private boolean loop = false;
|
|
||||||
|
|
||||||
TaskTicker setTask(Runnable task) {
|
|
||||||
this.task = task;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
TaskTicker setStepTimeMs(long stepTimeMs) {
|
|
||||||
this.stepTimeMs = stepTimeMs;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void start() {
|
|
||||||
thread = new Thread(this, "TaskTicker");
|
|
||||||
loop = true;
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop() {
|
|
||||||
loop = false;
|
|
||||||
if (thread != null) {
|
|
||||||
thread.interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (loop || !Thread.currentThread().isInterrupted()) {
|
|
||||||
task.run();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(stepTimeMs);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2017-06-14
|
|
||||||
*/
|
|
||||||
package asys.zond.shell;
|
|
||||||
|
|
||||||
public interface CommandLineHandler {
|
|
||||||
void handle(String commandLine);
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2017-06-14
|
|
||||||
*/
|
|
||||||
package asys.zond.shell;
|
|
||||||
|
|
||||||
import asys.zond.proxy.Connector;
|
|
||||||
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();
|
|
||||||
|
|
||||||
for (String l : s.split("\n")) {
|
|
||||||
Connector.getInstance().sendMessage(l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Очистка печатной строки от мусора
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.commons.exec;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
import org.apache.commons.exec.util.DebugUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies all data from an input stream to an output stream.
|
|
||||||
*
|
|
||||||
* @version $Id: StreamPumper.java 1557263 2014-01-10 21:18:09Z ggregory $
|
|
||||||
*/
|
|
||||||
public class StreamPumper implements Runnable {
|
|
||||||
|
|
||||||
/** the default size of the internal buffer for copying the streams */
|
|
||||||
private static final int DEFAULT_SIZE = 1024;
|
|
||||||
|
|
||||||
/** the input stream to pump from */
|
|
||||||
private final InputStream is;
|
|
||||||
|
|
||||||
/** the output stream to pmp into */
|
|
||||||
private final OutputStream os;
|
|
||||||
|
|
||||||
/** the size of the internal buffer for copying the streams */
|
|
||||||
private final int size;
|
|
||||||
|
|
||||||
/** was the end of the stream reached */
|
|
||||||
private boolean finished;
|
|
||||||
|
|
||||||
/** close the output stream when exhausted */
|
|
||||||
private final boolean closeWhenExhausted;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new stream pumper.
|
|
||||||
*
|
|
||||||
* @param is input stream to read data from
|
|
||||||
* @param os output stream to write data to.
|
|
||||||
* @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
|
|
||||||
*/
|
|
||||||
public StreamPumper(final InputStream is, final OutputStream os,
|
|
||||||
final boolean closeWhenExhausted) {
|
|
||||||
this.is = is;
|
|
||||||
this.os = os;
|
|
||||||
this.size = DEFAULT_SIZE;
|
|
||||||
this.closeWhenExhausted = closeWhenExhausted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new stream pumper.
|
|
||||||
*
|
|
||||||
* @param is input stream to read data from
|
|
||||||
* @param os output stream to write data to.
|
|
||||||
* @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted.
|
|
||||||
* @param size the size of the internal buffer for copying the streams
|
|
||||||
*/
|
|
||||||
public StreamPumper(final InputStream is, final OutputStream os,
|
|
||||||
final boolean closeWhenExhausted, final int size) {
|
|
||||||
this.is = is;
|
|
||||||
this.os = os;
|
|
||||||
this.size = size > 0 ? size : DEFAULT_SIZE;
|
|
||||||
this.closeWhenExhausted = closeWhenExhausted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new stream pumper.
|
|
||||||
*
|
|
||||||
* @param is input stream to read data from
|
|
||||||
* @param os output stream to write data to.
|
|
||||||
*/
|
|
||||||
public StreamPumper(final InputStream is, final OutputStream os) {
|
|
||||||
this(is, os, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies data from the input stream to the output stream. Terminates as
|
|
||||||
* soon as the input stream is closed or an error occurs.
|
|
||||||
*/
|
|
||||||
public void run() {
|
|
||||||
synchronized (this) {
|
|
||||||
// Just in case this object is reused in the future
|
|
||||||
finished = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final byte[] buf = new byte[this.size];
|
|
||||||
|
|
||||||
int length;
|
|
||||||
try {
|
|
||||||
//hack: пропатчили алгоритм
|
|
||||||
while (!Thread.currentThread().isInterrupted() && (length = is.read(buf)) > 0) {
|
|
||||||
os.write(buf, 0, length);
|
|
||||||
os.flush();
|
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
|
||||||
// nothing to do - happens quite often with watchdog
|
|
||||||
} finally {
|
|
||||||
if (closeWhenExhausted) {
|
|
||||||
try {
|
|
||||||
os.close();
|
|
||||||
} catch (final IOException e) {
|
|
||||||
final String msg = "Got exception while closing exhausted output stream";
|
|
||||||
DebugUtils.handleException(msg ,e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
synchronized (this) {
|
|
||||||
finished = true;
|
|
||||||
notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells whether the end of the stream has been reached.
|
|
||||||
*
|
|
||||||
* @return true is the stream has been exhausted.
|
|
||||||
*/
|
|
||||||
public synchronized boolean isFinished() {
|
|
||||||
return finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method blocks until the stream pumper finishes.
|
|
||||||
*
|
|
||||||
* @exception InterruptedException
|
|
||||||
* if any thread interrupted the current thread before or while the current thread was waiting for a
|
|
||||||
* notification.
|
|
||||||
* @see #isFinished()
|
|
||||||
*/
|
|
||||||
public synchronized void waitFor() throws InterruptedException {
|
|
||||||
while (!isFinished()) {
|
|
||||||
wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
clientId = SpigotServer0
|
|
||||||
host = 127.0.0.1
|
|
||||||
port = 8779
|
|
||||||
passcode = testpassphrase
|
|
||||||
Reference in New Issue
Block a user