Skip to content

Commit

Permalink
added global backend console
Browse files Browse the repository at this point in the history
  • Loading branch information
dries007 committed Oct 11, 2014
1 parent eb7391c commit 69c3aa6
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 76 deletions.
1 change: 1 addition & 0 deletions src/main/java/net/doubledoordev/backend/Main.java
Expand Up @@ -40,6 +40,7 @@

package net.doubledoordev.backend;

import com.google.gson.JsonObject;
import net.doubledoordev.backend.server.Server;
import net.doubledoordev.backend.server.rcon.RCon;
import net.doubledoordev.backend.util.Cache;
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/net/doubledoordev/backend/permissions/User.java
Expand Up @@ -180,4 +180,9 @@ public int getDiskspaceLeft()
if (server.getOwner().equals(username)) leftover -= server.getDiskspaceUse();
return leftover > 0 ? leftover : 0;
}

public boolean isAdmin()
{
return this.getGroup() == Group.ADMIN;
}
}
5 changes: 3 additions & 2 deletions src/main/java/net/doubledoordev/backend/server/Server.java
Expand Up @@ -69,6 +69,7 @@
import java.util.regex.Pattern;

import static net.doubledoordev.backend.util.Constants.*;
import static net.doubledoordev.backend.util.CustomLogAppender.LOG_LINES_KEPT;

/**
* Class that holds methods related to Server instances.
Expand Down Expand Up @@ -889,7 +890,7 @@ public Process getProcess()
public boolean canUserControl(User user)
{
if (user == null) return false;
if (user.getGroup() == Group.ADMIN || user.getUsername().equalsIgnoreCase(getOwner())) return true;
if (user.isAdmin() || user.getUsername().equalsIgnoreCase(getOwner())) return true;
for (String admin : getAdmins()) if (admin.equalsIgnoreCase(user.getUsername())) return true;
for (String admin : getCoOwners()) if (admin.equalsIgnoreCase(user.getUsername())) return true;
return false;
Expand All @@ -898,7 +899,7 @@ public boolean canUserControl(User user)
public boolean isCoOwner(User user)
{
if (user == null) return false;
if (user.getGroup() == Group.ADMIN || user.getUsername().equalsIgnoreCase(getOwner())) return true;
if (user.isAdmin() || user.getUsername().equalsIgnoreCase(getOwner())) return true;
for (String admin : getCoOwners()) if (admin.equalsIgnoreCase(user.getUsername())) return true;
return false;
}
Expand Down
Expand Up @@ -146,7 +146,6 @@ public boolean accept(File dir, String name)
public static final TemplateModel HELPER_TEMPLATE_MODEL = getStaticHelper();
public static final Timer TIMER = new Timer();
protected static final char[] symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
public static int LOG_LINES_KEPT = 1000;

/**
* Methods that only get called to init the Constants
Expand Down
112 changes: 112 additions & 0 deletions src/main/java/net/doubledoordev/backend/util/CustomLogAppender.java
@@ -0,0 +1,112 @@
/*
* Unless otherwise specified through the '@author' tag or comments at
* the top of the file or on a specific portion of the code the following license applies:
*
* Copyright (c) 2014, DoubleDoorDevelopment
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* The header specified or the above copyright notice, this list of conditions
* and the following disclaimer below must be displayed at the top of the source code
* of any web page received while using any part of the service this software provides.
*
* The header to be displayed:
* This page was generated by DoubleDoorDevelopment's D3Backend or a derivative thereof.
*
* Neither the name of the project nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package net.doubledoordev.backend.util;

import com.google.gson.JsonObject;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;

import java.io.Serializable;
import java.util.ArrayList;

/**
* @author Dries007
*/
@Plugin(name = "CustomLogAppender", category = "Core", elementType = "appender", printObject = true)
public class CustomLogAppender extends AbstractAppender
{
public static int LOG_LINES_KEPT = 1000;
private static final ArrayList<String> LOG = new ArrayList<>(LOG_LINES_KEPT + 10);

protected CustomLogAppender(String name, Filter filter, Layout<? extends Serializable> layout)
{
super(name, filter, layout);
}

protected CustomLogAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions)
{
super(name, filter, layout, ignoreExceptions);
}

