Adding MOTD on Status Page

This commit is contained in:
Silversthorn 2021-08-29 00:48:30 +02:00
parent a05b3a8634
commit 3ff3d0ccf1
7 changed files with 269 additions and 18 deletions

View File

@ -1,9 +1,12 @@
from app.classes.shared.helpers import Helpers
import struct
import socket
import base64
import json
import sys
import os
import logging.config
from app.classes.shared.console import console
logger = logging.getLogger(__name__)
@ -25,8 +28,26 @@ class Server:
description = self.description
if 'extra' in description.keys():
for e in description['extra']:
#Conversion format code needed only for Java Version
lines.append(get_code_format("reset"))
if "bold" in e.keys():
lines.append(get_code_format("bold"))
if "italic" in e.keys():
lines.append(get_code_format("italic"))
if "underlined" in e.keys():
lines.append(get_code_format("underlined"))
if "strikethrough" in e.keys():
lines.append(get_code_format("strikethrough"))
if "obfuscated" in e.keys():
lines.append(get_code_format("obfuscated"))
if "color" in e.keys():
lines.append(get_code_format(e['color']))
#Then append the text
if "text" in e.keys():
lines.append(e['text'])
if e['text'] == '\n':
lines.append("§§")
else:
lines.append(e['text'])
total_text = " ".join(lines)
self.description = total_text
@ -70,6 +91,26 @@ class Player:
def __str__(self):
return self.name
def get_code_format(format_name):
root_dir = os.path.abspath(os.path.curdir)
format_file = os.path.join(root_dir, 'app', 'config', 'motd_format.json')
try:
with open(format_file, "r", encoding='utf-8') as f:
data = json.load(f)
if format_name in data.keys():
return data.get(format_name)
else:
logger.error("Format MOTD Error: format name {} does not exist".format(format_name))
console.error("Format MOTD Error: format name {} does not exist".format(format_name))
return ""
except Exception as e:
logger.critical("Config File Error: Unable to read {} due to {}".format(format_file, e))
console.critical("Config File Error: Unable to read {} due to {}".format(format_file, e))
return ""
# For the rest of requests see wiki.vg/Protocol
def ping(ip, port):

View File

@ -4,6 +4,7 @@ import time
import psutil
import logging
import datetime
import base64
from app.classes.shared.helpers import helper
@ -145,12 +146,19 @@ class Stats:
logger.info("Unable to read json from ping_obj: {}".format(e))
pass
try:
server_icon = base64.encodebytes(ping_obj.icon)
except Exception as e:
server_icon = False
logger.info("Unable to read the server icon : {}".format(e))
ping_data = {
'online': online_stats.get("online", 0),
'max': online_stats.get('max', 0),
'players': online_stats.get('players', 0),
'server_description': ping_obj.description,
'server_version': ping_obj.version
'server_version': ping_obj.version,
'server_icon': server_icon
}
return ping_data
@ -246,6 +254,62 @@ class Stats:
server_stats_list.append(server_stats)
return server_stats_list
def get_raw_server_stats(self, server_id):
server_stats = {}
server = self.controller.get_server_obj(server_id)
logger.debug('Getting stats for server: {}'.format(server_id))
# get our server object, settings and data dictionaries
server_obj = self.controller.get_server_obj(server_id)
server_obj.reload_server_settings()
server_settings = self.controller.get_server_settings(server_id)
server_data = self.controller.get_server_data(server_id)
# world data
world_name = server_settings.get('level-name', 'Unknown')
world_path = os.path.join(server_data.get('path', None), world_name)
# process stats
p_stats = self._get_process_stats(server_obj.PID)
# TODO: search server properties file for possible override of 127.0.0.1
internal_ip = server_data.get('server_ip', "127.0.0.1")
server_port = server_settings.get('server-port', "25565")
logger.debug("Pinging server '{}' on {}:{}".format(server.name, internal_ip, server_port))
int_mc_ping = ping(internal_ip, int(server_port))
int_data = False
ping_data = {}
# if we got a good ping return, let's parse it
if int_mc_ping:
int_data = True
ping_data = self.parse_server_ping(int_mc_ping)
server_stats = {
'id': server_id,
'started': server_obj.get_start_time(),
'running': server_obj.check_running(),
'cpu': p_stats.get('cpu_usage', 0),
'mem': p_stats.get('memory_usage', 0),
"mem_percent": p_stats.get('mem_percentage', 0),
'world_name': world_name,
'world_size': self.get_world_size(world_path),
'server_port': server_port,
'int_ping_results': int_data,
'online': ping_data.get("online", False),
"max": ping_data.get("max", False),
'players': ping_data.get("players", False),
'desc': ping_data.get("server_description", False),
'version': ping_data.get("server_version", False),
'icon': ping_data.get("server_icon", False)
}
return server_stats
def record_stats(self):
stats_to_send = self.get_node_stats()

