finish converting AJAX to Websocket

This commit is contained in:
iou1name 2019-11-15 12:21:35 -05:00
parent 58f1bd2979
commit fc2aa37f93
2 changed files with 185 additions and 182 deletions

View File

@ -1,75 +1,94 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Websocket events.""" """Websocket events."""
import re
import types import types
import models import models
from models import network from models import network
async def toggle_outlet(ws, data): async def toggle_outlet(ws, data):
"""Toggles the state of a RelayDevice.""" """Toggles the state of a RelayDevice."""
device_id = data.get('device_id') device_id = data.get('device_id')
sub_device_id = data.get('sub_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) device = network.find(device_id)
if not device: 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 return
state = device.toggle(sub_device_id) state = device.toggle(sub_device_id)
if state is None: 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 return
models.save_network(network) models.save_network(network)
data = {}
data['ok'] = True data['ok'] = True
data['device_id'] = device_id
data['sub_device_id'] = sub_device_id
data['state'] = state data['state'] = state
res = {'event': 'toggle_outlet', 'data': data} res = {'event': 'toggle_outlet', 'data': data}
await ws.send_json(res) await ws.send_json(res)
async def edit(ws, data): async def edit_field(ws, data):
"""Edits the text of a particular field.""" """Edits the text of a particular field."""
device_id = data.get('device_id') device_id = data.get('device_id')
sub_device_id = data.get('sub_device_id') sub_device_id = data.get('sub_device_id')
field = data.get('field') field = data.get('field')
value = data.get('value') 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) device = network.find(device_id)
if not device: 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 return
if device.locked: 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 return
if sub_device_id: if sub_device_id:
sub_device = device.find(sub_device_id) sub_device = device.find(sub_device_id)
if not sub_device: 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 return
if hasattr(sub_device, field): if hasattr(sub_device, field):
setattr(sub_device, field, value) setattr(sub_device, field, value)
else: 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 return
else: else:
if hasattr(device, field): if hasattr(device, field):
setattr(device, field, value) setattr(device, field, value)
else: 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 return
res = {
'ok': True,
'field': field,
'value': value
}
models.save_network(network) models.save_network(network)
data['ok'] = True
res = {'event': 'edit_field', 'data': data}
await ws.send_json(res) await ws.send_json(res)
@ -80,10 +99,15 @@ async def new_device(ws, data):
""" """
device_type = data.get('device_type') device_type = data.get('device_type')
data = {}
data['device_type'] = device_type
if device_type == 'RelayDevice': if device_type == 'RelayDevice':
device = models.RelayDevice() device = models.RelayDevice()
else: 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 return
devices = [dev for dev in network if dev.type == device_type] 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 device.id = device_type + num
network.append(device) network.append(device)
models.save_network(network) 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) await ws.send_json(res)
async def lock_device(ws, data): async def lock_device(ws, data):
"""Locks or unlocks a device to prevent or allow editing it's fields.""" """Locks or unlocks a device to prevent or allow editing it's fields."""
device_id = data.get('device_id') 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) device = network.find(device_id)
if not device: 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 return
if locked: device.locked = locked
device.locked = True
else:
device.locked = False
models.save_network(network) 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.""" """Deletes a device."""
device_id = data.get('device_id') device_id = data.get('device_id')
data = {}
data['device_id'] = device_id
device = network.find(device_id) device = network.find(device_id)
if not device: 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 return
network.remove(device) network.remove(device)
models.save_network(network) 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 = {} events = {}

View File

