Websockets.. Work in progress!

websocket.html is just a blank page with the newest javascript helpers
threading working wonderfully! Except my own code.
websocket.html and thte bit from panel_handler.py can be deleted once this is done. It was just because the css and js kept loading for super long
This commit is contained in:
LukasDoesDev 2020-12-17 15:39:29 +02:00
parent 31b311980c
commit 8cd2d59230
6 changed files with 216 additions and 2 deletions

View File

@ -8,6 +8,7 @@ import threading
from app.classes.shared.helpers import helper from app.classes.shared.helpers import helper
from app.classes.shared.console import console from app.classes.shared.console import console
from app.classes.web.tornado import webserver from app.classes.web.tornado import webserver
from app.classes.web.websocket_handler import WebSocketHandler
from app.classes.minecraft.stats import stats from app.classes.minecraft.stats import stats
from app.classes.shared.controller import controller from app.classes.shared.controller import controller
@ -24,6 +25,7 @@ except ModuleNotFoundError as e:
console.critical("Import Error: Unable to load {} module".format(e, e.name)) console.critical("Import Error: Unable to load {} module".format(e, e.name))
sys.exit(1) sys.exit(1)
class TasksManager: class TasksManager:
def __init__(self): def __init__(self):
@ -38,6 +40,9 @@ class TasksManager:
self.command_thread = threading.Thread(target=self.command_watcher, daemon=True, name="command_watcher") self.command_thread = threading.Thread(target=self.command_watcher, daemon=True, name="command_watcher")
self.command_thread.start() self.command_thread.start()
self.realtime_thread = threading.Thread(target=self.realtime_thread, daemon=True, name="realtime")
self.realtime_thread.start()
def get_main_thread_run_status(self): def get_main_thread_run_status(self):
return self.main_thread_exiting return self.main_thread_exiting
@ -72,10 +77,8 @@ class TasksManager:
db_helper.mark_command_complete(c.get('command_id', None)) db_helper.mark_command_complete(c.get('command_id', None))
time.sleep(1) time.sleep(1)
def _main_graceful_exit(self): def _main_graceful_exit(self):
try: try:
os.remove(helper.session_file) os.remove(helper.session_file)
@ -133,5 +136,33 @@ class TasksManager:
logger.info("Scheduling Serverjars.com cache refresh service every 12 hours") logger.info("Scheduling Serverjars.com cache refresh service every 12 hours")
schedule.every(12).hours.do(server_jar_obj.refresh_cache) schedule.every(12).hours.do(server_jar_obj.refresh_cache)
@staticmethod
def realtime_thread():
console.debug('realtime zero')
while True:
if len(WebSocketHandler.connections) > 0:
print(WebSocketHandler)
WebSocketHandler.broadcast(WebSocketHandler, 'sample_data', {
'foo': 'bar',
'baz': 'Hello, World!'
})
if WebSocketHandler.host_stats.get('cpu_usage') != \
db_helper.get_latest_hosts_stats().get('cpu_usage') or \
WebSocketHandler.host_stats.get('mem_percent') != \
db_helper.get_latest_hosts_stats().get('mem_percent'):
console.debug('realtime one')
WebSocketHandler.host_stats = db_helper.get_latest_hosts_stats()
if len(WebSocketHandler.connections) > 0:
WebSocketHandler.broadcast(WebSocketHandler, 'update_host_stats', {
'cpu': WebSocketHandler.host_stats.get('cpu_usage'),
'mem': WebSocketHandler.host_stats.get('mem_percent')
})
time.sleep(4)
else:
console.debug('realtime two')
time.sleep(2)
tasks_manager = TasksManager() tasks_manager = TasksManager()

View File

@ -65,6 +65,9 @@ class PanelHandler(BaseHandler):
elif page == 'files_menu': elif page == 'files_menu':
template = "panel/files_menu.html" template = "panel/files_menu.html"
elif page == 'websocket':
template = "panel/websocket.html"
elif page == "remove_server": elif page == "remove_server":
server_id = self.get_argument('id', None) server_id = self.get_argument('id', None)
server_data = controller.get_server_data(server_id) server_data = controller.get_server_data(server_id)

View File