View File

@ -97,6 +97,14 @@ class Controller:
server_obj = self.get_server_obj(server_id)
server_obj.reload_server_settings()
def get_server_settings(self, server_id):
for s in self.servers_list:
if int(s['server_id']) == int(server_id):
return s['server_settings']
logger.warning("Unable to find server object for server id {}".format(server_id))
return False
def get_server_obj(self, server_id):
for s in self.servers_list:
if int(s['server_id']) == int(server_id):
@ -104,6 +112,14 @@ class Controller:
logger.warning("Unable to find server object for server id {}".format(server_id))
return False
def get_server_data(self, server_id):
for s in self.servers_list:
if int(s['server_id']) == int(server_id):
return s['server_data_obj']
logger.warning("Unable to find server object for server id {}".format(server_id))
return False
@staticmethod
def list_defined_servers():
@ -184,14 +200,6 @@ class Controller:
server_list = db_helper.get_authorized_servers(userId)
return server_list
def get_server_data(self, server_id):
for s in self.servers_list:
if int(s['server_id']) == int(server_id):
return s['server_data_obj']
logger.warning("Unable to find server object for server id {}".format(server_id))
return False
def list_running_servers(self):
running_servers = []

View File

@ -26,6 +26,10 @@ class StatusHandler(BaseHandler):
def get(self):
page_data = {}
page_data['servers'] = db_helper.get_all_servers_stats()
for srv in page_data['servers']:
server_data = srv.get('server_data', False)
server_id = server_data.get('server_id', False)
srv['raw_ping_result'] = self.controller.stats.get_raw_server_stats(server_id)
template = 'public/status.html'
@ -37,6 +41,10 @@ class StatusHandler(BaseHandler):
def post(self):
page_data = {}
page_data['servers'] = db_helper.get_all_servers_stats()
for srv in page_data['servers']:
server_data = srv.get('server_data', False)
server_id = server_data.get('server_id', False)
srv['raw_ping_result'] = self.controller.stats.get_raw_server_stats(server_id)
template = 'public/status.html'

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,125 @@
var obfuscators = [];
var styleMap = {
'§0': 'color:#000000',
'§1': 'color:#0000AA',
'§2': 'color:#00AA00',
'§3': 'color:#00AAAA',
'§4': 'color:#AA0000',
'§5': 'color:#AA00AA',
'§6': 'color:#FFAA00',
'§7': 'color:#AAAAAA',
'§8': 'color:#555555',
'§9': 'color:#5555FF',
'§a': 'color:#55FF55',
'§b': 'color:#55FFFF',
'§c': 'color:#FF5555',
'§d': 'color:#FF55FF',
'§e': 'color:#FFFF55',
'§f': 'color:#FFFFFF',
'§l': 'font-weight:bold',
'§m': 'text-decoration:line-through',
'§n': 'text-decoration:underline',
'§o': 'font-style:italic',
};
function obfuscate(string, elem) {
var magicSpan,
currNode;
if(string.indexOf('<br>') > -1) {
elem.innerHTML = string;
for(var j = 0, len = elem.childNodes.length; j < len; j++) {
currNode = elem.childNodes[j];
if(currNode.nodeType === 3) {
magicSpan = document.createElement('span');
magicSpan.innerHTML = currNode.nodeValue;
elem.replaceChild(magicSpan, currNode);
init(magicSpan);
}
}
} else {
init(elem, string);
}
function init(el, str) {
var i = 0,
obsStr = str || el.innerHTML,
len = obsStr.length;
obfuscators.push( window.setInterval(function () {
if(i >= len) i = 0;
obsStr = replaceRand(obsStr, i);
el.innerHTML = obsStr;
i++;
}, 0) );
}
function randInt(min, max) {
return Math.floor( Math.random() * (max - min + 1) ) + min;
}
function replaceRand(string, i) {
var randChar = String.fromCharCode( randInt(64, 95) );
return string.substr(0, i) + randChar + string.substr(i + 1, string.length);
}
}
function applyCode(string, codes) {
var elem = document.createElement('span'),
obfuscated = false;
string = string.replace(/\x00*/g, '');
for(var i = 0, len = codes.length; i < len; i++) {
elem.style.cssText += styleMap[codes[i]] + ';';
if(codes[i] === '§k') {
obfuscate(string, elem);
obfuscated = true;
}
}
if(!obfuscated) elem.innerHTML = string;
return elem;
}
function parseStyle(string) {
var codes = string.match(/§.{1}/g) || [],
indexes = [],
apply = [],
tmpStr,
deltaIndex,
noCode,
final = document.createDocumentFragment(),
i;
string = string.replace(/\n|\\n/g, '<br>');
for(i = 0, len = codes.length; i < len; i++) {
indexes.push( string.indexOf(codes[i]) );
string = string.replace(codes[i], '\x00\x00');
}
if(indexes[0] !== 0) {
final.appendChild( applyCode( string.substring(0, indexes[0]), [] ) );
}
for(i = 0; i < len; i++) {
indexDelta = indexes[i + 1] - indexes[i];
if(indexDelta === 2) {
while(indexDelta === 2) {
apply.push ( codes[i] );
i++;
indexDelta = indexes[i + 1] - indexes[i];
}
apply.push ( codes[i] );
} else {
apply.push( codes[i] );
}
if( apply.lastIndexOf('§r') > -1) {
apply = apply.slice( apply.lastIndexOf('§r') + 1 );
}
tmpStr = string.substring( indexes[i], indexes[i + 1] );
final.appendChild( applyCode(tmpStr, apply) );
}
return final;
}
function clearObfuscators() {
var i = obfuscators.length;
for(;i--;) {
clearInterval(obfuscators[i]);
}
obfuscators = [];
}
function initParser(input, output) {
clearObfuscators();
var input = document.getElementById(input),
output = document.getElementById(output),
parsed = parseStyle( input.innerHTML );
output.innerHTML = '';
output.appendChild(parsed);
}

