Using Wabsocket for refreshing Status Page

This commit is contained in:
Silversthorn 2022-01-19 21:34:59 +01:00
parent 0412480216
commit 97cad998e8
3 changed files with 264 additions and 93 deletions

View File

@ -1,4 +1,5 @@
from datetime import timedelta from datetime import timedelta
from http import server
import os import os
import sys import sys
import json import json
@ -79,7 +80,7 @@ class TasksManager:
logger.info("Reload from DB called. Current enabled schedules: ") logger.info("Reload from DB called. Current enabled schedules: ")
for item in jobs: for item in jobs:
logger.info("JOB: {}".format(item)) logger.info("JOB: {}".format(item))
def command_watcher(self): def command_watcher(self):
while True: while True:
# select any commands waiting to be processed # select any commands waiting to be processed
@ -270,8 +271,7 @@ class TasksManager:
logger.info("Scheduling Serverjars.com cache refresh service every 12 hours") logger.info("Scheduling Serverjars.com cache refresh service every 12 hours")
self.scheduler.add_job(server_jar_obj.refresh_cache, 'interval', hours=12, id="serverjars") self.scheduler.add_job(server_jar_obj.refresh_cache, 'interval', hours=12, id="serverjars")
@staticmethod def realtime(self):
def realtime():
loop = asyncio.new_event_loop() loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop) asyncio.set_event_loop(loop)
@ -296,7 +296,42 @@ class TasksManager:
'mem_percent': host_stats.get('mem_percent'), 'mem_percent': host_stats.get('mem_percent'),
'mem_usage': host_stats.get('mem_usage') 'mem_usage': host_stats.get('mem_usage')
}) })
time.sleep(4)
servers = self.controller.servers_list
servers_ping = []
for srv in servers:
server_data = srv.get('server_data_obj', False)
if server_data:
server_id = server_data.get('server_id', False)
srv['raw_ping_result'] = self.controller.stats.get_raw_server_stats(server_id)
if ("{}".format(srv['raw_ping_result'].get('icon')) == "b''"):
srv['raw_ping_result']['icon'] = False
servers_ping.append({
'id': srv['raw_ping_result'].get('id'),
'started': srv['raw_ping_result'].get('started'),
'running': srv['raw_ping_result'].get('running'),
'cpu': srv['raw_ping_result'].get('cpu'),
'mem': srv['raw_ping_result'].get('mem'),
'mem_percent': srv['raw_ping_result'].get('mem_percent'),
'world_name': srv['raw_ping_result'].get('world_name'),
'world_size': srv['raw_ping_result'].get('world_size'),
'server_port': srv['raw_ping_result'].get('server_port'),
'int_ping_results': srv['raw_ping_result'].get('int_ping_results'),
'online': srv['raw_ping_result'].get('online'),
'max': srv['raw_ping_result'].get('max'),
'players': srv['raw_ping_result'].get('players'),
'desc': srv['raw_ping_result'].get('desc'),
'version': srv['raw_ping_result'].get('version'),
'icon': srv['raw_ping_result'].get('icon')
})
if (len(servers_ping) > 0) & (len(websocket_helper.clients) > 0):
#TODO websocket_helper.broadcast_page('/panel/dashboard', 'update_server_status', servers)
try:
websocket_helper.broadcast_page('/status', 'update_server_status', servers_ping)
except:
console.warning("Can't broadcast server status to websocket")
time.sleep(5)
def log_watcher(self): def log_watcher(self):
self.controller.servers.check_for_old_logs() self.controller.servers.check_for_old_logs()

View File

