diff --git a/app/classes/minecraft/mc_ping.py b/app/classes/minecraft/mc_ping.py
index 4a27d686..0d21d9d4 100644
--- a/app/classes/minecraft/mc_ping.py
+++ b/app/classes/minecraft/mc_ping.py
@@ -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):
diff --git a/app/classes/minecraft/server_props.py b/app/classes/minecraft/server_props.py
index cd4ffd89..89c24c99 100644
--- a/app/classes/minecraft/server_props.py
+++ b/app/classes/minecraft/server_props.py
@@ -19,7 +19,7 @@ class ServerProps:
s = line
s1 = s[:s.find('=')]
if '\n' in s:
- s2 = s[s.find('=')+1:s.find('\\')]
+ s2 = s[s.find('=')+1:s.find('\n')]
else:
s2 = s[s.find('=')+1:]
d[s1] = s2
diff --git a/app/classes/minecraft/serverjars.py b/app/classes/minecraft/serverjars.py
index e7a5f448..66f90cbc 100644
--- a/app/classes/minecraft/serverjars.py
+++ b/app/classes/minecraft/serverjars.py
@@ -11,6 +11,7 @@ from app.classes.shared.helpers import helper
from app.classes.shared.console import console
from app.classes.shared.models import Servers
from app.classes.minecraft.server_props import ServerProps
+from app.classes.web.websocket_helper import websocket_helper
logger = logging.getLogger(__name__)
@@ -173,11 +174,11 @@ class ServerJars:
response = self._get_api_result(url)
return response
- def download_jar(self, server, version, path):
- update_thread = threading.Thread(target=self.a_download_jar, daemon=True, name="exe_download", args=(server, version, path))
+ def download_jar(self, server, version, path, name):
+ update_thread = threading.Thread(target=self.a_download_jar, daemon=True, name="exe_download", args=(server, version, path, name))
update_thread.start()
- def a_download_jar(self, server, version, path):
+ def a_download_jar(self, server, version, path, name):
fetch_url = "{base}/api/fetchJar/{server}/{version}".format(base=self.base_url, server=server, version=version)
# open a file stream
@@ -189,6 +190,8 @@ class ServerJars:
except Exception as e:
logger.error("Unable to save jar to {path} due to error:{error}".format(path=path, error=e))
pass
+ websocket_helper.broadcast('notification', "Executable download finished for server named: " + name)
+
return False
diff --git a/app/classes/minecraft/stats.py b/app/classes/minecraft/stats.py
index 6d0492c2..30b78697 100644
--- a/app/classes/minecraft/stats.py
+++ b/app/classes/minecraft/stats.py
@@ -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
@@ -167,7 +175,7 @@ class Stats:
# TODO: search server properties file for possible override of 127.0.0.1
- internal_ip = server_data.get('server-ip', "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 {} on port {}".format(internal_ip, server_port))
@@ -210,7 +218,7 @@ class 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")
+ 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(s.get('server_name', "ID#{}".format(server_id)), internal_ip, server_port))
@@ -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()
diff --git a/app/classes/shared/controller.py b/app/classes/shared/controller.py
index 9c7e53cf..97fd1775 100644
--- a/app/classes/shared/controller.py
+++ b/app/classes/shared/controller.py
@@ -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():
@@ -157,7 +173,7 @@ class Controller:
@staticmethod
def can_add_role(user_id):
- #TODO: Complete if we need a User Addition limit
+ #TODO: Complete if we need a Role Addition limit
#return db_helper.can_add_in_crafty(user_id, Enum_Permissions_Crafty.Roles_Config)
return True
@@ -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 = []
@@ -297,7 +305,7 @@ class Controller:
server_stop = "stop"
# download the jar
- server_jar_obj.download_jar(server, version, full_jar_path)
+ server_jar_obj.download_jar(server, version, full_jar_path, name)
new_id = self.register_server(name, server_id, server_dir, backup_path, server_command, server_file, server_log_file, server_stop)
return new_id
diff --git a/app/classes/shared/models.py b/app/classes/shared/models.py
index bb95d56b..ec50704a 100644
--- a/app/classes/shared/models.py
+++ b/app/classes/shared/models.py
@@ -242,7 +242,8 @@ class db_builder:
# Users.enabled: True,
# Users.superuser: True
#}).execute()
- db_shortcuts.add_user(username, password=password, superuser=True)
+ user_id = db_shortcuts.add_user(username, password=password, superuser=True)
+ #db_shortcuts.update_user(user_id, user_crafty_data={"permissions_mask":"111", "server_quantity":[-1,-1,-1]} )
#console.info("API token is {}".format(api_token))
@@ -257,6 +258,9 @@ class db_builder:
class db_shortcuts:
+ #************************************************************************************************
+ # Generic Databse Methods
+ #************************************************************************************************
@staticmethod
def return_rows(query):
rows = []
@@ -271,6 +275,14 @@ class db_shortcuts:
return rows
+ @staticmethod
+ def return_db_rows(model):
+ data = [model_to_dict(row) for row in model]
+ return data
+
+ #************************************************************************************************
+ # Generic Servers Methods
+ #************************************************************************************************
@staticmethod
def create_server(name: str, server_uuid: str, server_dir: str, backup_path: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port=25565):
return Servers.insert({
@@ -302,6 +314,9 @@ class db_shortcuts:
except IndexError:
return {}
+ #************************************************************************************************
+ # Servers Methods
+ #************************************************************************************************
@staticmethod
def get_all_defined_servers():
query = Servers.select()
@@ -345,21 +360,14 @@ class db_shortcuts:
return server_data
@staticmethod
- def get_user_roles_id(user_id):
- roles_list = []
- roles = User_Roles.select().where(User_Roles.user_id == user_id)
- for r in roles:
- roles_list.append(db_helper.get_role(r.role_id)['role_id'])
- return roles_list
-
- @staticmethod
- def get_user_roles_names(user_id):
- roles_list = []
- roles = User_Roles.select().where(User_Roles.user_id == user_id)
- for r in roles:
- roles_list.append(db_helper.get_role(r.role_id)['role_name'])
- return roles_list
+ def get_server_friendly_name(server_id):
+ server_data = db_helper.get_server_data_by_id(server_id)
+ friendly_name = "{} with ID: {}".format(server_data.get('server_name', None), server_data.get('server_id', 0))
+ return friendly_name
+ #************************************************************************************************
+ # Servers Permissions Methods
+ #************************************************************************************************
@staticmethod
def get_permissions_mask(role_id, server_id):
permissions_mask = ''
@@ -414,6 +422,10 @@ class db_shortcuts:
server_data.append({'server_data': s, "stats": db_helper.return_rows(latest)[0]})
return server_data
+
+ #************************************************************************************************
+ # Servers_Stats Methods
+ #************************************************************************************************
@staticmethod
def get_server_stats_by_id(server_id):
stats = Server_Stats.select().where(Server_Stats.server_id == server_id).order_by(Server_Stats.created.desc()).limit(1)
@@ -438,6 +450,32 @@ class db_shortcuts:
return False
return True
+ @staticmethod
+ def set_update(server_id, value):
+ try:
+ row = Server_Stats.select().where(Server_Stats.server_id == server_id)
+ except Exception as ex:
+ logger.error("Database entry not found. ".format(ex))
+ with database.atomic():
+ Server_Stats.update(updating=value).where(Server_Stats.server_id == server_id).execute()
+
+ @staticmethod
+ def get_TTL_without_player(server_id):
+ last_stat = Server_Stats.select().where(Server_Stats.server_id == server_id).order_by(Server_Stats.created.desc()).first()
+ last_stat_with_player = Server_Stats.select().where(Server_Stats.server_id == server_id).where(Server_Stats.online > 0).order_by(Server_Stats.created.desc()).first()
+ return last_stat.created - last_stat_with_player.created
+
+ @staticmethod
+ def can_stop_no_players(server_id, time_limit):
+ can = False
+ ttl_no_players = get_TTL_without_player(server_id)
+ if (time_limit == -1) or (ttl_no_players > time_limit):
+ can = True
+ return can
+
+ #************************************************************************************************
+ # Crafty Permissions Methods
+ #************************************************************************************************
@staticmethod
def get_crafty_permissions_mask(user_id):
permissions_mask = ''
@@ -470,6 +508,9 @@ class db_shortcuts:
}
return quantity_list
+ #************************************************************************************************
+ # User_Crafty Methods
+ #************************************************************************************************
@staticmethod
def get_User_Crafty(user_id):
try:
@@ -488,6 +529,11 @@ class db_shortcuts:
user_crafty = db_helper.get_User_Crafty(user_id)
return user_crafty
+ @staticmethod
+ def add_user_crafty(user_id, uc_permissions):
+ user_crafty = User_Crafty.insert({User_Crafty.user_id: user_id, User_Crafty.permissions: uc_permissions}).execute()
+ return user_crafty
+
@staticmethod
def get_created_quantity_list(user_id):
user_crafty = db_helper.get_User_Crafty(user_id)
@@ -518,7 +564,11 @@ class db_shortcuts:
user_crafty.created_server += 1
User_Crafty.save(user_crafty)
return user_crafty.created_server
-
+
+
+ #************************************************************************************************
+ # Host_Stats Methods
+ #************************************************************************************************
@staticmethod
def get_latest_hosts_stats():
query = Host_Stats.select().order_by(Host_Stats.id.desc()).get()
@@ -532,16 +582,15 @@ class db_shortcuts:
if len(test) == 0:
return token
+
+ #************************************************************************************************
+ # Users Methods
+ #************************************************************************************************
@staticmethod
def get_all_users():
query = Users.select()
return query
- @staticmethod
- def get_all_roles():
- query = Roles.select()
- return query
-
@staticmethod
def get_user_id_by_name(username):
if username == "SYSTEM":
@@ -562,57 +611,12 @@ class db_shortcuts:
return user
else:
return {}
-
- @staticmethod
- def add_role_to_user(user_id, role_id):
- User_Roles.insert({
- User_Roles.user_id: user_id,
- User_Roles.role_id: role_id
- }).execute()
-
- @staticmethod
- def add_user_roles(user):
- if type(user) == dict:
- user_id = user['user_id']
- else:
- user_id = user.user_id
-
- # I just copied this code from get_user, it had those TODOs & comments made by mac - Lukas
-
- roles_query = User_Roles.select().join(Roles, JOIN.INNER).where(User_Roles.user_id == user_id)
- # TODO: this query needs to be narrower
- roles = set()
- for r in roles_query:
- roles.add(r.role_id.role_id)
-
- user['roles'] = roles
- #logger.debug("user: ({}) {}".format(user_id, user))
- return user
-
- @staticmethod
- def add_user_crafty(user_id, uc_permissions):
- user_crafty = User_Crafty.insert({User_Crafty.user_id: user_id, User_Crafty.permissions: uc_permissions}).execute()
- return user_crafty
-
- @staticmethod
- def add_role_server(server_id, role_id, rs_permissions="00000000"):
- servers = Role_Servers.insert({Role_Servers.server_id: server_id, Role_Servers.role_id: role_id, Role_Servers.permissions: rs_permissions}).execute()
- return servers
-
-
+
@staticmethod
def user_query(user_id):
user_query = Users.select().where(Users.user_id == user_id)
return user_query
-
- @staticmethod
- def user_role_query(user_id):
- user_query = User_Roles.select().where(User_Roles.user_id == user_id)
- query = Roles.select().where(Roles.role_id == -1)
- for u in user_query:
- query = Roles.select().where(Roles.role_id == u.role_id)
- return query
-
+
@staticmethod
def get_user(user_id):
if user_id == 0:
@@ -731,6 +735,14 @@ class db_shortcuts:
return False
return True
+ #************************************************************************************************
+ # Roles Methods
+ #************************************************************************************************
+ @staticmethod
+ def get_all_roles():
+ query = Roles.select()
+ return query
+
@staticmethod
def get_roleid_by_name(role_name):
try:
@@ -805,18 +817,79 @@ class db_shortcuts:
if not db_shortcuts.get_role(role_id):
return False
return True
+
+ #************************************************************************************************
+ # User_Roles Methods
+ #************************************************************************************************
+ @staticmethod
+ def get_user_roles_id(user_id):
+ roles_list = []
+ roles = User_Roles.select().where(User_Roles.user_id == user_id)
+ for r in roles:
+ roles_list.append(db_helper.get_role(r.role_id)['role_id'])
+ return roles_list
+ @staticmethod
+ def get_user_roles_names(user_id):
+ roles_list = []
+ roles = User_Roles.select().where(User_Roles.user_id == user_id)
+ for r in roles:
+ roles_list.append(db_helper.get_role(r.role_id)['role_name'])
+ return roles_list
+
+ @staticmethod
+ def add_role_to_user(user_id, role_id):
+ User_Roles.insert({
+ User_Roles.user_id: user_id,
+ User_Roles.role_id: role_id
+ }).execute()
+
+ @staticmethod
+ def add_user_roles(user):
+ if type(user) == dict:
+ user_id = user['user_id']
+ else:
+ user_id = user.user_id
+
+ # I just copied this code from get_user, it had those TODOs & comments made by mac - Lukas
+
+ roles_query = User_Roles.select().join(Roles, JOIN.INNER).where(User_Roles.user_id == user_id)
+ # TODO: this query needs to be narrower
+ roles = set()
+ for r in roles_query:
+ roles.add(r.role_id.role_id)
+
+ user['roles'] = roles
+ #logger.debug("user: ({}) {}".format(user_id, user))
+ return user
+
+
+ #************************************************************************************************
+ # Role_Servers Methods
+ #************************************************************************************************
+ @staticmethod
+ def add_role_server(server_id, role_id, rs_permissions="00000000"):
+ servers = Role_Servers.insert({Role_Servers.server_id: server_id, Role_Servers.role_id: role_id, Role_Servers.permissions: rs_permissions}).execute()
+ return servers
+
+
+ @staticmethod
+ def user_role_query(user_id):
+ user_query = User_Roles.select().where(User_Roles.user_id == user_id)
+ query = Roles.select().where(Roles.role_id == -1)
+ for u in user_query:
+ query = Roles.select().where(Roles.role_id == u.role_id)
+ return query
+
+
+ #************************************************************************************************
+ # Commands Methods
+ #************************************************************************************************
@staticmethod
def get_unactioned_commands():
query = Commands.select().where(Commands.executed == 0)
return db_helper.return_rows(query)
- @staticmethod
- def get_server_friendly_name(server_id):
- server_data = db_helper.get_server_data_by_id(server_id)
- friendly_name = "{} with ID: {}".format(server_data.get('server_name', None), server_data.get('server_id', 0))
- return friendly_name
-
@staticmethod
def send_command(user_id, server_id, remote_ip, command):
@@ -833,16 +906,6 @@ class db_shortcuts:
Commands.command: command
}).execute()
- @staticmethod
- def get_actity_log():
- q = Audit_Log.select()
- return db_helper.return_db_rows(q)
-
- @staticmethod
- def return_db_rows(model):
- data = [model_to_dict(row) for row in model]
- return data
-
@staticmethod
def mark_command_complete(command_id=None):
if command_id is not None:
@@ -850,6 +913,14 @@ class db_shortcuts:
Commands.update({
Commands.executed: True
}).where(Commands.command_id == command_id).execute()
+
+ #************************************************************************************************
+ # Audit_Log Methods
+ #************************************************************************************************
+ @staticmethod
+ def get_actity_log():
+ q = Audit_Log.select()
+ return db_helper.return_db_rows(q)
def add_to_audit_log(self, user_id, log_msg, server_id=None, source_ip=None):
logger.debug("Adding to audit log User:{} - Message: {} ".format(user_id, log_msg))
@@ -877,6 +948,9 @@ class db_shortcuts:
Audit_Log.source_ip: source_ip
}).execute()
+ #************************************************************************************************
+ # Schedules Methods
+ #************************************************************************************************
@staticmethod
def create_scheduled_task(server_id, action, interval, interval_type, start_time, command, comment=None, enabled=True):
sch_id = Schedules.insert({
@@ -916,6 +990,9 @@ class db_shortcuts:
def get_schedules_enabled():
return Schedules.select().where(Schedules.enabled == True).execute()
+ #************************************************************************************************
+ # Backups Methods
+ #************************************************************************************************
@staticmethod
def get_backup_config(server_id):
try:
@@ -937,15 +1014,6 @@ class db_shortcuts:
}
return conf
- @staticmethod
- def set_update(server_id, value):
- try:
- row = Server_Stats.select().where(Server_Stats.server_id == server_id)
- except Exception as ex:
- logger.error("Database entry not found. ".format(ex))
- with database.atomic():
- Server_Stats.update(updating=value).where(Server_Stats.server_id == server_id).execute()
-
@staticmethod
def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None, auto_enabled: bool = True):
logger.debug("Updating server {} backup config with {}".format(server_id, locals()))
@@ -992,6 +1060,10 @@ class db_shortcuts:
b = Backups.create(**conf)
logger.debug("Creating new backup record.")
+
+#************************************************************************************************
+# Servers Permissions Class
+#************************************************************************************************
class Enum_Permissions_Server(Enum):
Commands = 0
Terminal = 1
@@ -1037,6 +1109,9 @@ class Permissions_Servers:
def get_permission(permission_mask, permission_tested: Enum_Permissions_Server):
return permission_mask[permission_tested.value]
+#************************************************************************************************
+# Crafty Permissions Class
+#************************************************************************************************
class Enum_Permissions_Crafty(Enum):
Server_Creation = 0
User_Config = 1
@@ -1077,6 +1152,10 @@ class Permissions_Crafty:
def get_permission(permission_mask, permission_tested: Enum_Permissions_Crafty):
return permission_mask[permission_tested.value]
+
+#************************************************************************************************
+# Static Accessors
+#************************************************************************************************
installer = db_builder()
db_helper = db_shortcuts()
server_permissions = Permissions_Servers()
diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py
index 6998be13..a504c15c 100644
--- a/app/classes/shared/server.py
+++ b/app/classes/shared/server.py
@@ -115,7 +115,6 @@ class Server:
self.settings = server_data_obj
# build our server run command
- self.setup_server_run_command()
if server_data_obj['auto_start']:
delay = int(self.settings['auto_start_delay'])
diff --git a/app/classes/web/status_handler.py b/app/classes/web/status_handler.py
new file mode 100644
index 00000000..aeaba5c1
--- /dev/null
+++ b/app/classes/web/status_handler.py
@@ -0,0 +1,55 @@
+from re import template
+import sys
+import json
+import logging
+import tornado.web
+import tornado.escape
+import requests
+
+from app.classes.shared.helpers import helper
+from app.classes.web.base_handler import BaseHandler
+from app.classes.shared.console import console
+from app.classes.shared.models import Users, fn, db_helper
+
+logger = logging.getLogger(__name__)
+
+try:
+ import bleach
+
+except ModuleNotFoundError as e:
+ logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
+ console.critical("Import Error: Unable to load {} module".format(e.name))
+ sys.exit(1)
+
+
+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'
+
+ self.render(
+ template,
+ data=page_data,
+ translate=self.translator.translate,
+ )
+ 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'
+
+ self.render(
+ template,
+ data=page_data,
+ translate=self.translator.translate,
+ )
\ No newline at end of file
diff --git a/app/classes/web/tornado.py b/app/classes/web/tornado.py
index a82f619f..aeed856f 100644
--- a/app/classes/web/tornado.py
+++ b/app/classes/web/tornado.py
@@ -29,6 +29,7 @@ try:
from app.classes.shared.translation import translation
from app.classes.web.upload_handler import UploadHandler
from app.classes.web.http_handler import HTTPHandler, HTTPHandlerPage
+ from app.classes.web.status_handler import StatusHandler
except ModuleNotFoundError as e:
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
@@ -132,6 +133,7 @@ class Webserver:
(r'/api/stats/node', NodeStats, handler_args),
(r'/ws', SocketHandler, handler_args),
(r'/upload', UploadHandler),
+ (r'/status', StatusHandler, handler_args)
]
app = tornado.web.Application(
diff --git a/app/frontend/static/assets/css/crafty.css b/app/frontend/static/assets/css/crafty.css
index 892bd52f..c39b2c2a 100644
--- a/app/frontend/static/assets/css/crafty.css
+++ b/app/frontend/static/assets/css/crafty.css
@@ -80,3 +80,8 @@ body { background-color: var(--dark) !important; /* Firefox */ }
.actions_serverlist > a > i {
cursor: pointer;
}
+.corner {
+ position: absolute;
+ margin-top: 0;
+ margin-left: 0;
+}
\ No newline at end of file
diff --git a/app/frontend/static/assets/images/logo_long.png b/app/frontend/static/assets/images/logo_long.png
new file mode 100644
index 00000000..8ebca3a5
Binary files /dev/null and b/app/frontend/static/assets/images/logo_long.png differ
diff --git a/app/frontend/static/assets/images/pack.png b/app/frontend/static/assets/images/pack.png
new file mode 100644
index 00000000..d198156c
Binary files /dev/null and b/app/frontend/static/assets/images/pack.png differ
diff --git a/app/frontend/static/assets/js/motd.js b/app/frontend/static/assets/js/motd.js
new file mode 100644
index 00000000..e90c5ebf
--- /dev/null
+++ b/app/frontend/static/assets/js/motd.js
@@ -0,0 +1,127 @@
+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('
') > -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, '
');
+ 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);
+ if (input != null && output != null) {
+ var parsed = parseStyle( input.innerHTML );
+ output.innerHTML = '';
+ output.appendChild(parsed);
+ }
+}
diff --git a/app/frontend/templates/blank_base.html b/app/frontend/templates/blank_base.html
index ace4b7dd..f4e8ec65 100644
--- a/app/frontend/templates/blank_base.html
+++ b/app/frontend/templates/blank_base.html
@@ -11,6 +11,8 @@
+
+
@@ -24,7 +26,7 @@