From c81ce67f92efa22212cce1339635cd9ab1a9f28c Mon Sep 17 00:00:00 2001 From: iou1name Date: Sun, 1 Sep 2019 16:48:45 -0400 Subject: [PATCH] convert ajax calls to websocket --- aberrant.py | 33 ++++++++++++++++++++++-- events.py | 18 +++++++++++++ static/aberrant.css | 16 ++++++++---- static/aberrant.js | 61 +++++++++++++++++++++++++++++++++++++++----- templates/index.html | 40 +++++++++++++++++++---------- 5 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 events.py diff --git a/aberrant.py b/aberrant.py index 3b24bcd..76ee8f4 100644 --- a/aberrant.py +++ b/aberrant.py @@ -2,12 +2,15 @@ """ The primary module for serving the Aberrant application. """ +import json + import jinja2 import aiohttp_jinja2 from aiohttp import web, WSMsgType from aiohttp_jinja2 import render_template import config +import events import rtorrent app = web.Application() @@ -18,18 +21,44 @@ rtorrent.init() routes = web.RouteTableDef() @routes.get(config.prefix + "/", name='index') -def index(request): +async def index(request): """The index page.""" torrents = rtorrent.get_active() tracker_stats = rtorrent.get_stats() return render_template("index.html", request, locals()) @routes.get(config.prefix + "/get_active_torrents", name='active-torrents') -def get_active_torrents(request): +async def get_active_torrents(request): """Returns all active torrents formatted as JSON.""" data = [vars(t) for t in rtorrent.get_active()] return web.json_response(data) +@routes.get(config.prefix + '/ws', name='ws') +async def websocket_handler(request): + """The websocket endpoint.""" + ws = web.WebSocketResponse() + ws_ready = ws.can_prepare(request) + if not ws_ready.ok: + return web.Response(text="Cannot start websocket.") + await ws.prepare(request) + + async for msg in ws: + if msg.type == WSMsgType.TEXT: + try: + data = json.loads(msg.data) + except json.JSONDecodeError: + continue + + event = data.get('event') + if not event or event not in events.events.keys(): + continue + + await events.events[event](ws, data.get('data')) + else: # TODO: handle differnt message types properly + break + await ws.close() + return ws + app.router.add_routes(routes) if __name__ == "__main__": diff --git a/events.py b/events.py new file mode 100644 index 0000000..e706ea5 --- /dev/null +++ b/events.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +""" +WebSocket events. +""" +import types + +import rtorrent + +async def active_torrents(ws, data): + """Returns active torrent information.""" + data = [vars(t) for t in rtorrent.get_active()] + res = {'event': 'active_torrents', 'data': data} + await ws.send_json(res) + +events = {} +for obj in dir(): + if type(locals()[obj]) == types.FunctionType: + events[locals()[obj].__name__] = locals()[obj] diff --git a/static/aberrant.css b/static/aberrant.css index c8b7b44..0a1be4c 100644 --- a/static/aberrant.css +++ b/static/aberrant.css @@ -14,15 +14,21 @@ tr { border: 1px solid #ccc; } -.name { - padding-left: 0.5em; -} - -.totalSize, .state, .downrate, .downPercent, .eta, .uprate, .tracker, .rt_id { +#torrents td { text-align: center; width: 10%; } +#torrents .name { + padding-left: 0.5em; + text-align: left; + width: 0; +} + +#torrents .down_percent:after { + content: "%"; +} + #tracker_stats { border-collapse: collapse; border: 1px solid #ccc; diff --git a/static/aberrant.js b/static/aberrant.js index ac229f0..f9d0a0e 100644 --- a/static/aberrant.js +++ b/static/aberrant.js @@ -1,8 +1,9 @@ function load() { + //let intervalID = window.setInterval(get_active_torrents_ajax, 20000); let intervalID = window.setInterval(get_active_torrents, 20000); } -function get_active_torrents() { +function get_active_torrents_ajax() { let httpRequest; httpRequest = new XMLHttpRequest(); httpRequest.onreadystatechange = function() { @@ -13,14 +14,14 @@ function get_active_torrents() { for (let i = 0; i < torrents.length; i++) { html_str += '' html_str += '' + torrents[i].name + ''; - html_str += '' + torrents[i].total_size_str + ''; + html_str += '' + torrents[i].total_size_str + ''; html_str += '' + torrents[i].state + ''; - html_str += '' + torrents[i].downrate_str + ''; - html_str += '' + torrents[i].down_percent + '%'; - html_str += '' + torrents[i].eta_str + ''; - html_str += '' + torrents[i].uprate_str + ''; + html_str += '' + torrents[i].downrate_str + ''; + html_str += '' + torrents[i].down_percent + '%'; + html_str += '' + torrents[i].eta_str + ''; + html_str += '' + torrents[i].uprate_str + ''; html_str += '' + torrents[i].tracker + ''; - html_str += '' + torrents[i].rtorrent_id + ''; + html_str += '' + torrents[i].rtorrent_id + ''; html_str += ''; } document.getElementById('torrents').children[1].innerHTML = html_str; @@ -28,3 +29,49 @@ function get_active_torrents() { httpRequest.open('GET', get_torrents_uri, true); httpRequest.send(); } + +var socket = new WebSocket('wss://' + window.location.hostname + ws_uri); +socket.oldSend = socket.send; +socket.send = function(event_title, data) { + data = JSON.stringify({event: event_title, data: data}); + socket.oldSend.apply(this, [data]); +} +socket.events = {}; +socket.onmessage = function(e) { + let data = JSON.parse(e.data); + let event = data.event; + data = data.data; + if (socket.events[event] === undefined) { return; } + socket.events[event](data); +} +socket.onclose = function(e) { + console.log('WebSocket lost connection to server. Re-trying...'); + // TODO: reconnect +} + +/* Websocket receive */ +socket.events['active_torrents'] = function(data) { + let table = document.querySelector('#torrents tbody'); + while (table.firstChild) { + table.removeChild(table.firstChild); + } + data.forEach(function(torrent) { + let template = document.querySelector('#torrent_template'); + let node = document.importNode(template.content, true); + for (let field of node.children[0].children) { + field.textContent = torrent[field.className]; + } + table.appendChild(node); + }); +} +socket.events['tracker_stats'] = function(data) { + console.log(data); +} + +/* Websocket send */ +function get_active_torrents() { + socket.send('active_torrents', {}); +} +function get_tracker_stats() { + socket.send('tracker_stats', {}); +} diff --git a/templates/index.html b/templates/index.html index c30a94c..2194608 100644 --- a/templates/index.html +++ b/templates/index.html @@ -3,10 +3,11 @@ Aberrant - + @@ -14,32 +15,45 @@ Name - Size + Size State - DL - % - ETA - UL + DL + + ETA + UL Tracker - RT id + RT id {% for torrent in torrents %} {{ torrent.name }} - {{ torrent.total_size_str }} + {{ torrent.total_size_str }} {{ torrent.state }} - {{ torrent.downrate_str }} - {{ torrent.down_percent }}% - {{ torrent.eta_str }} - {{ torrent.uprate_str }} + {{ torrent.downrate_str }} + {{ torrent.down_percent }} + {{ torrent.eta_str }} + {{ torrent.uprate_str }} {{ torrent.tracker }} - {{ torrent.rtorrent_id }} + {{ torrent.rtorrent_id }} {% endfor %} +