@PluginFactory
public static CustomLogAppender createAppender(@PluginAttribute("name") String name, @PluginAttribute("ignoreExceptions") boolean ignoreExceptions, @PluginElement("Layout") Layout layout, @PluginElement("Filters") Filter filter)
{
if (name == null)
{
LOGGER.error("No name provided for StubAppender");
return null;
}

if (layout == null)
{
layout = PatternLayout.createDefaultLayout();
}
//noinspection unchecked
return new CustomLogAppender(name, filter, layout, ignoreExceptions);
}

public static String getLogLinesAfter(int index)
{
JsonObject responce = new JsonObject();
StringBuilder stringBuilder = new StringBuilder();
synchronized (LOG)
{
responce.addProperty("size", LOG.size());
if (index < LOG.size()) for (String line : LOG.subList(index, LOG.size())) stringBuilder.append(line);
}
responce.addProperty("text", stringBuilder.toString());
return responce.toString();
}

@Override
public void append(LogEvent event)
{
LOG.add(new String(getLayout().toByteArray(event)));
while (LOG.size() > LOG_LINES_KEPT) LOG.remove(0);
}
}
Expand Up @@ -43,6 +43,7 @@
import freemarker.template.*;
import net.doubledoordev.backend.Main;
import net.doubledoordev.backend.util.Constants;
import net.doubledoordev.backend.util.CustomLogAppender;
import net.doubledoordev.backend.util.Settings;

