fix backend memory issue, better handling of preload images, please wait screen while preload, add memoryprofiler infos

This commit is contained in:
Reaby committed 2019-08-25 20:06:55 +03:00
1 parent 50e7359f3e
commit 342df5510a
12 files changed
+287 -205

No files matched your search

+12 -10
View File
@@ -5,6 +5,8 @@ let logger = require('morgan');
let lessMiddleware = require('less-middleware');
let path = require('path');
require('./modules/profiler.js').init("./tmp");
const EventEmitter = require('events');
let config = require("./config.js");
@@ -25,9 +27,7 @@ let LocalStrategy = require('passport-local').Strategy;
let User = require("./modules/db.js");
passport.use("local", new LocalStrategy(
{
},
{},
function (username, password, cb) {
User.findByUsername(username, function (err, user) {
if (err) {
@@ -64,13 +64,15 @@ if (config.mediaServer) {
nms.run();
}
passport.serializeUser(function(user, cb) {
passport.serializeUser(function (user, cb) {
cb(null, user.id);
});
passport.deserializeUser(function(id, cb) {
passport.deserializeUser(function (id, cb) {
User.findById(id, function (err, user) {
if (err) { return cb(err); }
if (err) {
return cb(err);
}
cb(null, user);
});
});
@@ -103,9 +105,9 @@ i18next
caches: false, // ['cookie']
// optional expire and domain for set cookie
// cookieExpirationDate: new Date(),
// cookieDomain: 'myDomain',
// cookieSecure: true // if need secure cookie
// cookieExpirationDate: new Date(),
// cookieDomain: 'myDomain',
// cookieSecure: true // if need secure cookie
}
});
@@ -120,7 +122,7 @@ app.use(express.urlencoded({extended: false}));
app.use(cookieParser());
app.use(lessMiddleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
app.use(require('express-session')({ secret: config.sessionKey, resave: false, saveUninitialized: true }));
app.use(require('express-session')({secret: config.sessionKey, resave: false, saveUninitialized: true}));
// Initialize Passport and restore authentication state, if any, from the
// session.
+1 -1
View File
@@ -1,7 +1,7 @@
{
"displayName": "default",
"background": "bg.jpg",
"duration": 30,
"duration": 15,
"transition": "tiles3d",
"useWebFonts": false,
"displayTime": true,
+45 -72
View File
@@ -56,11 +56,10 @@ class admin {
dispatcher.on("updateBundles", function () {
io.emit("callback.dashboard.updateBundles", {
"bundleDirs": self.bundleManager.getBundleInfos()
"bundleDirs": bundleManager.getBundleInfos()
});
});
io.on("connection", function (socket) {
cli.success("WS " + socket.conn.remoteAddress + " connect with id:" + socket.id);
@@ -143,14 +142,13 @@ class admin {
}
view.io.emit("callback.load", view.getSlideData());
self.updateDashboard(io);
view = null;
serverOptions = null;
});
socket.on('controls.blackout', function () {
let view = self.getView();
view.serverOptions.blackout = view.serverOptions.blackout === false;
view.io.emit("callback.blackout", {serverOptions: view.serverOptions});
self.screenView.toggleBlackout();
self.updateDashboard(io);
});
@@ -173,23 +171,23 @@ class admin {
} catch (err) {
cli.error("preview instance not found");
}
bundle = null;
});
socket.on("controls.skipTo", function (data) {
let bundleSettings = self.getView().getBundle();
let bundleSettings = self.screenView.getBundle();
let slides = bundleSettings.enabledSlides;
let idx = slides.indexOf(data.fileName);
if (idx >= 0) {
self.getServerOptions().loopIndex = idx;
}
self.getView().mainLoop();
self.screenView.mainLoop();
});
socket.on('controls.toggle', function (data) {
let fileName = data.fileName;
let bundleSettings = self.getView().getBundle();
let bundleSettings = self.screenView.getBundle();
let idx = bundleSettings.disabledSlides.indexOf(fileName);
if (idx > -1) {
@@ -197,8 +195,8 @@ class admin {
} else {
bundleSettings.setSlideStatus(fileName, false);
}
self.updateDashboard(socket);
bundleSettings = null;
});
// announce
@@ -210,8 +208,7 @@ class admin {
}
dispatcher.emit("all.override", data);
} else {
let view = self.getView();
view.overrideSlide(data.json, data.png, data.duration, data.transition);
self.screenView.overrideSlide(data.json, data.png, data.duration, data.transition);
}
} catch (err) {
cli.error("error, admin.override", err);
@@ -225,16 +222,12 @@ class admin {
}
dispatcher.emit("all.override", data);
} else {
let view = self.getView();
view.overrideSlide(data.json, data.png, data.duration, data.transition);
self.screenView.overrideSlide(data.json, data.png, data.duration, data.transition);
}
});
socket.on('admin.setBundle', function (data) {
let view = self.getView();
view.changeBundle(data.bundle);
view.displayCurrentSlide();
self.screenView.changeBundle(data.bundle);
self.updateDashboard(io);
});
@@ -253,27 +246,9 @@ class admin {
socket.on('admin.reorderSlides', function (data) {
let bundle = bundleManager.getBundle(data.bundleName);
let i = 0;
for (let uuid of data.sortedIDs) {
bundle.setIndex(uuid, i);
i += 1;
}
// calculate next slide order for all displays which has the bundle selected
let display = screenView;
if (display.serverOptions.currentBundle === data.bundleName) {
for (let slide of bundle.allSlides) {
// calculate new index for next slide;
if (slide.uuid === display.serverOptions.currentFile) {
display.serverOptions.loopIndex = slide.index + 1;
}
}
}
bundle.save();
self.updateSlides(io, bundle.name, bundle);
bundleManager.reorderSlides(data.bundleName, data.sortedIDs);
dispatcher.emit("display.recalcBundleData", data.bundleName);
self.updateSlides();
});
/** remove slide **/
@@ -281,7 +256,7 @@ class admin {
try {
let bundle = bundleManager.getBundle(data.bundleName);
bundle.removeUuid(data.uuid);
self.updateSlides(io, bundle.name, bundle);
self.updateSlides();
self.announce(null, "callback.removeSlide", data);
} catch (err) {
cli.error("error while removing slide", err);
@@ -290,8 +265,6 @@ class admin {
socket.on("admin.createBundle", function (data) {
cli.info("@ create Bundle");
try {
if (!fs.existsSync("data/bundles" + data.dir)) {
fs.mkdirSync("data/bundles/" + data.dir);
@@ -372,7 +345,7 @@ class admin {
cli.success("save web link");
socket.emit("callback.saveLink", {});
self.updateSlides(io, data.bundleName, bundle);
self.updateSlides();
} catch (err) {
cli.error(err, "save web link");
@@ -402,7 +375,7 @@ class admin {
try {
let bundle = bundleManager.getBundle(data.bundleName);
bundle.setName(data.uuid, data.name);
self.updateSlides(io, data.bundleName, bundle);
self.updateSlides();
} catch (err) {
cli.error("error while renaming slide", err);
}
@@ -482,8 +455,8 @@ class admin {
bundleName: data.bundleName,
uuid: filename
});
self.updateSlides(io, data.bundleName, bundle);
self.updateSlides();
self.dispatcher.emit("lobbyUpdate");
} catch (err) {
cli.error(err, "save new slide date");
socket.emit("callback.save", {error: err});
@@ -521,7 +494,6 @@ class admin {
socket.emit("callback.edit.updateFileList", {error: err});
}
});
}); // io
}
@@ -531,19 +503,21 @@ class admin {
* @param {object} socket
*/
updateDashboard(socket) {
let view = this.getView();
let serverOptions = view.serverOptions;
let bundleSettings = view.getBundle();
let bundleSettings = this.screenView.getBundle();
socket.emit("callback.dashboard.update", {
bundleSettings: bundleSettings,
allSlides: bundleSettings.allSlides,
serverOptions: serverOptions,
serverOptions: this.screenView.serverOptions,
displayId: this.displayId
});
this.dispatcher.emit("dashboard.update", {displayId: this.displayId, serverOptions: serverOptions});
this.dispatcher.emit("dashboard.update", {
displayId: this.displayId,
serverOptions: this.screenView.serverOptions
});
bundleSettings = null;
}
/** helper function to call announce easier **/
@@ -551,23 +525,21 @@ class admin {
this.dispatcher.emit("announce", {screens: screens, event: event, data: data});
}
updateSlides(socket, bundlename, bundle) {
socket.emit("callback.dashboard.updateSlides", {
bundleName: bundlename,
bundleSettings: bundle
updateSlides() {
let bundleName = this.getServerOptions().currentBundle;
let bundle = this.getView().getBundle();
this.io.emit("callback.dashboard.updateSlides", {
bundleName: bundleName,
bundleSettings: bundle,
});
}
syncDashboard(socket) {
this.previewInstances.push({adminId: socket.id, preview: {}, currentView: {}});
let serverOptions = this.getView().serverOptions;
let bundleDirs = this.bundleManager.getBundleInfos();
socket.emit("callback.dashboard.sync", {
displayId: this.displayId,
bundleDirs: bundleDirs,
serverOptions: serverOptions,
bundleDirs: this.bundleManager.getBundleInfos(),
serverOptions: this.screenView.serverOptions,
displays: config.displays
});
}
@@ -585,7 +557,7 @@ class admin {
* @return infoscreen3/display.serverOptions
*/
getServerOptions() {
return this.getView().serverOptions;
return this.screenView.serverOptions;
}
/**
@@ -597,28 +569,29 @@ class admin {
controls(action) {
let view = this.getView();
switch (action) {
case "previous":
let view = this.getView();
view.serverOptions.loopIndex -= 2;
view.mainLoop();
break;
case "play":
this.getServerOptions().loop = true;
this.getView().mainLoop();
view.serverOptions.loop = true;
view.mainLoop();
this.updateDashboard(this.io);
break;
case "pause":
this.getView().clearTimers();
this.getServerOptions().loop = false;
view.clearTimers();
view.serverOptions.loop = false;
this.updateDashboard(this.io);
break;
case "next":
this.getView().mainLoop();
view.mainLoop();
break;
}
view = null;
}
} //
// admin
}
+126
View File
@@ -0,0 +1,126 @@
let cli = require(`./cli.js`);
class adminLobby {
/**
* @param sharedIO
* @param dispatcher
* @param screenView
* @param adminView
* @param bundleManager
*/
constructor(sharedIO, dispatcher, screenView, adminView, bundleManager) {
let io = sharedIO.of("/admin");
this.io = io;
this.dispatcher = dispatcher;
this.screenView = screenView;
this.adminView = adminView;
this.bundleManager = bundleManager;
let self = this;
// create overview admin lobby
io.on("connection", function (socket) {
let arr = [];
for (let display of screenView) {
arr.push({displayId: display.serverOptions.displayId, serverOptions: display.serverOptions});
}
socket.emit("callback.serverOptions", arr);
// handle other events
cli.info("WS/" + socket.conn.remoteAddress + " connect");
socket.on('error', function (error) {
cli.error(error, "WS/ error");
});
socket.on('disconnect', function (reason) {
cli.info("WS/ " + reason + " " + socket.conn.remoteAddress);
});
socket.on('admin.reorderSlides', function (data) {
bundleManager.reorderSlides(data.bundleName, data.sortedIDs);
dispatcher.emit("display.recalcBundleData", data.bundleName);
let bundle = bundleManager.getBundle(data.bundleName);
updateSlides(data.bundleName, bundle);
});
socket.on('admin.removeSlide', function (data) {
try {
let bundle = bundleManager.getBundle(data.bundleName);
bundle.removeUuid(data.uuid);
updateSlides(data.bundleName, bundle);
self.announce(null, "callback.removeSlide", data);
} catch (err) {
cli.error("error while removing slide", err);
}
});
/** rename **/
socket.on('admin.renameSlide', function (data) {
try {
let bundle = bundleManager.getBundle(data.bundleName);
bundle.setName(data.uuid, data.name);
updateSlides(data.bundleName, bundle);
} catch (err) {
cli.error("error while renaming slide", err);
}
});
socket.on('controls.previous', function (data) {
getAdminView(data.displayId).controls("previous");
});
socket.on('controls.play', function (data) {
getAdminView(data.displayId).controls("play");
});
socket.on('controls.next', function (data) {
getAdminView(data.displayId).controls("next");
});
socket.on('controls.pause', function (data) {
getAdminView(data.displayId).controls("pause");
});
dispatcher.on("dashboard.update", function (data) {
socket.emit("callback.serverOptions", [data]);
});
});
function updateSlides(bundleName, bundleData) {
for (let aView of adminView) {
aView.updateSlides();
}
// update admin lobby
io.emit("callback.dashboard.updateSlides", {
bundleName: bundleName,
bundleSettings: bundleData
});
}
/**
* @return admin
*/
function getAdminView(index) {
try {
return adminView[index];
} catch (err) {
cli.log(err);
}
}
}
announce(screens, event, data) {
/**
* @event event:announce
*/
this.dispatcher.emit("announce", {screens: screens, event: event, data: data});
}
}
module.exports = adminLobby;
+2 -8
View File
@@ -119,21 +119,15 @@ class bundleClass {
}
}
toJson() {
this.sync();
return JSON.stringify(this.allSlides, null, "\t");
}
save() {
this.sync();
try {
fs.writeFileSync("./data/bundles/" + this.name + "/slides.json", this.toJson());
fs.writeFileSync("./data/bundles/" + this.name + "/slides.json", JSON.stringify(this.allSlides, null, "\t"));
fs.writeFileSync("./data/bundles/" + this.name + "/bundle.json", JSON.stringify(this.bundleData, null, "\t"));
} catch (e) {
cli.error("error while saving file:", e);
}
}
}
/**
@@ -166,4 +160,4 @@ function sortByProperty(property) {
*
* @type {bundleClass}
*/
module.exports = bundleClass;
module.exports = bundleClass;
+11 -1
View File
@@ -51,6 +51,16 @@ class bundleManager {
}
}
reorderSlides(bundleName, sortedIDs) {
let bundle = this.getBundle(bundleName);
let i = 0;
for (let uuid of sortedIDs) {
bundle.setIndex(uuid, i);
i += 1;
}
bundle.save();
}
/**
*
* @return {Array}
@@ -90,4 +100,4 @@ function getJson(file) {
/**
* @type {bundleManager}
*/
module.exports = bundleManager;
module.exports = bundleManager;
+33 -28
View File
@@ -1,3 +1,4 @@
'use strict'
let fs = require("fs");
let cli = require(`./cli.js`);
let bundleManager = require(`./bundleManager.js`);
@@ -16,16 +17,6 @@ class display {
*/
constructor(sharedIO, dispatcher, meta, displayId, bundleManager) {
cli.info("Starting display with id " + displayId + " ...");
/** @property {Array} timeoutId - holds setTimeout id's for mainLoop */
this.timeoutId = [];
/**
* @type {bundleManager|module:infoscreen3/bundleManager}
*/
this.bundleManager = bundleManager;
let self = this;
/**
* @property {number} displayId - this display id
* @property {number} currentId - index number @see getBundle()
@@ -59,11 +50,20 @@ class display {
displayTime: true
};
/** @property {Array} timeoutId - holds setTimeout id's for mainLoop */
this.timeoutId = null;
/**
* @type {bundleManager|module:infoscreen3/bundleManager}
*/
this.bundleManager = bundleManager;
let io = sharedIO.of("/display-" + displayId.toString());
this.io = io;
this.name = meta.name;
this.dispatcher = dispatcher;
this.id = displayId;
let self = this;
/**
* helper callback for global announce
@@ -76,10 +76,20 @@ class display {
self.displayCurrentSlide();
});
dispatcher.on("display.recalcBundleData", function (bundleName) {
if (self.serverOptions.currentBundle === bundleName) {
for (let slide of self.getBundle().allSlides) {
// calculate new index for next slide;
if (slide.uuid === self.serverOptions.currentFile) {
self.serverOptions.loopIndex = slide.index + 1;
}
}
}
});
dispatcher.on("announce", function (obj) {
// if global announce, ie screens is null
if (obj.screens === null) {
console.log("announcing: " + this.serverOptions.displayId);
io.emit(obj.event, obj.data);
} else {
// screens is array
@@ -141,6 +151,7 @@ class display {
this.serverOptions.transition = bundle.getBundleData().transition;
this.serverOptions.loop = true;
this.io.emit("callback.load", this.getSlideData());
bundle = null;
this.mainLoop();
}
@@ -153,10 +164,7 @@ class display {
* clears timers
*/
clearTimers() {
for (let i in this.timeoutId) {
clearTimeout(this.timeoutId[i]);
delete this.timeoutId[i];
}
clearTimeout(this.timeoutId);
}
/**
@@ -166,6 +174,10 @@ class display {
return this.bundleManager.getBundle(this.serverOptions.currentBundle);
}
toggleBlackout() {
this.serverOptions.blackout = this.serverOptions.blackout === false;
this.io.emit("callback.blackout", {serverOptions: this.serverOptions});
}
/**
* emits custom event for screens
@@ -208,8 +220,6 @@ class display {
}
if (this.serverOptions.loop) {
let that = this;
// override slide timeout if set by slide
let slideTimeout = this.serverOptions.slideDuration * 1000;
if (this.serverOptions.currentMeta.duration > 5) {
@@ -217,11 +227,7 @@ class display {
}
if (slideTimeout >= 5000) {
this.timeoutId.push(
setTimeout(function () {
that.mainLoop();
}, slideTimeout));
this.timeoutId = setTimeout(this.mainLoop.bind(this), slideTimeout);
} else {
this.serverOptions.loop = false;
}
@@ -231,6 +237,8 @@ class display {
this.displayCurrentSlide();
this.serverOptions.loopIndex += 1;
}
bundle = null;
}
overrideSlide(json, pngData, duration, transition) {
@@ -244,20 +252,17 @@ class display {
if (json.type === "image") {
fs.writeFileSync("./tmp/display_" + this.serverOptions.displayId + ".png", pngData.replace(/^data:image\/png;base64,/, ""), "base64");
}
let that = this;
if (duration && duration >= 5) {
this.serverOptions.loop = true;
this.timeoutId.push(
setTimeout(function () {
that.mainLoop();
}, duration * 1000));
this.timeoutId = setTimeout(this.mainLoop.bind(this), duration * 1000);
}
this.displayCurrentSlide();
this.serverOptions.transition = _transition;
}
displayCurrentSlide() {
this.announce([this.serverOptions.displayId, "admin"], "callback.update", this.getSlideData());
this.announce([this.id, "admin"], "callback.update", this.getSlideData());
}
}
+25
View File
@@ -0,0 +1,25 @@
var prevValue = 0;
let cli = require('./cli.js');
module.exports.init = function (datadir) {
setInterval(tickHeapDump, 1000);
};
/**
* Schedule a heapdump by the end of next tick
*/
function tickHeapDump() {
setImmediate(function () {
heapDump();
});
}
/**
* Creates a heap dump if the currently memory threshold is exceeded
*/
function heapDump() {
var memMB = (process.memoryUsage().rss / 1048576).toFixed(1);
if (prevValue != memMB) {
cli.info("Memory: " + memMB + 'Mb');
prevValue = memMB;
}
}
+2 -53
View File
@@ -1,13 +1,12 @@
let availableDisplays = require(`../config.js`).displays;
let display = require(`./display.js`);
let admin = require(`./admin.js`);
let adminLobby = require(`./adminLobby.js`);
let cli = require(`./cli.js`);
let _bundleManager = require(`./bundleManager.js`);
let chalk = require('chalk');
let fs = require('fs');
/**
* @param server
* @param app
@@ -70,46 +69,7 @@ module.exports = function (server, app, io, dispatcher) {
screenId += 1;
}
// create overview admin lobby
io.of("/admin").on("connection", function (socket) {
let arr = [];
for (let display of screenView) {
arr.push({displayId: display.serverOptions.displayId, serverOptions: display.serverOptions});
}
socket.emit("callback.serverOptions", arr);
// handle other events
cli.info("WS/" + socket.conn.remoteAddress + " connect");
socket.on('error', function (error) {
cli.error(error, "WS/ error");
});
socket.on('disconnect', function (reason) {
cli.info("WS/ " + reason + " " + socket.conn.remoteAddress);
});
socket.on('controls.previous', function (data) {
getAdminView(data.displayId).controls("previous");
});
socket.on('controls.play', function (data) {
getAdminView(data.displayId).controls("play");
});
socket.on('controls.next', function (data) {
getAdminView(data.displayId).controls("next");
});
socket.on('controls.pause', function (data) {
getAdminView(data.displayId).controls("pause");
});
dispatcher.on("dashboard.update", function (data) {
socket.emit("callback.serverOptions", [data]);
});
});
let adminLobby1 = new adminLobby(io, dispatcher, screenView, adminView, bundleManager);
// create lobby
io.of("/lobby").on("connection", function (socket) {
@@ -136,17 +96,6 @@ module.exports = function (server, app, io, dispatcher) {
});
});
/**
* @return admin
*/
function getAdminView(index) {
try {
return adminView[index];
} catch (err) {
cli.log(err);
}
}
return {screenView: screenView, adminView: adminView, bundleManager: bundleManager};
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+29 -31
View File
@@ -15,19 +15,16 @@ function symmetricDifference(a1, a2) {
var connectionTimeoutId;
window.f = new flux.slider('#slider', {
controls: false,
captions: false,
autoplay: false,
pagination: false,
width: $(window).width(),
height: $(window).height(),
});
$(function () {
if (!flux.browser.supportsTransitions)
alert("Flux Slider requires a browser that supports CSS3 transitions");
window.f = new flux.slider('#slider', {
controls: false,
captions: false,
autoplay: false,
pagination: false,
width: $(window).width(),
height: $(window).height(),
});
$(window).resize(function () {
if (this.resizeTO) clearTimeout(this.resizeTO);
this.resizeTO = setTimeout(function () {
@@ -113,15 +110,7 @@ socket.on('callback.time', function (data) {
socket.on('callback.load', function (data) {
serverOptions = data.serverOptions;
bundleData = data.bundleData;
preloadImages(data.slides);
checkBlackout();
setTimeout(function () {
setBackground(data.bundleData.background);
if (checkStream(serverOptions) === false) {
nextSlide(data);
}
}, 1000);
preloadImages(data);
});
@@ -150,7 +139,6 @@ socket.on('callback.reloadImage', function (data) {
socket.on('callback.announce', function (data) {
checkBlackout();
nextSlide(data);
});
socket.on('callback.forceSlide', function (data) {
@@ -258,15 +246,14 @@ function nextSlide(data) {
transition = serverOptions.currentMeta.transition;
}
$("#" + getWebLayer()).addClass("fadeOut").removeClass("fadeIn").contents().empty();
$("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn").contents().empty();
$("#" + getWebLayer()).addClass("fadeOut").removeClass("fadeIn");
$("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn");
$("#slider").show();
window.f.showImageById(serverOptions.currentFile, transition);
setTimeout(function () {
clearIFrame(getWebLayer());
clearIFrame(getWebLayer(1));
}, 2500);
$("#slider").show();
window.f.showImageById(serverOptions.currentFile, transition);
break;
}
}
@@ -348,15 +335,19 @@ function checkStream(serverOptions) {
}
return false;
}
return false;
return true;
}
/**
* preload images
* @param allSlides
* @param data
*/
function preloadImages(allSlides) {
function preloadImages(data) {
window.f.clearImages();
var allSlides = data.slides;
var count = allSlides.length;
var counter = 0;
for (var i in allSlides) {
try {
if (allSlides[i].type === "slide") {
@@ -364,6 +355,13 @@ function preloadImages(allSlides) {
image.id = imageId;
window.f.images.push(image);
window.f.imageData.push(imageData);
counter++;
if (counter >= count) {
setBackground(bundleData.background);
if (checkStream(serverOptions) === false) {
nextSlide(data);
}
}
});
}
} catch (err) {
@@ -484,9 +482,9 @@ function getDataUri(url, imageId, callback) {
var canvas = document.createElement('canvas');
canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size
canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size
canvas.getContext('2d').drawImage(this, 0, 0);
callback(imageId, canvas.toDataURL('image/png'), {src: url});
canvas = null;
};
image.src = url;
}
+1 -1
View File
@@ -28,7 +28,7 @@
</div>
<div id="bg">
<img id="bgimg" class="fsimage" src=""/>
<img id="bgimg" class="fsimage" src="/img/wait.png"/>
</div>
<video loop autoplay id="bgvid" class="fsimage" poster=""></video>