pslockout/webserver/server.js

153 lines
3.7 KiB
JavaScript

const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const app = express();
const DEBUG_LOGGING = false;
const AUTH_SERVER_URL = 'http://localhost:8000';
const log = (string) => {
date = new Date().toISOString().replace('T', ' ').split('.')[0];
console.log(date, '-', string);
}
// Enums
const lockStates = {
LOCK_OFF: 0,
LOCK_PREARM: 1,
LOCK_ARMED: 2,
LOCK_ON_PRESSED: 3,
LOCK_ON: 4,
};
let toolStatus = null;
const server = app.listen(8080, () => {
log('Lockout socket server listening on port 8080!');
});
const io = require('socket.io')(server);
// Express http server stuff:
// TODO : remove on prod
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
app.use(bodyParser.json());
app.post('/api/lockout/:mac', (req, res) => {
if (toolStatus) {
const mac = req.params.mac;
DEBUG_LOGGING && log(`${mac} - Lock state: ${Object.keys(lockStates)[req.body.lockState]}`);
const tmp = Object.entries(toolStatus).find(x => x[1].mac == mac)
const toolSlug = tmp ? tmp[0] : null;
if (toolSlug) {
let clearAction = false;
let tool = toolStatus[toolSlug];
tool.lastState = tool.state;
switch (req.body.lockState) {
case lockStates.LOCK_OFF:
tool.state = 'off';
if (tool.action == 'disarm') clearAction = true;
break;
case lockStates.LOCK_ARMED:
tool.state = 'armed';
if (tool.action == 'arm') clearAction = true;
break;
case lockStates.LOCK_ON:
tool.state = 'on';
break;
default:
break;
}
// Track in case state is switched from elsewhere
if (tool.state != tool.lastState) clearAction = true;
if (clearAction) {
log(`${mac} - Report | Previous state: ${tool.lastState} | New state: ${tool.state} | Website action: ${tool.action || 'N/A'}`);
tool.action = '';
io.sockets.emit('toolStatus', toolStatus);
}
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ action: tool.action }));
toolStatus[toolSlug] = tool;
} else {
res.sendStatus(404);
}
} else {
res.sendStatus(503);
}
});
app.get('*', (req, res) => {
res.sendStatus(404);
});
// Socket.io websocket stuff:
// TODO : remove on prod
io.origins('*:*');
io.on('connection', socket => {
socket.emit('toolStatus', toolStatus);
socket.on('log', string => {
log(string);
});
socket.on('requestInterlock', data => {
const username = data.username;
const token = data.token;
const toolSlug = data.change.toolSlug;
const action = data.change.action;
log(`${username} - Request | Tool: ${toolSlug} | Action: ${action}`);
axios.get(AUTH_SERVER_URL + '/user/', {
headers: {'Authorization': 'Token ' + token},
})
.then(res => {
const profile = res.data[0].profile || null;
if (profile && profile.authorized_tools.includes(toolSlug)) {
toolStatus[toolSlug].action = action;
log(`${username} - Allowed | Tool: ${toolSlug} | Action: ${action}`);
io.sockets.emit('toolStatus', toolStatus);
} else {
log(`${username} - DISALLOWED | Tool: ${toolSlug} | Action: ${action}`);
}
})
.catch(err =>
log(err.message)
);
});
});
setInterval(() => {
axios.get(AUTH_SERVER_URL + '/tooldata/')
.then(res => {
toolStatus = res.data.categories
.reduce((a, x) => a.concat(x.tools), [])
.reduce((a, x) => ({...a, [x.slug]: a[x.slug] ? {
...a[x.slug], mac: x.mac
} : {
mac: x.mac, action: '', state: 'off', lastState: 'n/a'
}}), toolStatus || {});
io.sockets.emit('toolStatus', toolStatus);
})
.catch(err =>
log(err.message)
);
}, 10000);