diff --git a/SubServers.Web/Avenir-Book.ttf b/SubServers.Web/Avenir-Book.ttf new file mode 100644 index 00000000..858df677 Binary files /dev/null and b/SubServers.Web/Avenir-Book.ttf differ diff --git a/SubServers.Web/pom.xml b/SubServers.Web/pom.xml new file mode 100644 index 00000000..9541da89 --- /dev/null +++ b/SubServers.Web/pom.xml @@ -0,0 +1,134 @@ + + + 4.0.0 + + net.ME1312.SubServers + SubServers.Web + -PLACEHOLDER + jar + + + + me1312-repo + https://dev.me1312.net/maven + + + + + + org.fusesource.jansi + jansi + 1.18 + compile + + + net.md_5 + bungeecord-internal + 1.8-SNAPSHOT + provided + + + net.ME1312.SubServers + SubServers.Bungee.Common + ${project.version} + provided + + + net.ME1312.SubServers + SubServers.Bungee + ${project.version} + provided + + + org.eclipse.jetty + jetty-server + 9.4.3.v20170317 + + + org.eclipse.jetty + jetty-servlet + 9.4.3.v20170317 + + + + + ../out/compile/target/SubServers.Web + src + + + src + + **/*.java + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.7 + 1.8 + + + + org.codehaus.mojo + ideauidesigner-maven-plugin + 1.0-beta-1 + + + + javac2 + + + + + true + true + true + + + + org.apache.maven.plugins + maven-antrun-plugin + + + process-resources + + run + + + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.2-beta-5 + + SubServers.Console + ../Artifacts/Plugins + + jar-with-dependencies + + false + + + + make-assembly + package + + single + + + + + + + \ No newline at end of file diff --git a/SubServers.Web/src/bungee.yml b/SubServers.Web/src/bungee.yml new file mode 100644 index 00000000..e96e6e75 --- /dev/null +++ b/SubServers.Web/src/bungee.yml @@ -0,0 +1,4 @@ +name: SubServers-Web +main: net.ME1312.SubServers.Web.ConsolePlugin +version: 2.18a +author: ME1312 \ No newline at end of file diff --git a/SubServers.Web/src/net/ME1312/SubServers/Web/ConsoleFont.ttf b/SubServers.Web/src/net/ME1312/SubServers/Web/ConsoleFont.ttf new file mode 100644 index 00000000..41413c15 Binary files /dev/null and b/SubServers.Web/src/net/ME1312/SubServers/Web/ConsoleFont.ttf differ diff --git a/SubServers.Web/src/net/ME1312/SubServers/Web/ConsolePlugin.java b/SubServers.Web/src/net/ME1312/SubServers/Web/ConsolePlugin.java new file mode 100644 index 00000000..64512e2c --- /dev/null +++ b/SubServers.Web/src/net/ME1312/SubServers/Web/ConsolePlugin.java @@ -0,0 +1,86 @@ +package net.ME1312.SubServers.Web; + +import net.ME1312.Galaxi.Library.Config.YAMLConfig; +import net.ME1312.SubServers.Bungee.Event.SubCreateEvent; +import net.ME1312.SubServers.Bungee.Event.SubSendCommandEvent; +import net.ME1312.SubServers.Bungee.Event.SubStartEvent; +import net.ME1312.SubServers.Bungee.Host.Host; +import net.ME1312.SubServers.Bungee.Host.RemotePlayer; +import net.ME1312.SubServers.Bungee.Host.SubCreator; +import net.ME1312.SubServers.Bungee.Host.SubServer; +import net.ME1312.SubServers.Bungee.Library.Metrics; +import net.ME1312.SubServers.Bungee.SubAPI; +import net.ME1312.SubServers.Bungee.SubProxy; + +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.event.EventHandler; +import net.md_5.bungee.event.EventPriority; + +import javax.swing.*; +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.logging.Level; + +public final class ConsolePlugin extends Plugin implements Listener { + public YAMLConfig config; + private JettyServer jettyServer; + + @Override + public void onEnable() { + reload(); + + new Metrics(this, 3853).addPlatformCharts(); + + jettyServer = new JettyServer(); + try { + jettyServer.start(); + } catch (Exception e) { + getLogger().log(Level.SEVERE, "An error occurred when enabling the webserver, Plugin disabling...", e); + this.onDisable(); + getProxy().getPluginManager().unregisterListeners(this); + getProxy().getPluginManager().unregisterCommands(this); + } + + SubAPI.getInstance().addListener(new Runnable() { + @Override + public void run() { + reload(); + } + }); + } + + private void reload() { + + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onServerCreate(SubCreateEvent event) { + if (!event.isCancelled()) { + + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onServerStart(SubStartEvent event) { + if (!event.isCancelled()) { + + } + } + + @Override + public void onDisable() { + try { + jettyServer.server.stop(); + } catch (Exception e) { + getLogger().log(Level.SEVERE, "An error occurred when disabling the plugin", e); + } + } + + @Override + public SubProxy getProxy() { + return (SubProxy) super.getProxy(); + } +} diff --git a/SubServers.Web/src/net/ME1312/SubServers/Web/JettyServer.java b/SubServers.Web/src/net/ME1312/SubServers/Web/JettyServer.java new file mode 100644 index 00000000..c213c035 --- /dev/null +++ b/SubServers.Web/src/net/ME1312/SubServers/Web/JettyServer.java @@ -0,0 +1,23 @@ +package net.ME1312.SubServers.Web; + +import net.ME1312.SubServers.Web.endpoints.BlockingServlet; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletHandler; + +public class JettyServer { + public Server server; + + public void start() throws Exception { + server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(8090); + server.setConnectors(new Connector[] {connector}); + + ServletHandler handler = new ServletHandler(); + server.setHandler(handler); + handler.addServletWithMapping(BlockingServlet.class, "/status"); + server.start(); + } +} \ No newline at end of file diff --git a/SubServers.Web/src/net/ME1312/SubServers/Web/Library/HTMLogger.java b/SubServers.Web/src/net/ME1312/SubServers/Web/Library/HTMLogger.java new file mode 100644 index 00000000..bcdbaf5d --- /dev/null +++ b/SubServers.Web/src/net/ME1312/SubServers/Web/Library/HTMLogger.java @@ -0,0 +1,336 @@ +package net.ME1312.SubServers.Web.Library; + +import net.ME1312.Galaxi.Library.Container.Container; + +import org.fusesource.jansi.AnsiOutputStream; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.LinkedList; +import java.util.Locale; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class HTMLogger extends AnsiOutputStream { + private static final String[] ANSI_COLOR_MAP = new String[]{"000000", "cd0000", "25bc24", "d7d700", "0000c3", "be00be", "00a5dc", "cccccc"}; + private static final String[] ANSI_BRIGHT_COLOR_MAP = new String[]{"808080", "ff0000", "31e722", "ffff00", "0000ff", "ff00ff", "00c8ff", "ffffff"}; + private static final byte[] BYTES_NBSP = "\u00A0".getBytes(UTF_8); + private static final byte[] BYTES_AMP = "&".getBytes(UTF_8); + private static final byte[] BYTES_LT = "<".getBytes(UTF_8); + private LinkedList currentAttributes = new LinkedList(); + private LinkedList queue = new LinkedList(); + private OutputStream raw; + protected boolean ansi = true; + protected boolean nbsp = false; + private boolean underline = false; + private boolean strikethrough = false; + + public static HTMLogger wrap(OutputStream raw) { + return wrap(raw, new HTMConstructor() { + @Override + public HTMLogger construct(OutputStream raw, OutputStream wrapped) { + return new HTMLogger(raw, wrapped); + } + }); + } + + public static T wrap(final OutputStream raw, HTMConstructor constructor) { + final Container html = new Container(null); + html.value(constructor.construct(raw, new OutputStream() { + private boolean nbsp = false; + + @Override + public void write(int data) throws IOException { + HTMLogger htm = html.value(); + if (htm.queue.size() > 0) { + LinkedList queue = htm.queue; + htm.queue = new LinkedList<>(); + for (String attr : queue) { + htm.write('<' + attr + '>'); + htm.currentAttributes.addFirst(attr); + } + } + + if (data == 32) { + if (htm.nbsp) { + if (nbsp) raw.write(BYTES_NBSP); + else raw.write(data); + nbsp = !nbsp; + } else raw.write(data); + } else { + nbsp = false; + switch(data) { + case '&': + raw.write(BYTES_AMP); + break; + case '<': + raw.write(BYTES_LT); + break; + case '\n': + htm.closeAttributes(); + default: + raw.write(data); + } + } + } + })); + return html.value(); + } + public HTMLogger(final OutputStream raw, OutputStream wrapped) { + super(wrapped); + this.raw = raw; + } + public interface HTMConstructor { + T construct(OutputStream raw, OutputStream wrapped); + } + + private void write(String s) throws IOException { + raw.write(s.getBytes(UTF_8)); + } + + private void writeAttribute(String attr) throws IOException { + queue.add(attr); + } + + public void closeAttribute(String s) throws IOException { + + // Try to remove a tag that doesn't exist yet first + String[] queue = this.queue.toArray(new String[0]); + for (int i = queue.length; i > 0;) { + String attr = queue[--i]; + if (attr.toLowerCase().startsWith(s.toLowerCase())) { + this.queue.removeLastOccurrence(attr); + return; + } + } + + // Close a tag that we've already written + LinkedList closedAttributes = new LinkedList(); + LinkedList currentAttributes = new LinkedList(this.currentAttributes); + LinkedList unclosedAttributes = new LinkedList(); + + for (String attr : currentAttributes) { + if (attr.toLowerCase().startsWith(s.toLowerCase())) { + for (String a : unclosedAttributes) { + closedAttributes.add(a); + this.currentAttributes.removeFirst(); + write("'); + } + unclosedAttributes.clear(); + this.currentAttributes.removeFirst(); + write("'); + break; + } else { + unclosedAttributes.add(attr); + } + } + + // Queue unrelated tags to be re-opened + for (String attr : closedAttributes) { + this.queue.addFirst(attr); + } + } + + public void closeAttributes() throws IOException { + queue.clear(); + + for (String attr : currentAttributes) { + write(""); + } + + underline = false; + strikethrough = false; + currentAttributes.clear(); + } + + @Override + protected void processDeleteLine(int amount) throws IOException { + super.processDeleteLine(amount); + } + + private void renderTextDecoration() throws IOException { + String dec = ""; + if (underline) dec += " underline"; + if (strikethrough) dec += " line-through"; + + closeAttribute("span style=\"text-decoration:"); + if (dec.length() != 0) writeAttribute("span style=\"text-decoration:" + dec.substring(1) + "\""); + } + + @Override + protected void processSetAttribute(int attribute) throws IOException { + if (ansi) switch(attribute) { + case 1: + closeAttribute("b"); + writeAttribute("b"); + break; + case 3: + closeAttribute("i"); + writeAttribute("i"); + break; + case 4: + underline = true; + renderTextDecoration(); + break; + case 9: + strikethrough = true; + renderTextDecoration(); + break; + case 22: + closeAttribute("b"); + break; + case 23: + closeAttribute("i"); + break; + case 24: + underline = false; + renderTextDecoration(); + break; + case 29: + strikethrough = false; + renderTextDecoration(); + break; + case 73: + closeAttribute("su"); + writeAttribute("sup"); + break; + case 74: + closeAttribute("su"); + writeAttribute("sub"); + break; + case 75: + closeAttribute("su"); + break; + } + } + + @Override + protected void processUnknownOperatingSystemCommand(int label, String arg) { + try { + if (ansi && label == 8) { + closeAttribute("a"); + String[] args = arg.split(";", 3); + if (args.length > 1 && args[1].length() > 0 && allowHyperlink(args[1])) { + writeAttribute("a href=\"" + args[1].replace("&", "&").replace("<", "<").replace("\"", """) + "\" target=\"_blank\""); + } + } + } catch (Exception e) {} + } + + protected boolean allowHyperlink(String link) { + if (link.toLowerCase(Locale.ENGLISH).startsWith("mailto:execute@galaxi.engine")) { + return false; + } else { + return true; + } + } + + @Override + protected void processAttributeRest() throws IOException { + closeAttributes(); + } + + private String parse256(int color) throws IOException { + if (color < 8) { + return ANSI_COLOR_MAP[color]; + } else if (color < 16) { + return ANSI_BRIGHT_COLOR_MAP[color - 8]; + } else if (color < 232) { + float x = color - 16; + int r = (int) ((x / 36f) * 51); + x = (x % 36f) ; + int g = (int) ((x / 6f) * 51); + int b = (int) ((x % 6f) * 51); + return ((r >= 16)?"":"0") + Integer.toString(r, 16) + ((g >= 16)?"":"0") + Integer.toString(g, 16) + ((b >= 16)?"":"0") + Integer.toString(b, 16); + } else if (color < 256) { + int gray = (int) (10.2f * (color - 231)); + return ((gray >= 16)?"":"0") + Integer.toString(gray, 16) + ((gray >= 16)?"":"0") + Integer.toString(gray, 16) + ((gray >= 16)?"":"0") + Integer.toString(gray, 16); + } else { + throw new IOException("Invalid 8 Bit Color: " + color); + } + } + + @Override + protected void processDefaultTextColor() throws IOException { + closeAttribute("span style=\"color:"); + } + + @Override + protected void processSetForegroundColor(int color) throws IOException { + processSetForegroundColor(color, false); + } + + @Override + protected void processSetForegroundColor(int color, boolean bright) throws IOException { + if (ansi) { + processDefaultTextColor(); + writeAttribute("span style=\"color:#" + ((!bright)?ANSI_COLOR_MAP:ANSI_BRIGHT_COLOR_MAP)[color] + "\""); + renderTextDecoration(); + } + } + + @Override + protected void processSetForegroundColorExt(int index) throws IOException { + if (ansi) { + processDefaultTextColor(); + writeAttribute("span style=\"color:#" + parse256(index) + "\""); + renderTextDecoration(); + } + } + + @Override + protected void processSetForegroundColorExt(int r, int g, int b) throws IOException { + if (ansi) { + processDefaultTextColor(); + writeAttribute("span style=\"color:#" + ((r >= 16)?"":"0") + Integer.toString(r, 16) + ((g >= 16)?"":"0") + Integer.toString(g, 16) + ((b >= 16)?"":"0") + Integer.toString(b, 16) + "\""); + renderTextDecoration(); + } + } + + @Override + protected void processDefaultBackgroundColor() throws IOException { + closeAttribute("span style=\"background-color:"); + } + + @Override + protected void processSetBackgroundColor(int color) throws IOException { + processSetBackgroundColor(color, false); + } + + @Override + protected void processSetBackgroundColor(int color, boolean bright) throws IOException { + if (ansi) { + processDefaultBackgroundColor(); + writeAttribute("span style=\"background-color:#" + ((!bright)?ANSI_COLOR_MAP:ANSI_BRIGHT_COLOR_MAP)[color] + "\""); + } + } + + @Override + protected void processSetBackgroundColorExt(int index) throws IOException { + if (ansi) { + processDefaultBackgroundColor(); + writeAttribute("span style=\"background-color:#" + parse256(index) + "\""); + } + } + + @Override + protected void processSetBackgroundColorExt(int r, int g, int b) throws IOException { + if (ansi) { + processDefaultBackgroundColor(); + writeAttribute("span style=\"background-color:#" + ((r >= 16)?"":"0") + Integer.toString(r, 16) + ((g >= 16)?"":"0") + Integer.toString(g, 16) + ((b >= 16)?"":"0") + Integer.toString(b, 16) + "\""); + } + } + + @Override + public void flush() throws IOException { + super.flush(); + raw.flush(); + } + + @Override + public void close() throws IOException { + closeAttributes(); + super.close(); + raw.close(); + } +} diff --git a/SubServers.Web/src/net/ME1312/SubServers/Web/endpoints/BlockingServlet.java b/SubServers.Web/src/net/ME1312/SubServers/Web/endpoints/BlockingServlet.java new file mode 100644 index 00000000..54694311 --- /dev/null +++ b/SubServers.Web/src/net/ME1312/SubServers/Web/endpoints/BlockingServlet.java @@ -0,0 +1,16 @@ +package net.ME1312.SubServers.Web.endpoints; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class BlockingServlet extends HttpServlet { + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + response.getWriter().println("{ \"status\": \"ok\"}"); + } +} diff --git a/pom.xml b/pom.xml index 3fa6be37..85b8ef75 100644 --- a/pom.xml +++ b/pom.xml @@ -16,5 +16,6 @@ SubServers.Host SubServers.Sync SubServers.Sync/velocity + SubServers.Web \ No newline at end of file