2017-01-30 21:22:36 +01:00
|
|
|
package net.ME1312.SubServers.Host;
|
|
|
|
|
|
|
|
import java.io.*;
|
|
|
|
import java.lang.management.ManagementFactory;
|
|
|
|
import java.net.URISyntaxException;
|
|
|
|
import java.net.URLEncoder;
|
|
|
|
import java.util.*;
|
|
|
|
import java.util.jar.JarEntry;
|
|
|
|
import java.util.jar.JarFile;
|
|
|
|
import javax.xml.parsers.DocumentBuilderFactory;
|
|
|
|
|
|
|
|
import jline.console.ConsoleReader;
|
2017-08-15 11:58:48 +02:00
|
|
|
import jline.console.CursorBuffer;
|
2017-08-18 11:58:06 +02:00
|
|
|
import net.ME1312.SubServers.Host.Library.TextColor;
|
2017-08-17 01:29:02 +02:00
|
|
|
import net.ME1312.SubServers.Host.Library.Util;
|
2017-08-18 11:58:06 +02:00
|
|
|
import org.fusesource.jansi.Ansi;
|
2017-08-15 11:58:48 +02:00
|
|
|
import org.fusesource.jansi.AnsiConsole;
|
2017-01-31 01:33:30 +01:00
|
|
|
import org.w3c.dom.NodeList;
|
2017-01-30 21:22:36 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* SubServers.Host Launcher Class
|
|
|
|
*/
|
|
|
|
public final class Launch {
|
2017-12-06 23:34:47 +01:00
|
|
|
private static File dir = null;
|
|
|
|
private static Process process = null;
|
2017-01-30 21:22:36 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepare and launch SubServers.Host
|
|
|
|
*
|
|
|
|
* @param args Args
|
|
|
|
* @throws Exception
|
|
|
|
*/
|
|
|
|
public static void main(String[] args) throws Exception {
|
2017-08-22 15:02:23 +02:00
|
|
|
if (System.getProperty("RM.subservers", "true").equalsIgnoreCase("true")) {
|
|
|
|
launch(args);
|
|
|
|
} else {
|
|
|
|
System.out.println(">> SubServers code has been disallowed to work on this machine");
|
|
|
|
System.out.println(">> Check with your provider for more information");
|
|
|
|
System.exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void launch(String[] args) throws Exception {
|
2017-02-05 23:03:17 +01:00
|
|
|
String plugins = "";
|
2017-01-30 21:22:36 +01:00
|
|
|
File rtdir = new File(System.getProperty("user.dir"));
|
|
|
|
File pldir = new File(rtdir, "Plugins");
|
2017-12-06 23:34:47 +01:00
|
|
|
dir = File.createTempFile("SubServers.Host.", ".jar");
|
|
|
|
dir.delete();
|
|
|
|
dir.mkdir();
|
|
|
|
System.out.println(">> Created " + dir.getPath().replace(File.separator, "/"));
|
|
|
|
extractJar(getCodeSourceLocation(), dir);
|
2017-01-30 21:22:36 +01:00
|
|
|
System.out.println(">> Extracted ~/" + getCodeSourceLocation().getName());
|
|
|
|
if (pldir.isDirectory() && pldir.listFiles().length > 0) {
|
2017-08-17 01:29:02 +02:00
|
|
|
for (File plugin : Arrays.asList(pldir.listFiles())) {
|
2017-02-05 23:03:17 +01:00
|
|
|
try {
|
|
|
|
boolean success = false;
|
2017-08-17 01:29:02 +02:00
|
|
|
if (getFileExtension(plugin.getName()).equalsIgnoreCase("zip")) {
|
2017-12-15 01:50:39 +01:00
|
|
|
InputStream stream = new FileInputStream(plugin);
|
|
|
|
Util.unzip(stream, dir);
|
|
|
|
stream.close();
|
2017-02-05 23:03:17 +01:00
|
|
|
success = true;
|
2017-08-17 01:29:02 +02:00
|
|
|
} else if (getFileExtension(plugin.getName()).equalsIgnoreCase("jar")) {
|
2017-12-06 23:34:47 +01:00
|
|
|
extractJar(plugin, dir);
|
2017-02-05 23:03:17 +01:00
|
|
|
success = true;
|
|
|
|
}
|
2017-12-06 23:34:47 +01:00
|
|
|
if (new File(dir, "package.xml").exists()) {
|
|
|
|
NodeList xml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(dir, "package.xml")).getElementsByTagName("class");
|
2017-02-05 23:03:17 +01:00
|
|
|
if (xml.getLength() > 0) {
|
|
|
|
for (int i = 0; i < xml.getLength(); i++) {
|
|
|
|
plugins += ((plugins.length() == 0)?"":" ") + xml.item(i).getTextContent().replace(' ', '_');
|
|
|
|
}
|
2017-01-30 21:22:36 +01:00
|
|
|
}
|
2017-12-06 23:34:47 +01:00
|
|
|
new File(dir, "package.xml").delete();
|
2017-01-30 21:22:36 +01:00
|
|
|
}
|
2017-08-17 01:29:02 +02:00
|
|
|
if (success) System.out.println(">> Extracted ~/plugins/" + plugin.getName());
|
2017-02-05 23:03:17 +01:00
|
|
|
} catch (Exception e) {
|
2017-08-17 01:29:02 +02:00
|
|
|
System.out.println(">> Couldn't extract ~/plugins/" + plugin.getName());
|
2017-02-05 23:03:17 +01:00
|
|
|
e.printStackTrace();
|
2017-01-30 21:22:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ArrayList<String> arguments = new ArrayList<String>();
|
|
|
|
String javaPath = String.valueOf(System.getProperty("java.home")) + File.separator + "bin" + File.separator + "java";
|
|
|
|
arguments.add(javaPath);
|
|
|
|
arguments.addAll(getVmArgs());
|
2017-12-06 23:34:47 +01:00
|
|
|
arguments.add("-Dsubservers.host.runtime=" + URLEncoder.encode(dir.getPath(), "UTF-8"));
|
2017-02-05 23:03:17 +01:00
|
|
|
if (!plugins.equals(""))
|
|
|
|
arguments.add("-Dsubservers.host.plugins=" + URLEncoder.encode(plugins, "UTF-8"));
|
2017-01-30 21:22:36 +01:00
|
|
|
arguments.add("-cp");
|
2017-12-06 23:34:47 +01:00
|
|
|
arguments.add(dir.getPath());
|
2017-05-30 21:38:51 +02:00
|
|
|
arguments.add("net.ME1312.SubServers.Host.ExHost");
|
2017-01-30 21:22:36 +01:00
|
|
|
arguments.addAll(Arrays.asList(args));
|
|
|
|
ProcessBuilder processBuilder = new ProcessBuilder(arguments);
|
|
|
|
processBuilder.directory(new File(System.getProperty("user.dir")));
|
|
|
|
processBuilder.redirectErrorStream(true);
|
2017-12-06 23:34:47 +01:00
|
|
|
syncConsole(processBuilder.start());
|
|
|
|
Thread.sleep(250);
|
|
|
|
int code = process.exitValue();
|
|
|
|
process = null;
|
|
|
|
exit(code);
|
2017-01-30 21:22:36 +01:00
|
|
|
}
|
|
|
|
|
2017-12-06 23:34:47 +01:00
|
|
|
private static void syncConsole(Process process) throws Exception {
|
2017-08-18 11:58:06 +02:00
|
|
|
ConsoleReader console = new ConsoleReader(System.in, (System.getProperty("subservers.host.log.color", "true").equalsIgnoreCase("true"))?AnsiConsole.out:System.out);
|
2017-08-15 11:58:48 +02:00
|
|
|
console.setExpandEvents(false);
|
2017-12-06 23:34:47 +01:00
|
|
|
Launch.process = process;
|
2017-01-30 21:22:36 +01:00
|
|
|
try {
|
|
|
|
new Thread(() -> {
|
|
|
|
try {
|
2017-08-15 11:58:48 +02:00
|
|
|
String line;
|
2017-01-30 21:22:36 +01:00
|
|
|
BufferedWriter cmd = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
|
2017-12-06 23:34:47 +01:00
|
|
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
|
|
|
if (Launch.process != null && Launch.process.isAlive()) {
|
|
|
|
try {
|
|
|
|
stashLine(console);
|
|
|
|
console.println(">> Received request from system to shutdown");
|
|
|
|
unstashLine(console);
|
|
|
|
console.flush();
|
|
|
|
cmd.write("exit");
|
|
|
|
cmd.newLine();
|
|
|
|
cmd.flush();
|
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}));
|
2017-08-15 11:58:48 +02:00
|
|
|
while (process.isAlive() && (line = console.readLine(">")) != null) {
|
|
|
|
if (line.equals("")) continue;
|
|
|
|
cmd.write(line);
|
2017-01-30 21:22:36 +01:00
|
|
|
cmd.newLine();
|
|
|
|
cmd.flush();
|
|
|
|
}
|
2017-08-15 11:58:48 +02:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
2017-01-30 21:22:36 +01:00
|
|
|
}
|
2017-08-15 11:58:48 +02:00
|
|
|
}).start();
|
|
|
|
new Thread(() -> {
|
|
|
|
try {
|
|
|
|
String line;
|
|
|
|
BufferedReader obr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
|
|
|
while (process.isAlive() && (line = obr.readLine()) != null) {
|
|
|
|
stashLine(console);
|
|
|
|
if (System.getProperty("subservers.host.log.color", "true").equalsIgnoreCase("true")) {
|
|
|
|
console.println(ConsoleColor.parseColor(line) + ConsoleColor.RESET);
|
|
|
|
} else {
|
|
|
|
console.println(ConsoleColor.stripColor(line.replaceAll("\u001B\\[[;\\d]*m", "")));
|
|
|
|
}
|
|
|
|
unstashLine(console);
|
|
|
|
console.flush();
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
2017-01-30 21:22:36 +01:00
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}).start();
|
2017-08-15 11:58:48 +02:00
|
|
|
String line;
|
2017-01-30 21:22:36 +01:00
|
|
|
BufferedReader obr = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
|
|
while (process.isAlive() && (line = obr.readLine()) != null) {
|
2017-08-15 11:58:48 +02:00
|
|
|
stashLine(console);
|
|
|
|
if (System.getProperty("subservers.host.log.color", "true").equalsIgnoreCase("true")) {
|
|
|
|
console.println(ConsoleColor.parseColor(line) + ConsoleColor.RESET);
|
|
|
|
} else {
|
|
|
|
console.println(ConsoleColor.stripColor(line.replaceAll("\u001B\\[[;\\d]*m", "")));
|
|
|
|
}
|
|
|
|
unstashLine(console);
|
|
|
|
console.flush();
|
2017-01-30 21:22:36 +01:00
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2017-08-17 01:29:02 +02:00
|
|
|
stashLine(console);
|
2017-01-30 21:22:36 +01:00
|
|
|
}
|
|
|
|
|
2017-12-06 23:34:47 +01:00
|
|
|
private static void exit(int code) {
|
|
|
|
System.out.println(">> Cleaning up");
|
|
|
|
deleteDir(dir);
|
|
|
|
System.exit(code);
|
|
|
|
}
|
|
|
|
|
2017-01-30 21:22:36 +01:00
|
|
|
private static void extractJar(File jarFile, File dir) throws Exception {
|
|
|
|
JarFile jar = new JarFile(jarFile);
|
|
|
|
Enumeration<JarEntry> files = jar.entries();
|
|
|
|
ArrayList<JarEntry> entries = new ArrayList<JarEntry>();
|
|
|
|
while (files.hasMoreElements()) {
|
|
|
|
entries.add(files.nextElement());
|
|
|
|
}
|
|
|
|
for (JarEntry file : entries) {
|
|
|
|
File f = new File(dir, file.getName());
|
|
|
|
if (f.exists()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (file.isDirectory()) {
|
|
|
|
f.mkdirs();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!f.getParentFile().exists()) {
|
|
|
|
f.getParentFile().mkdirs();
|
|
|
|
}
|
|
|
|
InputStream is = jar.getInputStream(file);
|
|
|
|
FileOutputStream fos = new FileOutputStream(f);
|
|
|
|
while (is.available() > 0) {
|
|
|
|
fos.write(is.read());
|
|
|
|
}
|
|
|
|
fos.close();
|
|
|
|
is.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void deleteDir(File f) {
|
|
|
|
if (f.isDirectory()) {
|
|
|
|
for (File c : f.listFiles()) {
|
|
|
|
deleteDir(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f.delete();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static List<String> getVmArgs() {
|
|
|
|
ArrayList<String> values = new ArrayList<String>();
|
|
|
|
values.addAll(ManagementFactory.getRuntimeMXBean().getInputArguments());
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static File getCodeSourceLocation() {
|
|
|
|
try {
|
|
|
|
return new File(Launch.class.getProtectionDomain().getCodeSource().getLocation().toURI());
|
|
|
|
}
|
|
|
|
catch (URISyntaxException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static String getFileExtension(String fileName) {
|
|
|
|
String extension = "";
|
|
|
|
int i = fileName.lastIndexOf(46);
|
|
|
|
if (i >= 0) {
|
|
|
|
extension = fileName.substring(i + 1);
|
|
|
|
}
|
|
|
|
return extension;
|
|
|
|
}
|
2017-08-15 11:58:48 +02:00
|
|
|
|
|
|
|
private static CursorBuffer stashed;
|
|
|
|
private static void stashLine(ConsoleReader console) {
|
|
|
|
stashed = console.getCursorBuffer().copy();
|
|
|
|
try {
|
|
|
|
console.getOutput().write("\u001b[1G\u001b[K");
|
|
|
|
console.flush();
|
|
|
|
} catch (IOException e) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void unstashLine(ConsoleReader console) {
|
|
|
|
try {
|
|
|
|
console.resetPromptLine(console.getPrompt(),
|
|
|
|
stashed.toString(), stashed.cursor);
|
|
|
|
} catch (IOException e) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private enum ConsoleColor {
|
2017-08-18 11:58:06 +02:00
|
|
|
AQUA(TextColor.AQUA, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.CYAN).bold().toString()),
|
|
|
|
BLACK(TextColor.BLACK, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLACK).boldOff().toString()),
|
|
|
|
BLUE(TextColor.BLUE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLUE).bold().toString()),
|
|
|
|
BOLD(TextColor.BOLD, Ansi.ansi().a(Ansi.Attribute.UNDERLINE_DOUBLE).toString()),
|
|
|
|
DARK_AQUA(TextColor.DARK_AQUA, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.CYAN).boldOff().toString()),
|
|
|
|
DARK_BLUE(TextColor.DARK_BLUE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLUE).boldOff().toString()),
|
|
|
|
DARK_GRAY(TextColor.DARK_GRAY, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLACK).bold().toString()),
|
|
|
|
DARK_GREEN(TextColor.DARK_GREEN, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.GREEN).boldOff().toString()),
|
|
|
|
DARK_PURPLE(TextColor.DARK_PURPLE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.MAGENTA).boldOff().toString()),
|
|
|
|
DARK_RED(TextColor.DARK_RED, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.RED).boldOff().toString()),
|
|
|
|
GOLD(TextColor.GOLD, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.YELLOW).boldOff().toString()),
|
|
|
|
GRAY(TextColor.GRAY, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.WHITE).boldOff().toString()),
|
|
|
|
GREEN(TextColor.GREEN, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.GREEN).bold().toString()),
|
|
|
|
ITALIC(TextColor.ITALIC, Ansi.ansi().a(Ansi.Attribute.ITALIC).toString()),
|
|
|
|
LIGHT_PURPLE(TextColor.LIGHT_PURPLE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.MAGENTA).bold().toString()),
|
|
|
|
MAGIC(TextColor.MAGIC, Ansi.ansi().a(Ansi.Attribute.BLINK_SLOW).toString()),
|
|
|
|
RED(TextColor.RED, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.RED).bold().toString()),
|
|
|
|
RESET(TextColor.RESET, Ansi.ansi().a(Ansi.Attribute.RESET).toString()),
|
|
|
|
STRIKETHROUGH(TextColor.STRIKETHROUGH, Ansi.ansi().a(Ansi.Attribute.STRIKETHROUGH_ON).toString()),
|
|
|
|
UNDERLINE(TextColor.UNDERLINE, Ansi.ansi().a(Ansi.Attribute.UNDERLINE).toString()),
|
|
|
|
WHITE(TextColor.WHITE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.WHITE).bold().toString()),
|
|
|
|
YELLOW(TextColor.YELLOW, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.YELLOW).bold().toString());
|
2017-08-15 11:58:48 +02:00
|
|
|
|
2017-08-18 11:58:06 +02:00
|
|
|
private final TextColor color;
|
2017-08-15 11:58:48 +02:00
|
|
|
private final String value;
|
|
|
|
|
2017-08-18 11:58:06 +02:00
|
|
|
ConsoleColor(TextColor color, String value) {
|
2017-08-15 11:58:48 +02:00
|
|
|
this.color = color;
|
|
|
|
this.value = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return getConsoleString();
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getValue() {
|
2017-08-18 11:58:06 +02:00
|
|
|
return color.getValue();
|
2017-08-15 11:58:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public String getConsoleString() {
|
2017-08-18 11:58:06 +02:00
|
|
|
return value;
|
2017-08-15 11:58:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static String parseColor(String str) {
|
|
|
|
for (ConsoleColor color : Arrays.asList(ConsoleColor.values())) {
|
|
|
|
str = str.replace(color.getValue(), color.getConsoleString());
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String stripColor(String str) {
|
|
|
|
for (ConsoleColor color : Arrays.asList(ConsoleColor.values())) {
|
|
|
|
str = str.replace(color.getValue(), "");
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
}
|
2017-01-30 21:22:36 +01:00
|
|
|
}
|