@ -24,6 +24,7 @@ try:
from app.classes.web.server_handler import ServerHandler from app.classes.web.server_handler import ServerHandler
from app.classes.web.ajax_handler import AjaxHandler from app.classes.web.ajax_handler import AjaxHandler
from app.classes.web.api_handler import ServersStats, NodeStats from app.classes.web.api_handler import ServersStats, NodeStats
from app.classes.web.websocket_handler import WebSocketHandler
except ModuleNotFoundError as e: except ModuleNotFoundError as e:
logger.critical("Import Error: Unable to load {} module".format(e, e.name)) logger.critical("Import Error: Unable to load {} module".format(e, e.name))
@ -125,6 +126,7 @@ class webserver:
(r'/ajax/(.*)', AjaxHandler), (r'/ajax/(.*)', AjaxHandler),
(r'/api/stats/servers', ServersStats), (r'/api/stats/servers', ServersStats),
(r'/api/stats/node', NodeStats), (r'/api/stats/node', NodeStats),
(r'/ws', WebSocketHandler),
] ]
app = tornado.web.Application( app = tornado.web.Application(

View File

@ -0,0 +1,37 @@
import json
import tornado.websocket
from app.classes.shared.console import console
from app.classes.shared.models import db_helper
class WebSocketHandler(tornado.websocket.WebSocketHandler):
connections = set()
host_stats = db_helper.get_latest_hosts_stats()
def open(self):
self.connections.add(self)
console.debug('Opened WebSocket connection')
self.broadcast('client_joined', {
'foo': 'bar',
})
def on_message(self, message):
# broadcast
# for client in self.connections:
# client.write_message(message)
# send message to client this message was sent by
# self.write_message
console.debug('Got message from WebSocket connection {}'.format(message))
def on_close(self):
self.connections.remove(self)
console.debug('Closed WebSocket connection')
def broadcast(self, message_type: str, data):
print(str(json.dumps({'type': message_type, 'data': data})))
message = str(json.dumps({'type': message_type, 'data': data}))
for client in self.connections:
client.write_message(message)

View File

@ -58,6 +58,8 @@
<div class="main-panel"> <div class="main-panel">
<div class="warnings"></div>
{% block content %} {% block content %}
{% end %} {% end %}
@ -103,6 +105,82 @@
}); });
}); });
}); });
{% if request.protocol == 'https'%}
let usingWebSockets = true;
let socketTypes = [];
try {
var wsInternal = new WebSocket('wss://' + location.host + '/ws');
wsInternal.onopen = function() {
console.log('opened WebSocket connection:', wsInternal)
};
wsInternal.onmessage = function (event) {
var message = JSON.parse(event.data);
console.log('got message: ', message)
socketTypes
.filter(event => event.type == message.type)
.forEach(event => event.callback(message.data))
}
webSocket = {
on: function (type, callback) {
socketTypes.push({ type: type, callback: callback })
},
emit: function (type, data) {
var message = {
type: type,
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')
{% end%}
function warn(message) {
var closeEl = document.createElement('span');
var strongEL = document.createElement('strong');
var msgEl = document.createElement('div');
closeEl.innerHTML = '&times;';
strongEL.textContent = 'Warning: ';
msgEl.append(strongEL, message);
closeEl.style.marginLeft = '15px';
closeEl.style.fontWeight = 'bold';
closeEl.style.float = 'right';
closeEl.style.fontSize = '22px';
closeEl.style.lineHeight = '20px';
closeEl.style.cursor = 'pointer';
closeEl.style.transition = '.3s';
closeEl.addEventListener('click', function () {this.parentElement.style.display='none';});
var parentEl = document.createElement('div');
parentEl.style.padding = '20px';
parentEl.style.backgroundColor = '#f7970f';
parentEl.appendChild(closeEl);
parentEl.appendChild(msgEl);
document.querySelector('.warnings').appendChild(parentEl);
}
</script> </script>
{% block js %} {% block js %}

View File

@ -0,0 +1,63 @@
<!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">
<title>Default</title>
</head>
<body class="dark-theme">
<script>
{% if request.protocol == 'https'%}
let usingWebSockets = true;
try {
function WebSocketManager (url) {
this.ws = new WebSocket(url);
this.ws.eventListeners = [];
this.ws.onopen = function() {
console.log('opened WebSocket connection:', this.ws)
};
this.ws.onmessage = function (event) {
var message = JSON.parse(event.data);
console.log('got message: ', message)
console.log(this)
this.eventListeners
.filter(event => event.type == message.type)
.forEach(event => event.callback(message.data))
}
this.on = function (type, callback) {
this.ws.eventListeners.push({ type: type, callback: callback })
}
this.emit = function (type, data) {
var message = {
type: type,
data: data
}
this.ws.send(JSON.stringify(message));
}
}
webSocket = new WebSocketManager('wss://' + location.host + '/ws');
} catch (error) {
console.error('Error while making websocket helpers', error);
usingWebSockets = false;
}
{% else %}
let usingWebSockets = false;
console.warn('WebSockets are not supported in Crafty if not using the https protocol')
{% end%}
</script>
</body>
</html>