@ -24,12 +24,13 @@ function load() {
/* Websocket setup */ /* Websocket setup */
function init_websocket() { 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 = socket.send;
socket.send = function(event_title, data) { socket.send = function(event_title, data) {
data = JSON.stringify({event: event_title, data: data}); data = JSON.stringify({event: event_title, data: data});
if (socket.readyState == 0) { if (socket.readyState == 0) {
console.log("Socket is still opening!"); console.log("Socket is still opening!");
return;
} }
socket._send(data); socket._send(data);
} }
@ -38,6 +39,10 @@ function init_websocket() {
socket.onerror = onerror; socket.onerror = onerror;
socket.events = {}; socket.events = {};
socket.events['toggle_outlet'] = toggle_outlet_recv; 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; return socket;
} }
@ -45,7 +50,13 @@ function onmessage (e) {
let data = JSON.parse(e.data); let data = JSON.parse(e.data);
let event = data.event; let event = data.event;
data = data.data; 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); socket.events[event](data);
} }
@ -63,12 +74,8 @@ function onerror(e) {
/* Websocket receive */ /* Websocket receive */
function toggle_outlet_recv(data) { 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 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; let svg = sub_device.querySelector('.outlet_image').getSVGDocument().firstChild;
if (data.state === true) { if (data.state === true) {
svg.classList.remove('off'); svg.classList.remove('off');
@ -79,58 +86,15 @@ function toggle_outlet_recv(data) {
} }
} }
/* Websocket send */ function edit_field_recv(data) {
function toggle_outlet(svg) { let device = document.querySelector('#' + data.device_id);
let sub_dev = get_object_from_svg(svg).parentElement; if (data.sub_device_id) {
let data = { device = device.querySelector('.' + data.sub_device_id);
device_id: sub_dev.parentElement.parentElement.id,
sub_device_id: sub_dev.querySelector('.id').innerText,
};
socket.send('toggle_outlet', data);
} }
let field = device.querySelector('.' + data.field);
/* 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 = '';
}
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('&');
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'); let span = document.createElement('span');
span.innerText = json['value']; span.innerText = data['value'];
span.className = 'field_value'; span.className = 'field_value';
field.firstElementChild.replaceWith(span); field.firstElementChild.replaceWith(span);
@ -139,49 +103,26 @@ function save_field(field) {
edit.className = 'edit font-awesome'; edit.className = 'edit font-awesome';
edit.setAttribute('onclick', 'edit_field(this.parentElement)'); edit.setAttribute('onclick', 'edit_field(this.parentElement)');
field.children[1].replaceWith(edit); field.children[1].replaceWith(edit);
});
} }
function new_device() { function new_device_recv(data) {
let params = { if (data.device_type == 'RelayDevice') {
device_type: 'RelayDevice', var template = document.querySelector('#RelayDevice_template');
}; } else {
let query = Object.keys(params) return;
.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); let node = document.importNode(template.content, true);
node.querySelector('.id').querySelector('.field_value').textContent = json.device_id; node.querySelector('.id').querySelector('.field_value').textContent = data.device_id;
document.querySelector('#devices').appendChild(node); document.querySelector('#devices').appendChild(node);
let children = document.querySelector('#devices').children; let children = document.querySelector('#devices').children;
children[children.length - 1].id = json.device_id; children[children.length - 1].id = data.device_id;
});
} }
function lock_device(device) { function lock_device_recv(data) {
if (device.querySelector('.save')) { return; } let device = document.querySelector('#' + data.device_id);
let params = {
device_id: device.id,
locked: true,
};
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'); let fields = device.querySelectorAll('.editable');
if (data.locked) {
fields.forEach(function(field) { fields.forEach(function(field) {
field.querySelector('.edit').remove(); field.querySelector('.edit').remove();
}); });
@ -192,26 +133,7 @@ function lock_device(device) {
unlock.className = 'unlock font-awesome'; unlock.className = 'unlock font-awesome';
unlock.setAttribute('onclick', 'unlock_device(this.parentElement.parentElement)'); unlock.setAttribute('onclick', 'unlock_device(this.parentElement.parentElement)');
device.querySelector('.id').appendChild(unlock); device.querySelector('.id').appendChild(unlock);
}); } else {
}
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');
fields.forEach(function(field) { fields.forEach(function(field) {
let edit = document.createElement('span'); let edit = document.createElement('span');
edit.innerHTML = ''; edit.innerHTML = '';
@ -232,45 +154,87 @@ function unlock_device(device) {
lock.className = 'lock font-awesome'; lock.className = 'lock font-awesome';
lock.setAttribute('onclick', 'lock_device(this.parentElement.parentElement)'); lock.setAttribute('onclick', 'lock_device(this.parentElement.parentElement)');
device.querySelector('.id').appendChild(lock); 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) { function delete_device(device) {
if (!window.confirm("Are you sure you want to delete this device?")) { return; } if (!window.confirm("Are you sure you want to delete this device?")) { return; }
let params = { let data = {
device_id: device.id, device_id: device.id,
}; };
let query = Object.keys(params) socket.send('delete_device', data);
.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()
});
} }
function delete_token(token_id) { /* DOM */
if (!window.confirm("Are you sure you want to delete this token?")) { return; } function edit_field(field) {
let params = { let value = field.firstElementChild.innerText;
token_id: token_id, let input = document.createElement('input');
}; input.value = value;
let query = Object.keys(params) field.firstElementChild.replaceWith(input);
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
.join('&');
fetch(url_prefix + '/delete_token?' + query) let save = document.createElement('span');
.then(function(response) { save.innerHTML = '';
return response.json(); save.className = 'save font-awesome';
}) save.setAttribute('onclick', 'save_field(this.parentElement)');
.then(function(json) { field.children[1].replaceWith(save);
if (!json.ok) { return; }
document.querySelector('#token_' + token_id).remove();
});
} }
/* Misc */ /* Misc */