Skip to content

Commit

Permalink
Added diff/current state to wsPubSub, moved processing to server in s…
Browse files Browse the repository at this point in the history
…ervices module.
  • Loading branch information
Sly1024 committed Mar 16, 2016
1 parent 34ce6e6 commit 6888b8c
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 41 deletions.
3 changes: 3 additions & 0 deletions modules/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
var allCommands = [
{ id: 'kodi', name: 'Kodi', command: 'su -c startkodi - pi' },
{ id: 'chmusb', name: 'Chmod Usb', command: 'chmod -R a+w /mnt/usb/' },
{ id: 'chmpigod', name: 'Chmod PiGod src', command: 'chmod -R a+w /home/pi/pigod/src/' },
{ id: 'reboot', name: 'Reboot', command: 'sudo reboot -f' },
{ id: 'rescan_minidlna', name: 'Rescan MiniDLNA', command: 'sudo minidlna -R; sudo service minidlna restart' }
];

allCommands.$_idField = 'id';

allCommands.forEach(function (cmd) { commandsById[cmd.id] = cmd; });

api.pubsub.subscribe('getCommands', function (data, targetWs, sourceWs) {
Expand Down
2 changes: 0 additions & 2 deletions modules/cpu.html
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,6 @@


updateProc(data) {
while (data.processes.length < 5) data.processes.push({ PID: '.' });

cpuSeries.append(Date.now(), data.cpu_perc);
this.update(data);
}
Expand Down
2 changes: 2 additions & 0 deletions modules/cpu.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
// uptime
var upt = lines[0].match(uptimeRE);

result.$_idField = 'PID';

return {
cpu_perc : (totalCPU * 10 | 0) / 10,
used_mem : (mems[4] >> 10),
Expand Down
4 changes: 1 addition & 3 deletions modules/io.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,8 @@

updateProc(data) {
var procs = data.processes;

if (procs.length < 1) procs.push({ TID: '.' });

var now = Date.now();

readSeries.append(now, data.total_read);
writeSeries.append(now, data.total_write);

Expand Down
2 changes: 2 additions & 0 deletions modules/io.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@

var total = lines[0].split(/\s+/);

result.$_idField = 'TID';

return {
total_read: Number(total[3]) * units[total[4]] / 1000,
total_write: Number(total[9]) * units[total[10]] / 1000,
Expand Down
2 changes: 0 additions & 2 deletions modules/net.html
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@
}

updateProc(data) {
if (data.processes.length < 1) data.processes.push({ PID: '.' });

var now = Date.now();
readSeries.append(now, data.tot_recv);
writeSeries.append(now, data.tot_sent);
Expand Down
2 changes: 2 additions & 0 deletions modules/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
result.push(obj);
}

result.$_idField = 'PID';

return {
tot_sent : (totalSent*10 | 0)/10,
tot_recv : (totalRecv*10 | 0)/10,
Expand Down
37 changes: 9 additions & 28 deletions modules/services.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@
</thead>
<tbody>
<tr each={ services }>
<td><img src="images/{icon}.png" width="16" height="16"></td>
<td><img src="images/{model.status2Icon[stat]}.png" width="16" height="16"></td>
<td class="">{name}</td>
<td class="">
<img src="images/play.png" width="16" height="16" class={ enabled: canStart, disabled: !canStart }
<img src="images/play.png" width="16" height="16" class={ enabled: stat != '+', disabled: stat == '+' }
onclick={ model.startClick }>
</td>
<td class="">
<img src="images/stop.png" width="16" height="16" class={ enabled: canStop, disabled: !canStop }
<img src="images/stop.png" width="16" height="16" class={ enabled: stat != '-', disabled: stat == '-' }
onclick={ model.stopClick }>
</td>
<td class="">
<img src="images/restart.png" width="16" height="16" class={ enabled: canStop, disabled: !canStop }
<img src="images/restart.png" width="16" height="16" class={ enabled: stat != '-', disabled: stat == '-' }
onclick={ model.restartClick }>
</td>
</tr>
Expand All @@ -48,7 +48,6 @@
var sortProps = ['name', 'stat'];

var servicesSorted = []; // sorted
var servicesByName = {}; // service obj by name

start() {
opts.pubsub.subscribe('services', data => this.updateProc(data));
Expand All @@ -58,38 +57,20 @@
opts.pubsub.unsubscribe('services');
}

var svcStatRE = /^ \[ ([-+\?]) \] (.*)$/;
var status2Icon = {
this.status2Icon = {
'-' : 'error',
'+' : 'ok',
'?' : 'help'
};

updateProc(data) {
var lines = data.split('\n');
var needSort = false;

for (var i = 0; i < lines.length; ++i) {
var match = lines[i].match(svcStatRE);
if (match && match.length === 3) {
var name = match[2];
var stat = match[1];
var obj = servicesByName[name];

if (!obj) {
obj = { name: name };
servicesByName[name] = obj;
servicesSorted.push(obj);
needSort = true;
}
obj.stat = stat;
obj.icon = status2Icon[stat];
obj.canStart = stat != '+';
obj.canStop = stat != '-';
}
}
// don't want to sort (modify) the array, because it is the previous state stored by the diff engine!
// TODO: save a deep clone in the wsPubSubClient's diff
servicesSorted = data.slice();

if (needSort) this.doSort();
this.doSort();

this.update({
last_udpated : new Date().toLocaleString(),
Expand Down
31 changes: 30 additions & 1 deletion modules/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,43 @@
var child_process = require('child_process');

api.registerDataStream('services',
api.createProcessStream('services', './servicesstream.sh', [], null, 1000, true)
api.createProcessStream('services', './servicesstream.sh', [], processData, 1000, true)
);

api.pubsub.subscribe('serviceCall', function (opts) {
if (opts.name && opts.command) {
child_process.exec('sudo service ' + opts.name + ' ' + opts.command);
}
});

var svcStatRE = /^ \[ ([-+\?]) \] (.*)$/;
var services = [];
var servicesByName = {};

services.$_idField = 'name';

function processData(data) {
var lines = data.split('\n');

for (var i = 0; i < lines.length; ++i) {
var match = lines[i].match(svcStatRE);
if (match && match.length === 3) {
var name = match[2];
var stat = match[1];
var obj = servicesByName[name];
if (!obj) {
obj = { name: name };
servicesByName[name] = obj;
services.push(obj);
}
obj.stat = stat;
}
}

// need to be referentially different than the previous, otherwise diff() returns NO_DIFF and sends nothing
// TODO: need to fix this in the wsPubSubServer code!
return services.slice();
}
}

})(exports);
4 changes: 2 additions & 2 deletions static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
return suppressErrorAlert;
};

// some polyfills
if (typeof Object.assign != 'function') {
(function () {
Object.assign = function (target) {
'use strict';
if (target === undefined || target === null) {
Expand All @@ -44,8 +44,8 @@
}
return output;
};
})();
}

</script>

<script type="text/javascript" src="sortable.js"></script>
Expand Down
84 changes: 82 additions & 2 deletions static/wsPubSubClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
pubsub.on('stopChannel', this.stopChannel.bind(this));
pubsub.on('publish', this.publish.bind(this));

this.states = {};
this.wsQ = []; // WebSocket message queue
this.connect(hostPort);
}
Expand Down Expand Up @@ -40,6 +41,8 @@
wsQ.length = 0;
}

me.states = {};

if (me.resubscribe) {
me.resubscribe = false;
var subs = me.pubsub.subs;
Expand All @@ -52,9 +55,12 @@
ws.onmessage = function (msg) {
var data = JSON.parse(msg.data);
if (data.action === 'publish') {
if (data.channel && data.payload) {
var channel = data.channel;
if (channel && data.payload) {
me.ignorePublish = true;
me.pubsub.publish(data.channel, data.payload);
var applied = me.applyDiff(me.states[channel], data.payload);
me.states[channel] = applied;
me.pubsub.publish(data.channel, applied);
me.ignorePublish = false;
} else {
throw new Error('[wsPubSubClient] unidentified msg ' + msg);
Expand Down Expand Up @@ -90,6 +96,80 @@
if (ws.readyState === 1) ws.send(str); else this.wsQ.push(str);
};

/** --------- Diff Functions -------------- */

var obj2str = Object.prototype.toString;

function isObject(arg) {
return obj2str.call(arg) === '[object Object]';
}

function isArray(arg) {
return Array.isArray ? Array.isArray(arg) : obj2str.call(arg) === '[object Object]';
}

/**
* Diff table for different source/target types.
* `target` = same value as target
* ND = No Diff (NODIFF_OBJ)
*
* | souce\target | null/undef | primitive | { object } | [ array ] |
* +--------------+------------+-----------+------------+--------------+
* | null/undef | target/ND | target | target | target |
* | primitive | target | target/ND | target | target |
* | { object } | target | target | {diff}/ND | target |
* | [ array ] | target | target | target |{$_arrDiff}/ND|
*
*/
proto.applyDiff = function(source, diff) {
//if (source == null) return diff; - No need

if (isObject(diff)) {
if (isArray(source) && diff.$_arrDiff) {
return this.applyArrDiff(source, diff);
}
if (isObject(source)) {
return this.applyObjDiff(source, diff);
}
}

return diff;
};

proto.applyObjDiff = function (source, diff) {
for (var key in diff) if (diff.hasOwnProperty(key)) {
source[key] = this.applyDiff(source[key], diff[key]);
}
if (diff.$_removed) {
diff.$_removed.forEach( function (key) {
source[key] = undefined; // we could `delete source[key];` but this is more efficient
});
}
return source;
};

proto.applyArrDiff = function (source, diff) {
var me = this;
var arrDiff = diff.$_arrDiff;

// remove
arrDiff[0].forEach(function (idx) { source.splice(idx, 1); });

// move
arrDiff[1].forEach(function (move) {
var item = source.splice(move[0], 1)[0];
if (move.length > 2) item = me.applyDiff(item, move[2]);
source.splice(move[1], 0, item);
});

// insert
arrDiff[2].forEach(function (insert) {
source.splice(insert[0], 0, insert[1]);
});

return source;
};

})(wsPubSubClient.prototype);

exports.wsPubSubClient = wsPubSubClient;
Expand Down
Loading

0 comments on commit 6888b8c

Please sign in to comment.