From fc2aa37f93133bb415180f8b89213318849ce00f Mon Sep 17 00:00:00 2001 From: iou1name Date: Fri, 15 Nov 2019 12:21:35 -0500 Subject: [PATCH] finish converting AJAX to Websocket --- events.py | 99 ++++++++++++------ static/juice.js | 268 +++++++++++++++++++++--------------------------- 2 files changed, 185 insertions(+), 182 deletions(-) diff --git a/events.py b/events.py index a221529..2e2c7ab 100644 --- a/events.py +++ b/events.py @@ -1,75 +1,94 @@ #!/usr/bin/env python3 """Websocket events.""" +import re import types import models from models import network - async def toggle_outlet(ws, data): """Toggles the state of a RelayDevice.""" device_id = data.get('device_id') sub_device_id = data.get('sub_device_id') + data = {} + data['device_id'] = device_id + data['sub_device_id'] = sub_device_id + device = network.find(device_id) if not device: - await ws.send_json({'ok': False, 'message': "device_id not found"}) + data['ok'] = False + data['error'] = "device_id not found" + await ws.send_json(data) return state = device.toggle(sub_device_id) if state is None: - await ws.send_json({'ok': False, 'message': "sub_device_id not found"}) + data['ok'] = False + data['error'] = "sub_device_id not found" + await ws.send_json(data) return models.save_network(network) - data = {} data['ok'] = True - data['device_id'] = device_id - data['sub_device_id'] = sub_device_id data['state'] = state res = {'event': 'toggle_outlet', 'data': data} await ws.send_json(res) -async def edit(ws, data): +async def edit_field(ws, data): """Edits the text of a particular field.""" device_id = data.get('device_id') sub_device_id = data.get('sub_device_id') field = data.get('field') value = data.get('value') + data = {} + data['device_id'] = device_id + if sub_device_id: + data['sub_device_id'] = sub_device_id + data['field'] = field + data['value'] = value + device = network.find(device_id) if not device: - await ws.send_json({'ok': False, 'message': "device_id not found"}) + data['ok'] = False + data['error'] = "device_id not found" + await ws.send_json(data) return if device.locked: - await ws.send_json({'ok': False, 'message': "device is locked for editing"}) + data['ok'] = False + data['error'] = "device is locked for editing" + await ws.send_json(data) return if sub_device_id: sub_device = device.find(sub_device_id) if not sub_device: - await ws.send_json({'ok': False, 'message': "sub_device_id not found"}) + data['ok'] = False + data['error'] = "sub_device_id not found" + await ws.send_json(data) return if hasattr(sub_device, field): setattr(sub_device, field, value) else: - await ws.send_json({'ok': False, 'message': "sub_device field not found"}) + data['ok'] = False + data['error'] = "sub_device field not found" + await ws.send_json(data) return else: if hasattr(device, field): setattr(device, field, value) else: - await ws.send_json({'ok': False, 'message': "device field not found"}) + data['ok'] = False + data['error'] = "device field not found" + await ws.send_json(data) return - - res = { - 'ok': True, - 'field': field, - 'value': value - } models.save_network(network) + + data['ok'] = True + res = {'event': 'edit_field', 'data': data} await ws.send_json(res) @@ -80,10 +99,15 @@ async def new_device(ws, data): """ device_type = data.get('device_type') + data = {} + data['device_type'] = device_type + if device_type == 'RelayDevice': device = models.RelayDevice() else: - await ws.send_json({'ok': False, 'message': "unknown device type"}) + data['ok'] = False + data['error'] = "unknown device type" + await ws.send_json(data) return devices = [dev for dev in network if dev.type == device_type] @@ -99,42 +123,57 @@ async def new_device(ws, data): device.id = device_type + num network.append(device) models.save_network(network) - res = {'ok': True, 'device_id': device.id} + + data['ok'] = True + data['device_id'] = device.id + res = {'event': 'new_device', 'data': data} await ws.send_json(res) async def lock_device(ws, data): """Locks or unlocks a device to prevent or allow editing it's fields.""" device_id = data.get('device_id') - locked = data.get('locked') == 'true' + locked = bool(data.get('locked')) + + data = {} + data['device_id'] = device_id + data['locked'] = locked device = network.find(device_id) if not device: - await ws.send_json({'ok': False, 'message': "device_id not found"}) + data['ok'] = False + data['error'] = "device_id not found" + await ws.send_json(data) return - if locked: - device.locked = True - else: - device.locked = False + device.locked = locked models.save_network(network) - await ws.send_json({'ok': True, 'device_id': device.id, 'locked': device.locked}) + data['ok'] = True + res = {'event': 'lock_device', 'data': data} + await ws.send_json(res) -async def delete(ws, data): +async def delete_device(ws, data): """Deletes a device.""" device_id = data.get('device_id') + data = {} + data['device_id'] = device_id + device = network.find(device_id) if not device: - await ws.send_json({'ok': False, 'message': "device_id not found"}) + data['ok'] = False + data['error'] = "device_id not found" + await ws.send_json(data) return network.remove(device) models.save_network(network) - await ws.send_json({'ok': True}) + data['ok'] = True + res = {'event': 'delete_device', 'data': data} + await ws.send_json(res) events = {} diff --git a/static/juice.js b/static/juice.js index ef37310..9bcb6cc 100644 --- a/static/juice.js +++ b/static/juice.js @@ -24,12 +24,13 @@ function load() { /* Websocket setup */ function init_websocket() { - let socket = new Websocket('wss://' + window.location.hostname + ws_uri); + let socket = new WebSocket('wss://' + window.location.hostname + ws_uri); socket._send = socket.send; socket.send = function(event_title, data) { data = JSON.stringify({event: event_title, data: data}); if (socket.readyState == 0) { console.log("Socket is still opening!"); + return; } socket._send(data); } @@ -38,6 +39,10 @@ function init_websocket() { socket.onerror = onerror; socket.events = {}; socket.events['toggle_outlet'] = toggle_outlet_recv; + socket.events['edit_field'] = edit_field_recv; + socket.events['new_device'] = new_device_recv; + socket.events['lock_device'] = lock_device_recv; + socket.events['delete_device'] = delete_device_recv; return socket; } @@ -45,7 +50,13 @@ function onmessage (e) { let data = JSON.parse(e.data); let event = data.event; data = data.data; - if (socket.events[event] === undefined) { return; } + if (!data.ok) { + throw new Error("Socket error: event = " + event +", error = " + data.error); + } + if (socket.events[event] === undefined) { + console.log("Unknown socket event: " + event); + return; + } socket.events[event](data); } @@ -63,12 +74,8 @@ function onerror(e) { /* Websocket receive */ function toggle_outlet_recv(data) { - if (!data.ok) { - throw new Error('Socket Event Error: toggle_outlet, message = ' + data.message); - return; - } let device = document.querySelector('#' + data.device_id); - let sub_device = document.querySelector('.' + data.sub_device_id); + let sub_device = device.querySelector('.' + data.sub_device_id); let svg = sub_device.querySelector('.outlet_image').getSVGDocument().firstChild; if (data.state === true) { svg.classList.remove('off'); @@ -79,109 +86,43 @@ function toggle_outlet_recv(data) { } } -/* Websocket send */ -function toggle_outlet(svg) { - let sub_dev = get_object_from_svg(svg).parentElement; - let data = { - device_id: sub_dev.parentElement.parentElement.id, - sub_device_id: sub_dev.querySelector('.id').innerText, - }; - socket.send('toggle_outlet', data); -} - -/* AJAX */ -function edit_field(field) { - let value = field.firstElementChild.innerText; - let input = document.createElement('input'); - input.value = value; - field.firstElementChild.replaceWith(input); - - let save = document.createElement('span'); - save.innerHTML = ''; - save.className = 'save font-awesome'; - save.setAttribute('onclick', 'save_field(this.parentElement)'); - field.children[1].replaceWith(save); -} - -function save_field(field) { - let value = field.firstElementChild.value; - let device_id = field.parentElement.id; - let sub_dev_id; - if (field.parentElement.className.includes('sub_device')) { - sub_dev_id = field.parentElement.children[0].textContent; - device_id = field.parentElement.parentElement.parentElement.id; - } else { - sub_dev_id = ''; +function edit_field_recv(data) { + let device = document.querySelector('#' + data.device_id); + if (data.sub_device_id) { + device = device.querySelector('.' + data.sub_device_id); } - let params = { - device_id: device_id, - sub_dev_id: sub_dev_id, - field: field.classList[0], - value: value - }; - let query = Object.keys(params) - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) - .join('&'); + let field = device.querySelector('.' + data.field); - fetch(window.location.href + 'edit?' + query) - .then(function(response) { - return response.json(); - }) - .then(function(json) { - if (!json.ok) { throw new Error('HTTP error, status = ' + json.status + ', message = ' + json.message); } - let span = document.createElement('span'); - span.innerText = json['value']; - span.className = 'field_value'; - field.firstElementChild.replaceWith(span); + let span = document.createElement('span'); + span.innerText = data['value']; + span.className = 'field_value'; + field.firstElementChild.replaceWith(span); - let edit = document.createElement('span'); - edit.innerHTML = ''; - edit.className = 'edit font-awesome'; - edit.setAttribute('onclick', 'edit_field(this.parentElement)'); - field.children[1].replaceWith(edit); - }); + let edit = document.createElement('span'); + edit.innerHTML = ''; + edit.className = 'edit font-awesome'; + edit.setAttribute('onclick', 'edit_field(this.parentElement)'); + field.children[1].replaceWith(edit); } -function new_device() { - let params = { - device_type: 'RelayDevice', - }; - let query = Object.keys(params) - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) - .join('&'); - - fetch(window.location.href + 'new_device?' + query) - .then(function(response) { - return response.json(); - }) - .then(function(json) { - let template = document.querySelector('#RelayDevice_template'); - let node = document.importNode(template.content, true); - node.querySelector('.id').querySelector('.field_value').textContent = json.device_id; - document.querySelector('#devices').appendChild(node); - let children = document.querySelector('#devices').children; - children[children.length - 1].id = json.device_id; - }); +function new_device_recv(data) { + if (data.device_type == 'RelayDevice') { + var template = document.querySelector('#RelayDevice_template'); + } else { + return; + } + let node = document.importNode(template.content, true); + node.querySelector('.id').querySelector('.field_value').textContent = data.device_id; + document.querySelector('#devices').appendChild(node); + let children = document.querySelector('#devices').children; + children[children.length - 1].id = data.device_id; } -function lock_device(device) { - if (device.querySelector('.save')) { return; } - let params = { - device_id: device.id, - locked: true, - }; - let query = Object.keys(params) - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) - .join('&'); +function lock_device_recv(data) { + let device = document.querySelector('#' + data.device_id); + let fields = device.querySelectorAll('.editable'); - fetch(window.location.href + 'lock_device?' + query) - .then(function(response) { - return response.json(); - }) - .then(function(json) { - if (!json.locked) { return; } - - let fields = device.querySelectorAll('.editable'); + if (data.locked) { fields.forEach(function(field) { field.querySelector('.edit').remove(); }); @@ -192,26 +133,7 @@ function lock_device(device) { unlock.className = 'unlock font-awesome'; unlock.setAttribute('onclick', 'unlock_device(this.parentElement.parentElement)'); device.querySelector('.id').appendChild(unlock); - }); -} - -function unlock_device(device) { - let params = { - device_id: device.id, - locked: false, - }; - let query = Object.keys(params) - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) - .join('&'); - - fetch(window.location.href + 'lock_device?' + query) - .then(function(response) { - return response.json(); - }) - .then(function(json) { - if (json.locked) { return; } - - let fields = device.querySelectorAll('.editable'); + } else { fields.forEach(function(field) { let edit = document.createElement('span'); edit.innerHTML = ''; @@ -232,45 +154,87 @@ function unlock_device(device) { lock.className = 'lock font-awesome'; lock.setAttribute('onclick', 'lock_device(this.parentElement.parentElement)'); device.querySelector('.id').appendChild(lock); - }); + } +} + +function delete_device_recv(data) { + let device = document.querySelector('#' + data.device_id); + device.remove() +} + +/* Websocket send */ +function toggle_outlet(svg) { + let sub_dev = get_object_from_svg(svg).parentElement; + let data = { + device_id: sub_dev.parentElement.parentElement.id, + sub_device_id: sub_dev.querySelector('.id').innerText, + }; + socket.send('toggle_outlet', data); +} + +function save_field(field) { + let value = field.firstElementChild.value; + let device_id = field.parentElement.id; + let sub_dev_id; + if (field.parentElement.className.includes('sub_device')) { + sub_device_id = field.parentElement.children[0].textContent; + device_id = field.parentElement.parentElement.parentElement.id; + } else { + sub_device_id = ''; + } + let data = { + device_id: device_id, + sub_dev_id: sub_dev_id, + field: field.classList[0], + value: value + }; + socket.send('edit_field', data); +} + +function new_device() { + let data = { + device_type: 'RelayDevice', + }; + socket.send('new_device', data); +} + +function lock_device(device) { + if (device.querySelector('.save')) { return; } + let data = { + device_id: device.id, + locked: true, + }; + socket.send('lock_device', data); +} + +function unlock_device(device) { + let data = { + device_id: device.id, + locked: false, + }; + socket.send('lock_device', data); } function delete_device(device) { if (!window.confirm("Are you sure you want to delete this device?")) { return; } - let params = { + let data = { device_id: device.id, }; - let query = Object.keys(params) - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) - .join('&'); - - fetch(window.location.href + 'delete?' + query) - .then(function(response) { - return response.json(); - }) - .then(function(json) { - if (!json) { return; } - device.remove() - }); + socket.send('delete_device', data); } -function delete_token(token_id) { - if (!window.confirm("Are you sure you want to delete this token?")) { return; } - let params = { - token_id: token_id, - }; - let query = Object.keys(params) - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) - .join('&'); +/* DOM */ +function edit_field(field) { + let value = field.firstElementChild.innerText; + let input = document.createElement('input'); + input.value = value; + field.firstElementChild.replaceWith(input); - fetch(url_prefix + '/delete_token?' + query) - .then(function(response) { - return response.json(); - }) - .then(function(json) { - if (!json.ok) { return; } - document.querySelector('#token_' + token_id).remove(); - }); + let save = document.createElement('span'); + save.innerHTML = ''; + save.className = 'save font-awesome'; + save.setAttribute('onclick', 'save_field(this.parentElement)'); + field.children[1].replaceWith(save); } /* Misc */