View File

@ -32,9 +32,14 @@
<td>
{{ server['stats']['online'] }} / {{ server['stats']['max'] }} {{ translate('dashboard', 'max') }}<br />
</td>
<td id="input_motd">
<td>
{% if server['stats']['desc'] != 'False' %}
{{ server['stats']['desc'] }} <br />
{% if server['raw_ping_result']['icon'] %}
<img src="data:image/png;base64,{% raw server['raw_ping_result']['icon'] %}" alt="icon"/>
{% else %}
<img src="/static/assets/images/pack.png" alt="icon" />
{% end %}
<span id="input_motd">{{ server['stats']['desc'] }}</span> <br />
{% end %}
</td>
<td>
@ -48,7 +53,7 @@
</td>
{% end %}
<td>
{% if server['stats']['running'] %}
{% if server['stats']['int_ping_results'] %}
<span class="text-success"><i class="fas fa-signal"></i> {{ translate('dashboard', 'online') }}</span>
{% else %}
<span class="text-danger"><i class="fas fa-ban"></i> {{ translate('dashboard', 'offline') }}</span>
@ -67,11 +72,11 @@
{% block js %}
<!-- <script src="/static/assets/js/motd.js"></script>
<script src="/static/assets/js/motd.js"></script>
<script>
//$(document).ready(function () {
// initParser('input_motd', 'output_motd');
//}());
</script> -->
$(document).ready(function () {
initParser('input_motd', 'input_motd');
}());
</script>
{% end %}