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 http import server
import os
import sys
import json
@ -79,7 +80,7 @@ class TasksManager:
logger.info("Reload from DB called. Current enabled schedules: ")
for item in jobs:
logger.info("JOB: {}".format(item))
def command_watcher(self):
while True:
# select any commands waiting to be processed
@ -270,8 +271,7 @@ class TasksManager:
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")
@staticmethod
def realtime():
def realtime(self):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
@ -296,7 +296,42 @@ class TasksManager:
'mem_percent': host_stats.get('mem_percent'),
'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):
self.controller.servers.check_for_old_logs()

View File

@ -1,7 +1,6 @@
{% extends ../public_base.html %}
{% block meta %}
<meta http-equiv="refresh" content="30">
{% end %}
{% block title %}Crafty Controller - {{ translate('dashboard', 'dashboard', data['lang']) }}{% end %}
@ -24,40 +23,49 @@
<tbody>
{% for server in data['servers'] %}
<tr>
<td>
<td id="server_name_{{ server['stats']['server_id']['server_id'] }}">
<i class="fas fa-server"></i>
{{ server['server_data']['server_name'] }}
{{ server['server_data']['server_name'] }}
</td>
{% if server['stats']['int_ping_results'] != 'False' %}
<td>
{{ server['stats']['online'] }} / {{ server['stats']['max'] }} {{ translate('dashboard', 'max', data['lang']) }}<br />
</td>
<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 %}
{% if server['stats']['int_ping_results'] != 'False' %}
<td id="server_players_{{ server['stats']['server_id']['server_id'] }}">
{{ server['stats']['online'] }} / {{ server['stats']['max'] }} {{ translate('dashboard', 'max',
data['lang']) }}<br />
</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 %}
<td colspan="3">
<!-- 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>
<img src="/static/assets/images/pack.png" alt="icon" />
{% 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'] %}
<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 %}
<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 %}
</td>
</tr>
@ -73,14 +81,84 @@
{% block js %}
<script src="/static/assets/js/motd.js"></script>
<script>
$(document).ready(function () {
var all_motds = Array.from(document.getElementsByClassName('input_motd'));
for (element of all_motds) {
initParser(element.id, element.id);
};
}());
</script>
<script src="/static/assets/js/motd.js"></script>
<script>
function display_motd() {
var all_motds = Array.from(document.getElementsByClassName('input_motd'));
for (element of all_motds) {
initParser(element.id, element.id);
};
}
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 %}

View File

@ -1,60 +1,118 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
{% block meta %}{% end %}
<title>{% block title %}{{ _('Default') }}{% end %}</title>
<!-- plugins:css -->
<link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css">
<link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css">
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
<link rel="stylesheet" href="/static/assets/vendors/fontawesome5/css/all.css">
<!-- endinject -->
<!-- Plugin css for this page -->
<!-- End Plugin css for this page -->
<!-- Layout styles -->
<link rel="stylesheet" href="/static/assets/css/dark/style.css">
<!-- End Layout styles -->
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg">
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
</head>
<body class="dark-theme">
<div class="container-scroller">
<div class="container-fluid page-body-wrapper full-page-wrapper">
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
<div class="row w-100">
<div class="mx-auto">
<div class="auto-form-wrapper">
{% block content %}
{% end %}
</div>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
{% block meta %}{% end %}
<title>{% block title %}{{ _('Default') }}{% end %}</title>
<!-- plugins:css -->
<link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css">
<link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css">
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
<link rel="stylesheet" href="/static/assets/vendors/fontawesome5/css/all.css">
<!-- endinject -->
<!-- Plugin css for this page -->
<!-- End Plugin css for this page -->
<!-- Layout styles -->
<link rel="stylesheet" href="/static/assets/css/dark/style.css">
<!-- End Layout styles -->
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg">
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
</head>
<body class="dark-theme">
<div class="container-scroller">
<div class="container-fluid page-body-wrapper full-page-wrapper">
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
<div class="row w-100">
<div class="mx-auto">
<div class="auto-form-wrapper">
{% block content %}
{% end %}
</div>
</div>
</div>
<!-- content-wrapper ends -->
</div>
<!-- page-body-wrapper ends -->
<!-- content-wrapper ends -->
</div>
<!-- container-scroller -->
<!-- plugins:js -->
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
<!-- endinject -->
<!-- inject:js -->
<script src="/static/assets/js/shared/off-canvas.js"></script>
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
<script src="/static/assets/js/shared/misc.js"></script>
<script src="/static/assets/js/shared/settings.js"></script>
<script src="/static/assets/js/shared/todolist.js"></script>
<!-- endinject -->
{% block js %}
<!-- Custom js for this page -->
<!-- End custom js for this page -->
{% end %}
</body>
<!-- page-body-wrapper ends -->
</div>
<!-- container-scroller -->
<!-- plugins:js -->
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
<!-- endinject -->
<!-- inject:js -->
<script src="/static/assets/js/shared/off-canvas.js"></script>
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
<script src="/static/assets/js/shared/misc.js"></script>
<script src="/static/assets/js/shared/settings.js"></script>
<script src="/static/assets/js/shared/todolist.js"></script>
<!-- endinject -->
<script>
// {% if request.protocol == 'https' %}
let usingWebSockets = true;
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>