import java.io.FileNotFoundException;
Expand Down Expand Up @@ -118,11 +119,13 @@ public static Response handleGet(HashMap<String, Object> dataObject, IHTTPSessio
{
switch (args[0])
{
case "consoleText":
case "serverConsoleText":
return new Response(OK, MIME_PLAINTEXT, getServerByName(args[1]).getLogLinesAfter(Integer.parseInt(args[2])));
case "backendConsoleText":
return new Response(OK, MIME_PLAINTEXT, CustomLogAppender.getLogLinesAfter(Integer.parseInt(args[1])));
case "worldmanager":
if (args.length > 1) dataObject.put("wm", getServerByName(args[1]).getWorldManager());
case "console":
case "serverconsole":
case "servers":
if (args.length > 1) dataObject.put("server", getServerByName(args[1]));
break;
Expand Down
14 changes: 8 additions & 6 deletions src/main/resources/log4j2.xml
Expand Up @@ -38,16 +38,16 @@
~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<Configuration status="WARN">
<Configuration status="WARN" packages="net.doubledoordev.backend.util">
<Appenders>
<Console name="ConsoleWithMethod" target="SYSTEM_OUT">
<PatternLayout pattern="[%p - %c - %M] %m%n"/>
</Console>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%p - %c] %m%n"/>
</Console>
<CustomLogAppender name="CustomLogAppender">
<PatternLayout pattern="[%p - %c] %m%n"/>
</CustomLogAppender>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%p - %c - %M] %m%n"/>
<PatternLayout pattern="[%p - %c] %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<OnStartupTriggeringPolicy/>
Expand All @@ -64,11 +64,13 @@
</Appenders>
<Loggers>
<Logger name="Main" level="trace" additivity="false">
<AppenderRef ref="ConsoleWithMethod"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="FileWithMethod"/>
<AppenderRef ref="CustomLogAppender"/>
</Logger>
<Root level="trace" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="CustomLogAppender"/>
</Root>
</Loggers>
</Configuration>
69 changes: 5 additions & 64 deletions src/main/resources/templates/console.ftl
@@ -1,65 +1,7 @@
<!DOCTYPE html>
<!--
~ Unless otherwise specified through the '@author' tag or comments at
~ the top of the file or on a specific portion of the code the following license applies:
~
~ Copyright (c) 2014, DoubleDoorDevelopment
~ All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
~ modification, are permitted provided that the following conditions are met:
~
~ * Redistributions of source code must retain the above copyright notice, this
~ list of conditions and the following disclaimer.
~
~ * Redistributions in binary form must reproduce the above copyright notice,
~ this list of conditions and the following disclaimer in the documentation
~ and/or other materials provided with the distribution.
~
~ * The header specified or the above copyright notice, this list of conditions
~ and the following disclaimer below must be displayed at the top of the source code
~ of any web page received while using any part of the service this software provides.
~
~ The header to be displayed:
~ This page was generated by DoubleDoorDevelopment's D3Backend or a derivative thereof.
~
~ * Neither the name of the project nor the names of its
~ contributors may be used to endorse or promote products derived from
~ this software without specific prior written permission.
~
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
~ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
~ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
~ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
~ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
~ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
~ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
~ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Console ${server.name}</title>
<!-- Le meta -->
<meta name="author" content="Dries007">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Le styles -->
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/css/font-awesome.min.css" rel="stylesheet">
</head>
<body>
<b>Note: This is not a real console. This is just a command interface that displays responses.</b>
<textarea class="textarea form-control" id="text" style="height: 445px;"></textarea>
<input type="text" class="form-control" placeholder="Command..." onkeydown="if (event.keyCode == 13) sendCommand(this)">
<script src="/static/js/commands.js"></script>
<#include "header.ftl">
<textarea class="textarea form-control" id="text" style="height: 800px;"></textarea>
<script>
function sendCommand($input) {
execute('PUT', window.location.origin, ["console", "${server.name}", $input.value], function () {$input.value = ""; })
}
var callURL = window.location.origin + "/consoleText/${server.name}";
var callURL = window.location.origin + "/backendConsoleText";
var lines = 0;
var textarea = document.getElementById('text');
var autoScroll = true;
Expand All @@ -76,7 +18,7 @@
if (xmlhttp.status != 200) alert("Error...\n" + xmlhttp.responseText);
else
{
autoScroll = textarea.scrollHeight <= textarea.scrollTop + 500;
autoScroll = textarea.scrollHeight <= textarea.scrollTop + 800;
responce = JSON.parse(xmlhttp.responseText);
textarea.value += responce["text"];
lines = responce["size"];
Expand All @@ -88,5 +30,4 @@
setInterval(getConsoleText, 5000);
getConsoleText();
</script>
</body>
</html>
<#include "footer.ftl">
3 changes: 3 additions & 0 deletions src/main/resources/templates/header.ftl
Expand Up @@ -85,6 +85,9 @@
</li>
<li id="newserverListNavTab"><a href="/newserver">New Server</a></li>
<li id="usersNavTab"><a href="/users">Users</a></li>
<#if user.isAdmin()>
<li id="consoleNavTab"><a href="/console">Console</a></li>
</#if>
</#if>
</ul>
<ul class="nav navbar-nav navbar-right">
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/server.ftl
Expand Up @@ -5,7 +5,7 @@
<p>
<div class="btn-group">
<button type="button" <#if allowModify && !server.online>onclick="call('server', '${server.name}', 'startServer')" <#else>disabled</#if> class="btn btn-success">Start</button>
<button type="button" class="btn btn-info" <#if allowModify>onclick="openPopup('/console/${server.name}')" <#else>disabled</#if>>Console</button>
<button type="button" class="btn btn-info" <#if allowModify>onclick="openPopup('/serverconsole/${server.name}')" <#else>disabled</#if>>Console</button>
<button type="button" <#if allowModify && server.online>onclick="call('server', '${server.name}', 'stopServer')" <#else>disabled</#if> class="btn btn-warning">Stop</button>
<button type="button" <#if allowModify && server.online>onclick="if (confirm('Are you sure?')) call('server', '${server.name}', 'forceStopServer');" <#else>disabled</#if> class="btn btn-danger">Kill</button>
</div>
Expand Down

0 comments on commit 69c3aa6

Please sign in to comment.