@ -1,7 +1,6 @@
{% extends ../public_base.html %} {% extends ../public_base.html %}
{% block meta %} {% block meta %}
<meta http-equiv="refresh" content="30">
{% end %} {% end %}
{% block title %}Crafty Controller - {{ translate('dashboard', 'dashboard', data['lang']) }}{% end %} {% block title %}Crafty Controller - {{ translate('dashboard', 'dashboard', data['lang']) }}{% end %}
@ -24,40 +23,49 @@
<tbody> <tbody>
{% for server in data['servers'] %} {% for server in data['servers'] %}
<tr> <tr>
<td> <td id="server_name_{{ server['stats']['server_id']['server_id'] }}">
<i class="fas fa-server"></i> <i class="fas fa-server"></i>
{{ server['server_data']['server_name'] }} {{ server['server_data']['server_name'] }}
</td> </td>
{% if server['stats']['int_ping_results'] != 'False' %} {% if server['stats']['int_ping_results'] != 'False' %}
<td> <td id="server_players_{{ server['stats']['server_id']['server_id'] }}">
{{ server['stats']['online'] }} / {{ server['stats']['max'] }} {{ translate('dashboard', 'max', data['lang']) }}<br /> {{ server['stats']['online'] }} / {{ server['stats']['max'] }} {{ translate('dashboard', 'max',
</td> data['lang']) }}<br />
<td>
{% if server['stats']['desc'] != 'False' %}
{% 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']['server_id']['server_id'] }}" class="input_motd">{{ server['stats']['desc'] }}</span> <br />
{% end %}
</td>
<td>
{% if server['stats']['version'] != 'False' %}
{{ server['stats']['version'] }}
{% end %}
</td> </td>
<td id="server_motd_{{ server['stats']['server_id']['server_id'] }}">
{% if server['stats']['desc'] != 'False' %}
{% if server['raw_ping_result']['icon'] %}
<img src="data:image/png;base64,{% raw server['raw_ping_result']['icon'] %}" alt="icon" />
{% else %} {% else %}
<td colspan="3"> <img src="/static/assets/images/pack.png" alt="icon" />
<!-- TODO: translate the following text -->
<span class="text-warning"><i class="fas fa-exclamation-triangle"></i> Crafty can't get infos from this Server </span>
</td>
{% end %} {% end %}
<td> <span id="input_motd_{{ server['stats']['server_id']['server_id'] }}" class="input_motd">{{
server['stats']['desc'] }}</span> <br />
{% end %}
</td>
<td id="server_version_{{ server['stats']['server_id']['server_id'] }}">
{% if server['stats']['version'] != 'False' %}
{{ server['stats']['version'] }}
{% end %}
</td>
{% else %}
<td id="server_players_{{ server['stats']['server_id']['server_id'] }}">
<span class="text-warning"><i class="fas fa-exclamation-triangle"></i></span>
</td>
<td id="server_motd_{{ server['stats']['server_id']['server_id'] }}">
<span class="text-warning">Crafty can't get infos from this Server </span>
</td>
<td id="server_version_{{ server['stats']['server_id']['server_id'] }}">
<span class="text-warning"><i class="fas fa-question"></i></i></span>
</td>
{% end %}
<td id="server_online_status_{{ server['stats']['server_id']['server_id'] }}">
{% if server['stats']['running'] %} {% if server['stats']['running'] %}
<span class="text-success"><i class="fas fa-signal"></i> {{ translate('dashboard', 'online', data['lang']) }}</span> <span class="text-success"><i class="fas fa-signal"></i> {{ translate('dashboard', 'online', data['lang'])
}}</span>
{% else %} {% else %}
<span class="text-danger"><i class="fas fa-ban"></i> {{ translate('dashboard', 'offline', data['lang']) }}</span> <span class="text-danger"><i class="fas fa-ban"></i> {{ translate('dashboard', 'offline', data['lang'])
}}</span>
{% end %} {% end %}
</td> </td>
</tr> </tr>
@ -73,14 +81,84 @@
{% block js %} {% block js %}
<script src="/static/assets/js/motd.js"></script> <script src="/static/assets/js/motd.js"></script>
<script> <script>
$(document).ready(function () { function display_motd() {
var all_motds = Array.from(document.getElementsByClassName('input_motd')); var all_motds = Array.from(document.getElementsByClassName('input_motd'));
for (element of all_motds) { for (element of all_motds) {
initParser(element.id, element.id); initParser(element.id, element.id);
}; };
}()); }
</script>
function update_one_server_status(server) {
server_name = document.getElementById('server_name_' + server.id).get;
server_players = document.getElementById('server_players_' + server.id);
server_motd = document.getElementById('server_motd_' + server.id);
server_version = document.getElementById('server_version_' + server.id);
server_online_status = document.getElementById('server_online_status_' + server.id);
server_no_data = document.getElementById('server_players_' + server.id);
console.log("Received Data : " + server.id + ": " + server.world_name);
/* TODO Update each element */
if (server.int_ping_results) {
/* Update Players */
if (server.players)
{
server_players.innerHTML = server.online + ` / ` + server.max + ` {{ translate('dashboard', 'max', data['lang']) }}<br />`
}
/* Update Motd */
var motd = "";
if (server.desc) {
if (server.icon) {
motd = `<img src="data:image/png;base64,` + server.icon + `" alt="icon" /> `;
}
else {
motd = `<img src="/static/assets/images/pack.png" alt="icon" /> `;
}
motd = motd + `<span id="input_motd_` + server.id + `" class="input_motd">` + server.desc + `</span> <br />`;
server_motd.innerHTML = motd;
}
/* Version */
if (server.version)
{
server_version.innerHTML = server.version
}
}
else {
server_players.innerHTML = `<span class="text-warning"><i class="fas fa-exclamation-triangle"></i></span>`;
server_motd.innerHTML = `<span class="text-warning">Crafty can't get infos from this Server </span>`;
server_version.innerHTML = `<span class="text-warning"><i class="fas fa-question"></i></i></span>`
}
/* Update Online Status */
var online_status = "";
if (server.running) {
online_status = `<span class="text-success"><i class="fas fa-signal"></i> {{ translate('dashboard', 'online', data['lang'])}}</span>`;
}
else {
online_status = `<span class="text-danger"><i class="fas fa-ban"></i> {{ translate('dashboard', 'offline', data['lang'])}}</span>`;
}
server_online_status.innerHTML = online_status;
}
function update_servers_status(data) {
console.log(data);
for (server of data) {
update_one_server_status(server);
}
display_motd();
}
$(document).ready(function () {
console.log("ready!");
display_motd()
webSocket.on('update_server_status', update_servers_status);
}());
</script>
{% end %} {% end %}

View File

@ -1,60 +1,118 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<!-- Required meta tags --> <head>
<meta charset="utf-8"> <!-- Required meta tags -->
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta charset="utf-8">
{% block meta %}{% end %} <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{% block title %}{{ _('Default') }}{% end %}</title> {% block meta %}{% end %}
<!-- plugins:css --> <title>{% block title %}{{ _('Default') }}{% end %}</title>
<link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css"> <!-- plugins:css -->
<link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css"> <link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css">
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css"> <link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css">
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css"> <link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css"> <link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
<link rel="stylesheet" href="/static/assets/vendors/fontawesome5/css/all.css"> <link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
<!-- endinject --> <link rel="stylesheet" href="/static/assets/vendors/fontawesome5/css/all.css">
<!-- Plugin css for this page --> <!-- endinject -->
<!-- End Plugin css for this page --> <!-- Plugin css for this page -->
<!-- Layout styles --> <!-- End Plugin css for this page -->
<link rel="stylesheet" href="/static/assets/css/dark/style.css"> <!-- Layout styles -->
<!-- End Layout styles --> <link rel="stylesheet" href="/static/assets/css/dark/style.css">
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg"> <!-- End Layout styles -->
<link rel="alternate icon" href="/static/assets/images/favicon.png" /> <link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg">
</head> <link rel="alternate icon" href="/static/assets/images/favicon.png" />
<body class="dark-theme"> </head>
<div class="container-scroller">
<div class="container-fluid page-body-wrapper full-page-wrapper"> <body class="dark-theme">
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one"> <div class="container-scroller">
<div class="row w-100"> <div class="container-fluid page-body-wrapper full-page-wrapper">
<div class="mx-auto"> <div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
<div class="auto-form-wrapper"> <div class="row w-100">
{% block content %} <div class="mx-auto">
{% end %} <div class="auto-form-wrapper">
</div> {% block content %}
{% end %}
</div> </div>
</div> </div>
</div> </div>
<!-- content-wrapper ends -->
</div> </div>
<!-- page-body-wrapper ends --> <!-- content-wrapper ends -->
</div> </div>
<!-- container-scroller --> <!-- page-body-wrapper ends -->
<!-- plugins:js --> </div>
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script> <!-- container-scroller -->
<!-- endinject --> <!-- plugins:js -->
<!-- inject:js --> <script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
<script src="/static/assets/js/shared/off-canvas.js"></script> <!-- endinject -->
<script src="/static/assets/js/shared/hoverable-collapse.js"></script> <!-- inject:js -->
<script src="/static/assets/js/shared/misc.js"></script> <script src="/static/assets/js/shared/off-canvas.js"></script>
<script src="/static/assets/js/shared/settings.js"></script> <script src="/static/assets/js/shared/hoverable-collapse.js"></script>
<script src="/static/assets/js/shared/todolist.js"></script> <script src="/static/assets/js/shared/misc.js"></script>
<!-- endinject --> <script src="/static/assets/js/shared/settings.js"></script>
<script src="/static/assets/js/shared/todolist.js"></script>
{% block js %} <!-- endinject -->
<!-- Custom js for this page --> <script>
<!-- End custom js for this page -->
{% end %} // {% if request.protocol == 'https' %}
let usingWebSockets = true;
</body>
let listenEvents = [];
try {
pageQueryParams = 'page_query_params=' + encodeURIComponent(location.search)
page = 'page=' + encodeURIComponent(location.pathname)
var wsInternal = new WebSocket('wss://' + location.host + '/ws?' + page + '&' + pageQueryParams);
wsInternal.onopen = function () {
console.log('opened WebSocket connection:', wsInternal)
};
wsInternal.onmessage = function (rawMessage) {
var message = JSON.parse(rawMessage.data);
console.log('got message: ', message)
listenEvents
.filter(listenedEvent => listenedEvent.event == message.event)
.forEach(listenedEvent => listenedEvent.callback(message.data))
};
wsInternal.onerror = function (errorEvent) {
console.error('WebSocket Error', errorEvent);
};
wsInternal.onclose = function (closeEvent) {
console.log('Closed WebSocket', closeEvent);
};
webSocket = {
on: function (event, callback) {
console.log('registered ' + event + ' event');
listenEvents.push({ event: event, callback: callback })
},
emit: function (event, data) {
var message = {
event: event,
data: data
}
wsInternal.send(JSON.stringify(message));
}
}
} catch (error) {
console.error('Error while making websocket helpers', error);
usingWebSockets = false;
}
// {% else %}
let usingWebSockets = false;
warn('WebSockets are not supported in Crafty if not using the https protocol')
var webSocket;
// {% end%}
</script>
{% block js %}
<!-- Custom js for this page -->
<!-- End custom js for this page -->
{% end %}
</body>
</html> </html>