-
Notifications
You must be signed in to change notification settings - Fork 1
/
server.js
137 lines (116 loc) · 3.94 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
* http server for viewing chart with collected statistics
* launch with `yarn server`
*/
const Datastore = require('nedb');
const moment = require('moment');
const compression = require('compression');
const Express = require('express');
const { size } = require('lodash/collection');
const SocketIo = require('socket.io');
const Http = require('http');
const ipc = require('node-ipc');
const internalBus = new (require('events'))();
const debug = require('debug')('mhz19b-server');
const constants = require('./const');
const {
APP_PORT,
APP_HOST,
STORAGE_FILENAME,
PUBLIC_PATH,
IPC_ID_HTTP_SERVER,
// WINDOW_SECONDS,
MESSAGE_NAME,
} = constants;
// init IPC server
let ipcClientIdSeq = 0;
ipc.config.id = IPC_ID_HTTP_SERVER;
ipc.config.retry = 1500;
ipc.config.silent = true;
ipc.serve();
ipc.server.on('start', () => debug(`started ipc server id=${IPC_ID_HTTP_SERVER}`));
ipc.server.on(MESSAGE_NAME, point => internalBus.emit(MESSAGE_NAME, point));
ipc.server.on('connect', socket => {
const clientId = ++ipcClientIdSeq;
debug(`new ipc client connection id=${clientId}`);
socket.on('close', () => debug(`ipc client id=${clientId} socket closed`));
});
ipc.server.start();
const app = Express();
const server = Http.Server(app);
app.use(compression());
const io = SocketIo(server, { origins: 'http://localhost:8888' });
debug(`Loading database...`);
const db = new Datastore({
filename: STORAGE_FILENAME,
autoload: true,
});
debug(`Done`);
// once enabled this action "corrupts" database file and its not possible to load it anymore
// db.ensureIndex({ fieldName: 'timestamp' }, debug);
io.on('connection', function(socket) {
debug(`new ws connection id=${socket.id}`);
const ppmHandler = point => socket.emit(MESSAGE_NAME, point);
internalBus.on(MESSAGE_NAME, ppmHandler);
socket.on('disconnect', () => {
debug(`ws id=${socket.id} disconnected`);
internalBus.removeListener(MESSAGE_NAME, ppmHandler);
});
});
app.get(
'/constants',
(req, res) => res.json(constants)
);
app.get(
'/json',
(req, res) => {
const tick = Date.now();
debug(`received request to ${req.path}`);
if (size(req.query)) {
debug(`query params: ${JSON.stringify(req.query)}`);
}
const windowSize = parseInt(req.query.windowSize, 10);
const where = {
ppm: {
// exclude points generated at the moment of sensor startup
$ne: 410
},
timestamp: {
$gt: moment().subtract(windowSize, 'seconds')
},
};
db
.find(where)
.sort({ timestamp: 1 })
.exec((err, points) => {
// reduce max amount of points in response
const maxPoints = 3000;
const totalPoints = points.length;
const eachN = Math.max(1, Math.floor(totalPoints / maxPoints));
debug(`Fetched ${totalPoints} points from DB, max in response = ${maxPoints}. Going to take each ${eachN} point`);
const resultedArray = [];
points.forEach(({ timestamp, ppm, temperature }, index) => {
if (index % eachN === 0) {
resultedArray.push([timestamp.getTime(), ppm, temperature]);
}
});
if (resultedArray.length < totalPoints) {
debug(`Result was reduced to ${resultedArray.length} points`);
}
const delta = Date.now() - tick;
debug(`data prepared in ${delta}ms, sending response`);
res.json(resultedArray);
});
}
);
app.use(Express.static(PUBLIC_PATH));
server.listen(APP_PORT, (err) => {
if (err) {
debug(`failed to launch server: ${err}`);
} else {
debug(`listening on ${APP_HOST}:${APP_PORT}`)
const browserLink = `http://${APP_HOST}:${APP_PORT}/`;
debug(`open browser at ${browserLink}`)
}
});
// opn(browserLink);