mirror of
https://github.com/ME1312/SubServers-2.git
synced 2024-09-28 13:27:26 +02:00
0ade35f544
Spigot 1.13 has a compatabilty layer for old bukkit names, this will allow you to take advantage of that. 1.12: `bukkit:grass` -> `minecraft:grass` 1.13: `bukkit:grass` -> `minecraft:grass_block` 1.13: `grass` -> `minecraft:grass`
626 lines
32 KiB
Java
626 lines
32 KiB
Java
package net.ME1312.SubServers.Host;
|
|
|
|
import jline.console.ConsoleReader;
|
|
import net.ME1312.SubServers.Host.API.Event.*;
|
|
import net.ME1312.SubServers.Host.API.SubPluginInfo;
|
|
import net.ME1312.SubServers.Host.API.SubPlugin;
|
|
import net.ME1312.SubServers.Host.Executable.SubCreator;
|
|
import net.ME1312.SubServers.Host.Executable.SubServer;
|
|
import net.ME1312.SubServers.Host.Library.*;
|
|
import net.ME1312.SubServers.Host.Library.Config.YAMLConfig;
|
|
import net.ME1312.SubServers.Host.Library.Config.YAMLSection;
|
|
import net.ME1312.SubServers.Host.Library.Exception.IllegalPluginException;
|
|
import net.ME1312.SubServers.Host.Library.Log.FileLogger;
|
|
import net.ME1312.SubServers.Host.Library.Log.Logger;
|
|
import net.ME1312.SubServers.Host.Library.Version.Version;
|
|
import net.ME1312.SubServers.Host.Library.Version.VersionType;
|
|
import net.ME1312.SubServers.Host.Network.Cipher;
|
|
import net.ME1312.SubServers.Host.Network.SubDataClient;
|
|
import org.fusesource.jansi.AnsiConsole;
|
|
import org.json.JSONObject;
|
|
import org.w3c.dom.Document;
|
|
import org.w3c.dom.Node;
|
|
import org.w3c.dom.NodeList;
|
|
import org.xml.sax.InputSource;
|
|
|
|
import javax.xml.parsers.DocumentBuilderFactory;
|
|
import java.io.*;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.net.InetAddress;
|
|
import java.net.URL;
|
|
import java.nio.charset.Charset;
|
|
import java.nio.file.Files;
|
|
import java.text.DecimalFormat;
|
|
import java.util.*;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.jar.JarEntry;
|
|
import java.util.jar.JarFile;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
/**
|
|
* SubServers.Host Main Class
|
|
*/
|
|
public final class ExHost {
|
|
protected NamedContainer<Long, Map<String, Map<String, String>>> lang = null;
|
|
public HashMap<String, SubCreator.ServerTemplate> templates = new HashMap<String, SubCreator.ServerTemplate>();
|
|
public HashMap<String, SubServer> servers = new HashMap<String, SubServer>();
|
|
public SubCreator creator;
|
|
|
|
public Logger log;
|
|
public final UniversalFile dir = new UniversalFile(new File(System.getProperty("user.dir")));
|
|
public YAMLConfig config;
|
|
public YAMLSection host = null;
|
|
public SubDataClient subdata = null;
|
|
|
|
public final SubAPI api = new SubAPI(this);
|
|
//public static final Version version = Version.fromString("2.13a/pr4");
|
|
public static final Version version = new Version(Version.fromString("2.13a/pr5"), VersionType.SNAPSHOT, (ExHost.class.getPackage().getSpecificationTitle() == null)?"?":ExHost.class.getPackage().getSpecificationTitle()); // TODO Snapshot Version
|
|
|
|
private ConsoleReader jline;
|
|
private boolean running = false;
|
|
private boolean ready = false;
|
|
|
|
/**
|
|
* SubServers.Host Launch
|
|
*
|
|
* @param args Args
|
|
* @throws Exception
|
|
*/
|
|
public static void main(String[] args) throws Exception {
|
|
if (System.getProperty("RM.subservers", "true").equalsIgnoreCase("true")) {
|
|
joptsimple.OptionParser parser = new joptsimple.OptionParser();
|
|
parser.allowsUnrecognizedOptions();
|
|
parser.accepts("v");
|
|
parser.accepts("version");
|
|
parser.accepts("noconsole");
|
|
joptsimple.OptionSet options = parser.parse(args);
|
|
if(options.has("version") || options.has("v")) {
|
|
System.out.println("");
|
|
System.out.println(System.getProperty("os.name") + " " + System.getProperty("os.version") + ',');
|
|
System.out.println("Java " + System.getProperty("java.version") + ",");
|
|
System.out.println("SubServers.Host v" + version.toExtendedString());
|
|
System.out.println("");
|
|
} else {
|
|
new ExHost(options);
|
|
}
|
|
} 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 ExHost(joptsimple.OptionSet options) {
|
|
try {
|
|
JarFile jarFile = new JarFile(new File(ExHost.class.getProtectionDomain().getCodeSource().getLocation().toURI()));
|
|
Enumeration<JarEntry> entries = jarFile.entries();
|
|
|
|
boolean isplugin = false;
|
|
while (entries.hasMoreElements()) {
|
|
JarEntry entry = entries.nextElement();
|
|
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
|
|
api.knownClasses.add(entry.getName().substring(0, entry.getName().length() - 6).replace('/', '.'));
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
|
|
log = new Logger("SubServers");
|
|
try {
|
|
jline = new ConsoleReader(System.in, AnsiConsole.out());
|
|
Logger.setup(AnsiConsole.out(), AnsiConsole.err(), jline, dir);
|
|
log.info.println("Loading SubServers.Host v" + version.toString() + " Libraries");
|
|
dir.mkdirs();
|
|
new File(dir, "Plugins").mkdir();
|
|
if (!(new UniversalFile(dir, "config.yml").exists())) {
|
|
Util.copyFromJar(ExHost.class.getClassLoader(), "net/ME1312/SubServers/Host/Library/Files/config.yml", new UniversalFile(dir, "config.yml").getPath());
|
|
log.info.println("Created ~/config.yml");
|
|
} else if ((new Version((new YAMLConfig(new UniversalFile(dir, "config.yml"))).get().getSection("Settings").getString("Version", "0")).compareTo(new Version("2.11.2a+"))) != 0) {
|
|
Files.move(new UniversalFile(dir, "config.yml").toPath(), new UniversalFile(dir, "config.old" + Math.round(Math.random() * 100000) + ".yml").toPath());
|
|
|
|
Util.copyFromJar(ExHost.class.getClassLoader(), "net/ME1312/SubServers/Host/Library/Files/config.yml", new UniversalFile(dir, "config.yml").getPath());
|
|
log.info.println("Updated ~/config.yml");
|
|
}
|
|
config = new YAMLConfig(new UniversalFile(dir, "config.yml"));
|
|
|
|
if (!(new UniversalFile(dir, "Templates").exists())) {
|
|
new UniversalFile(dir, "Templates").mkdir();
|
|
log.info.println("Created ~/Templates/");
|
|
}
|
|
|
|
if (new UniversalFile(dir, "Recently Deleted").exists()) {
|
|
int f = new UniversalFile(dir, "Recently Deleted").listFiles().length;
|
|
for (File file : new UniversalFile(dir, "Recently Deleted").listFiles()) {
|
|
try {
|
|
if (file.isDirectory()) {
|
|
if (new UniversalFile(dir, "Recently Deleted:" + file.getName() + ":info.json").exists()) {
|
|
FileReader reader = new FileReader(new UniversalFile(dir, "Recently Deleted:" + file.getName() + ":info.json"));
|
|
JSONObject json = new JSONObject(Util.readAll(reader));
|
|
reader.close();
|
|
if (json.keySet().contains("Timestamp")) {
|
|
if (TimeUnit.MILLISECONDS.toDays(Calendar.getInstance().getTime().getTime() - json.getLong("Timestamp")) >= 7) {
|
|
Util.deleteDirectory(file);
|
|
f--;
|
|
log.info.println("Removed ~/Recently Deleted/" + file.getName());
|
|
}
|
|
} else {
|
|
Util.deleteDirectory(file);
|
|
f--;
|
|
log.info.println("Removed ~/Recently Deleted/" + file.getName());
|
|
}
|
|
} else {
|
|
Util.deleteDirectory(file);
|
|
f--;
|
|
log.info.println("Removed ~/Recently Deleted/" + file.getName());
|
|
}
|
|
} else {
|
|
Files.delete(file.toPath());
|
|
f--;
|
|
log.info.println("Removed ~/Recently Deleted/" + file.getName());
|
|
}
|
|
} catch (Exception e) {
|
|
log.error.println(e);
|
|
}
|
|
}
|
|
if (f <= 0) {
|
|
Files.delete(new UniversalFile(dir, "Recently Deleted").toPath());
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Find Jars
|
|
*/
|
|
UniversalFile pldir = new UniversalFile(dir, "Plugins");
|
|
LinkedList<File> pljars = new LinkedList<File>();
|
|
if (pldir.exists() && pldir.isDirectory()) for (File file : pldir.listFiles()) {
|
|
if (file.getName().endsWith(".jar")) pljars.add(file);
|
|
}
|
|
if (pljars.size() > 0) {
|
|
long begin = Calendar.getInstance().getTime().getTime();
|
|
log.info.println("Loading SubAPI Plugins...");
|
|
|
|
/*
|
|
* Load Jars & Find Main Classes
|
|
* (Unordered)
|
|
*/
|
|
LinkedHashMap<PluginClassLoader, NamedContainer<LinkedList<String>, LinkedHashMap<String, String>>> classes = new LinkedHashMap<PluginClassLoader, NamedContainer<LinkedList<String>, LinkedHashMap<String, String>>>();
|
|
for (File file : pljars) {
|
|
try {
|
|
JarFile jar = new JarFile(file);
|
|
Enumeration<JarEntry> entries = jar.entries();
|
|
PluginClassLoader loader = new PluginClassLoader(this.getClass().getClassLoader(), file.toURI().toURL());
|
|
List<String> contents = new ArrayList<String>();
|
|
|
|
loader.setDefaultClass(ClassNotFoundException.class);
|
|
boolean isplugin = false;
|
|
while (entries.hasMoreElements()) {
|
|
JarEntry entry = entries.nextElement();
|
|
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
|
|
String cname = entry.getName().substring(0, entry.getName().length() - 6).replace('/', '.');
|
|
contents.add(cname);
|
|
try {
|
|
Class<?> clazz = loader.loadClass(cname);
|
|
if (clazz.isAnnotationPresent(SubPlugin.class)) {
|
|
NamedContainer<LinkedList<String>, LinkedHashMap<String, String>> jarmap = (classes.keySet().contains(loader))?classes.get(loader):new NamedContainer<LinkedList<String>, LinkedHashMap<String, String>>(new LinkedList<String>(), new LinkedHashMap<>());
|
|
for (String dependancy : clazz.getAnnotation(SubPlugin.class).dependencies()) jarmap.name().add(dependancy);
|
|
for (String dependancy : clazz.getAnnotation(SubPlugin.class).softDependencies()) jarmap.name().add(dependancy);
|
|
jarmap.get().put(clazz.getAnnotation(SubPlugin.class).name(), cname);
|
|
classes.put(loader, jarmap);
|
|
isplugin = true;
|
|
}
|
|
} catch (Throwable e) {
|
|
log.error.println(new IllegalPluginException(e, "Couldn't load class: " + cname));
|
|
}
|
|
}
|
|
}
|
|
loader.setDefaultClass(null);
|
|
|
|
if (!isplugin) {
|
|
new PluginClassLoader(this.getClass().getClassLoader(), file.toURI().toURL());
|
|
log.info.println("Loaded Library: " + file.getName());
|
|
}
|
|
api.knownClasses.addAll(contents);
|
|
jar.close();
|
|
} catch (Throwable e) {
|
|
log.error.println(new InvocationTargetException(e, "Problem searching plugin jar: " + file.getName()));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Load Main Classes & Plugin Descriptions
|
|
* (Ordered by Known Dependencies)
|
|
*/
|
|
int progress = 1;
|
|
HashMap<String, SubPluginInfo> plugins = new LinkedHashMap<String, SubPluginInfo>();
|
|
while (classes.size() > 0) {
|
|
LinkedHashMap<PluginClassLoader, LinkedList<String>> loaded = new LinkedHashMap<PluginClassLoader, LinkedList<String>>();
|
|
for (PluginClassLoader loader : classes.keySet()) {
|
|
LinkedList<String> loadedlist = new LinkedList<String>();
|
|
for (String name : classes.get(loader).get().keySet()) {
|
|
boolean load = true;
|
|
for (String depend : classes.get(loader).name()) {
|
|
if (!plugins.keySet().contains(depend.toLowerCase())) {
|
|
load = progress <= 0;
|
|
}
|
|
}
|
|
|
|
if (load) {
|
|
String main = classes.get(loader).get().get(name);
|
|
try {
|
|
Class<?> clazz = loader.loadClass(main);
|
|
if (!clazz.isAnnotationPresent(SubPlugin.class))
|
|
throw new ClassCastException("Cannot find plugin descriptor");
|
|
|
|
Object obj = clazz.getConstructor().newInstance();
|
|
try {
|
|
SubPluginInfo plugin = new SubPluginInfo(this, obj, clazz.getAnnotation(SubPlugin.class).name(), Version.fromString(clazz.getAnnotation(SubPlugin.class).version()),
|
|
Arrays.asList(clazz.getAnnotation(SubPlugin.class).authors()), (clazz.getAnnotation(SubPlugin.class).description().length() > 0)?clazz.getAnnotation(SubPlugin.class).description():null,
|
|
(clazz.getAnnotation(SubPlugin.class).website().length() > 0)?new URL(clazz.getAnnotation(SubPlugin.class).website()):null, Arrays.asList(clazz.getAnnotation(SubPlugin.class).loadBefore()),
|
|
Arrays.asList(clazz.getAnnotation(SubPlugin.class).dependencies()), Arrays.asList(clazz.getAnnotation(SubPlugin.class).softDependencies()));
|
|
if (plugins.keySet().contains(plugin.getName().toLowerCase()))
|
|
log.warn.println("Duplicate plugin: " + plugin.getName().toLowerCase());
|
|
plugin.addExtra("subservers.plugin.loadafter", new ArrayList<String>());
|
|
plugins.put(plugin.getName().toLowerCase(), plugin);
|
|
} catch (Throwable e) {
|
|
log.error.println(new IllegalPluginException(e, "Couldn't load plugin descriptor for main class: " + main));
|
|
}
|
|
} catch (ClassCastException e) {
|
|
log.error.println(new IllegalPluginException(e, "Main class isn't annotated as a SubPlugin: " + main));
|
|
} catch (InvocationTargetException e) {
|
|
log.error.println(new IllegalPluginException(e.getTargetException(), "Uncaught exception occurred while loading main class: " + main));
|
|
} catch (Throwable e) {
|
|
log.error.println(new IllegalPluginException(e, "Couldn't load main class: " + main));
|
|
}
|
|
loadedlist.add(name);
|
|
}
|
|
}
|
|
if (loadedlist.size() > 0) loaded.put(loader, loadedlist);
|
|
}
|
|
progress = 0;
|
|
for (PluginClassLoader loader : loaded.keySet()) {
|
|
NamedContainer<LinkedList<String>, LinkedHashMap<String, String>> jarmap = classes.get(loader);
|
|
progress++;
|
|
for (String main : loaded.get(loader)) jarmap.get().remove(main);
|
|
if (jarmap.get().size() > 0) {
|
|
classes.put(loader, jarmap);
|
|
} else {
|
|
classes.remove(loader);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Load Extra Plugin Settings
|
|
*/
|
|
for (SubPluginInfo plugin : plugins.values()) {
|
|
for (String loadbefore : plugin.getLoadBefore()) {
|
|
if (plugins.keySet().contains(loadbefore.toLowerCase())) {
|
|
List<String> loadafter = plugins.get(loadbefore.toLowerCase()).getExtra("subservers.plugin.loadafter").asRawStringList();
|
|
loadafter.add(plugin.getName().toLowerCase());
|
|
plugins.get(loadbefore.toLowerCase()).addExtra("subservers.plugin.loadafter", loadafter);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Register Plugins
|
|
* (Ordered by LoadBefore & Dependencies)
|
|
*/
|
|
int i = 0;
|
|
while (plugins.size() > 0) {
|
|
List<String> loaded = new ArrayList<String>();
|
|
for (SubPluginInfo plugin : plugins.values()) {
|
|
try {
|
|
boolean load = true;
|
|
for (String depend : plugin.getDependancies()) {
|
|
if (plugins.keySet().contains(depend.toLowerCase())) {
|
|
load = false;
|
|
} else if (!api.plugins.keySet().contains(depend.toLowerCase())) {
|
|
throw new IllegalPluginException(new IllegalStateException("Unknown dependency: " + depend), "Cannot meet requirements for plugin: " + plugin.getName() + " v" + plugin.getVersion().toString());
|
|
}
|
|
}
|
|
for (String softdepend : plugin.getSoftDependancies()) {
|
|
if (plugins.keySet().contains(softdepend.toLowerCase())) {
|
|
load = false;
|
|
}
|
|
}
|
|
for (String loadafter : plugin.getExtra("subservers.plugin.loadafter").asRawStringList()) {
|
|
if (plugins.keySet().contains(loadafter.toLowerCase())) {
|
|
load = false;
|
|
}
|
|
}
|
|
if (load) try {
|
|
plugin.removeExtra("subservers.plugin.loadafter");
|
|
plugin.setEnabled(true);
|
|
api.addListener(plugin, plugin.get());
|
|
api.plugins.put(plugin.getName().toLowerCase(), plugin);
|
|
api.plugins.put(plugin.getName().toLowerCase(), plugin);
|
|
loaded.add(plugin.getName().toLowerCase());
|
|
String a = "";
|
|
int ai = 0;
|
|
for (String author : plugin.getAuthors()) {
|
|
ai++;
|
|
if (ai > 1) {
|
|
if (plugin.getAuthors().size() > 2) a += ", ";
|
|
else if (plugin.getAuthors().size() == 2) a += ' ';
|
|
if (ai == plugin.getAuthors().size()) a += "and ";
|
|
}
|
|
a += author;
|
|
}
|
|
log.info.println("Loaded " + plugin.getName() + " v" + plugin.getVersion().toString() + " by " + a);
|
|
i++;
|
|
} catch (Throwable e) {
|
|
plugin.setEnabled(false);
|
|
throw new InvocationTargetException(e, "Problem loading plugin: " + plugin.getName());
|
|
}
|
|
} catch (InvocationTargetException e) {
|
|
log.error.println(e);
|
|
loaded.add(plugin.getName().toLowerCase());
|
|
}
|
|
}
|
|
progress = 0;
|
|
for (String name : loaded) {
|
|
progress++;
|
|
plugins.remove(name);
|
|
}
|
|
if (progress == 0 && plugins.size() != 0) {
|
|
log.error.println(new IllegalStateException("Couldn't load more plugins yet " + plugins.size() + " remain unloaded"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Enable Plugins
|
|
*/
|
|
api.executeEvent(new SubEnableEvent(this));
|
|
log.info.println(i + " Plugin"+((i == 1)?"":"s") + " loaded in " + new DecimalFormat("0.000").format((Calendar.getInstance().getTime().getTime() - begin) / 1000D) + "s");
|
|
}
|
|
|
|
running = true;
|
|
Cipher cipher = null;
|
|
if (!config.get().getSection("Settings").getSection("SubData").getRawString("Encryption", "NONE").equalsIgnoreCase("NONE")) {
|
|
if (config.get().getSection("Settings").getSection("SubData").getString("Password", "").length() == 0) {
|
|
log.info.println("Cannot encrypt connection without a password");
|
|
} else if (!SubDataClient.getCiphers().keySet().contains(config.get().getSection("Settings").getSection("SubData").getRawString("Encryption").toUpperCase().replace('-', '_').replace(' ', '_'))) {
|
|
log.info.println("Unknown encryption type: " + config.get().getSection("Settings").getSection("SubData").getRawString("Encryption"));
|
|
} else {
|
|
cipher = SubDataClient.getCipher(config.get().getSection("Settings").getSection("SubData").getRawString("Encryption"));
|
|
}
|
|
}
|
|
subdata = new SubDataClient(this, config.get().getSection("Settings").getSection("SubData").getString("Name", "undefined"),
|
|
InetAddress.getByName(config.get().getSection("Settings").getSection("SubData").getString("Address", "127.0.0.1:4391").split(":")[0]),
|
|
Integer.parseInt(config.get().getSection("Settings").getSection("SubData").getString("Address", "127.0.0.1:4391").split(":")[1]), cipher);
|
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
|
if (running) {
|
|
log.warn.println("Received request from system to shutdown");
|
|
forcequit(0);
|
|
}
|
|
}));
|
|
creator = new SubCreator(this);
|
|
|
|
loadDefaults();
|
|
|
|
new Metrics(this);
|
|
new Timer().schedule(new TimerTask() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
Document updxml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(Util.readAll(new BufferedReader(new InputStreamReader(new URL("https://src.me1312.net/maven/net/ME1312/SubServers/SubServers.Host/maven-metadata.xml").openStream(), Charset.forName("UTF-8")))))));
|
|
|
|
NodeList updnodeList = updxml.getElementsByTagName("version");
|
|
Version updversion = version;
|
|
int updcount = 0;
|
|
for (int i = 0; i < updnodeList.getLength(); i++) {
|
|
Node node = updnodeList.item(i);
|
|
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
|
if (!node.getTextContent().startsWith("-") && !node.getTextContent().equals(version.toString()) && Version.fromString(node.getTextContent()).compareTo(updversion) > 0) {
|
|
updversion = Version.fromString(node.getTextContent());
|
|
updcount++;
|
|
}
|
|
}
|
|
}
|
|
if (updcount > 0) log.info.println("SubServers.Host v" + updversion + " is available. You are " + updcount + " version" + ((updcount == 1)?"":"s") + " behind.");
|
|
} catch (Exception e) {}
|
|
}
|
|
}, 0, TimeUnit.DAYS.toMillis(2));
|
|
|
|
if (!options.has("noconsole")) {
|
|
loop();
|
|
}
|
|
} catch (Exception e) {
|
|
log.error.println(e);
|
|
forcequit(1);
|
|
}
|
|
}
|
|
|
|
public void reload() throws IOException {
|
|
if (subdata != null)
|
|
subdata.destroy(0);
|
|
|
|
config.reload();
|
|
|
|
Cipher cipher = null;
|
|
if (!config.get().getSection("Settings").getSection("SubData").getRawString("Encryption", "NONE").equalsIgnoreCase("NONE")) {
|
|
if (config.get().getSection("Settings").getSection("SubData").getString("Password", "").length() == 0) {
|
|
log.info.println("Cannot encrypt connection without a password");
|
|
} else if (!SubDataClient.getCiphers().keySet().contains(config.get().getSection("Settings").getSection("SubData").getRawString("Encryption").toUpperCase().replace('-', '_').replace(' ', '_'))) {
|
|
log.info.println("Unknown encryption type: " + config.get().getSection("Settings").getSection("SubData").getRawString("Encryption"));
|
|
} else {
|
|
cipher = SubDataClient.getCipher(config.get().getSection("Settings").getSection("SubData").getRawString("Encryption"));
|
|
}
|
|
}
|
|
subdata = new SubDataClient(this, config.get().getSection("Settings").getSection("SubData").getString("Name", "undefined"),
|
|
InetAddress.getByName(config.get().getSection("Settings").getSection("SubData").getString("Address", "127.0.0.1:4391").split(":")[0]),
|
|
Integer.parseInt(config.get().getSection("Settings").getSection("SubData").getString("Address", "127.0.0.1:4391").split(":")[1]), cipher);
|
|
|
|
SubAPI.getInstance().executeEvent(new SubReloadEvent(this));
|
|
}
|
|
|
|
private void loop() throws Exception {
|
|
String line;
|
|
ready = true;
|
|
while (ready && (line = jline.readLine(">")) != null) {
|
|
if (!ready || line.replaceAll("\\s", "").length() == 0) continue;
|
|
final CommandPreProcessEvent event;
|
|
api.executeEvent(event = new CommandPreProcessEvent(this, line));
|
|
if (!event.isCancelled()) {
|
|
LinkedList<String> args = new LinkedList<String>();
|
|
Matcher parser = Pattern.compile("(?:^|\\s+)(\"(?:\\\\\"|[^\"])+\"?|(?:\\\\\\s|[^\\s])+)").matcher(line);
|
|
while (parser.find()) {
|
|
String arg = parser.group(1);
|
|
if (arg.startsWith("\"")) arg = arg.substring(1, arg.length() - ((arg.endsWith("\""))?1:0));
|
|
arg = unescapeCommand(arg);
|
|
args.add(arg);
|
|
}
|
|
String cmd = args.get(0);
|
|
args.remove(0);
|
|
if (cmd.startsWith("/")) cmd = cmd.substring(1);
|
|
if (args.size() >= 1 &&
|
|
((cmd.equalsIgnoreCase("sub") && !api.commands.keySet().contains("sub")) ||
|
|
(cmd.equalsIgnoreCase("subserver") && !api.commands.keySet().contains("subserver")) ||
|
|
(cmd.equalsIgnoreCase("subservers") && !api.commands.keySet().contains("subservers")))) {
|
|
cmd = args.get(0);
|
|
args.remove(0);
|
|
}
|
|
|
|
if (api.commands.keySet().contains(cmd.toLowerCase())) {
|
|
try {
|
|
api.commands.get(cmd.toLowerCase()).command(cmd, args.toArray(new String[args.size()]));
|
|
} catch (Exception e) {
|
|
log.error.println(new InvocationTargetException(e, "Uncaught exception while running command"));
|
|
}
|
|
} else {
|
|
String s = cmd.replace("\\", "\\\\").replace("\n", "\\n").replace("\"", "\\\"").replace(" ", "\\ ");
|
|
for (String arg : args) {
|
|
s += ' ' + arg.replace("\\", "\\\\").replace("\n", "\\n").replace("\"", "\\\"").replace(" ", "\\ ");
|
|
}
|
|
log.message.println("Unknown Command - " + s);
|
|
}
|
|
jline.getOutput().write("\b \b");
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Parse escapes in a command
|
|
*
|
|
* @param str String
|
|
* @return Unescaped String
|
|
*/
|
|
private String unescapeCommand(String str) {
|
|
StringBuilder sb = new StringBuilder(str.length());
|
|
|
|
for (int i = 0; i < str.length(); i++) {
|
|
char ch = str.charAt(i);
|
|
if (ch == '\\') {
|
|
char nextChar = (i == str.length() - 1) ? '\\' : str
|
|
.charAt(i + 1);
|
|
// Octal escape?
|
|
if (nextChar >= '0' && nextChar <= '7') {
|
|
String code = "" + nextChar;
|
|
i++;
|
|
if ((i < str.length() - 1) && str.charAt(i + 1) >= '0'
|
|
&& str.charAt(i + 1) <= '7') {
|
|
code += str.charAt(i + 1);
|
|
i++;
|
|
if ((i < str.length() - 1) && str.charAt(i + 1) >= '0'
|
|
&& str.charAt(i + 1) <= '7') {
|
|
code += str.charAt(i + 1);
|
|
i++;
|
|
}
|
|
}
|
|
sb.append((char) Integer.parseInt(code, 8));
|
|
continue;
|
|
}
|
|
switch (nextChar) {
|
|
case '\\':
|
|
ch = '\\';
|
|
break;
|
|
case 'n':
|
|
ch = '\n';
|
|
break;
|
|
case '\"':
|
|
ch = '\"';
|
|
break;
|
|
case ' ':
|
|
ch = ' ';
|
|
break;
|
|
// Hex Unicode: u????
|
|
case 'u':
|
|
if (i >= str.length() - 5) {
|
|
ch = 'u';
|
|
break;
|
|
}
|
|
int code = Integer.parseInt(
|
|
"" + str.charAt(i + 2) + str.charAt(i + 3)
|
|
+ str.charAt(i + 4) + str.charAt(i + 5), 16);
|
|
sb.append(Character.toChars(code));
|
|
i += 5;
|
|
continue;
|
|
}
|
|
i++;
|
|
}
|
|
sb.append(ch);
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
private void loadDefaults() {
|
|
SubCommand.load(this);
|
|
}
|
|
|
|
/**
|
|
* Stop SubServers.Host
|
|
*
|
|
* @param exit Exit Code
|
|
*/
|
|
public void stop(int exit) {
|
|
if (ready) {
|
|
log.info.println("Shutting down...");
|
|
SubDisableEvent event = new SubDisableEvent(this, exit);
|
|
api.executeEvent(event);
|
|
|
|
forcequit(event.getExitCode());
|
|
}
|
|
} private void forcequit(int exit) {
|
|
if (ready) {
|
|
ready = false;
|
|
|
|
List<String> subservers = new ArrayList<String>();
|
|
subservers.addAll(servers.keySet());
|
|
|
|
for (String server : subservers) {
|
|
servers.get(server).stop();
|
|
try {
|
|
servers.get(server).waitFor();
|
|
} catch (Exception e) {
|
|
log.error.println(e);
|
|
}
|
|
}
|
|
servers.clear();
|
|
|
|
if (creator != null) {
|
|
creator.terminate();
|
|
try {
|
|
creator.waitFor();
|
|
} catch (Exception e) {
|
|
log.error.println(e);
|
|
}
|
|
}
|
|
running = false;
|
|
|
|
try {
|
|
Thread.sleep(500);
|
|
} catch (Exception e) {
|
|
log.error.println(e);
|
|
}
|
|
if (subdata != null) Util.isException(() -> subdata.destroy(0));
|
|
|
|
if (new File(dir, "Templates").exists()) Util.deleteDirectory(new File(dir, "Templates"));
|
|
|
|
Util.isException(FileLogger::end);
|
|
System.exit(exit);
|
|
}
|
|
}
|
|
} |