Cleanup more callback things (#3051)

Looks quite stable on my computers, so maybe we give it a try?

---------

Co-authored-by: veeck <michael@veeck.de>
This commit is contained in:
Veeck 2023-02-26 18:36:47 +01:00 committed by GitHub
parent b5b61246e6
commit 1b2785cc56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1243 additions and 1244 deletions

View File

@ -37,10 +37,7 @@ _This release is scheduled to be released on 2023-04-01._
- Update dates in Calendar widgets every minute - Update dates in Calendar widgets every minute
- Cleanup jest coverage for patches - Cleanup jest coverage for patches
- Update `stylelint` dependencies, switch to `stylelint-config-standard` and handle `stylelint` issues - Update `stylelint` dependencies, switch to `stylelint-config-standard` and handle `stylelint` issues
- Convert load callbacks to async/await - Convert lots of callbacks to async/await
- Convert module start to async/await
- Convert translator callbacks to async/await
- Convert app-start/-stop callbacks to async/awaits
### Fixed ### Fixed

View File

@ -152,9 +152,8 @@ function App() {
* Loads a specific module. * Loads a specific module.
* *
* @param {string} module The name of the module (including subpath). * @param {string} module The name of the module (including subpath).
* @param {Function} callback Function to be called after loading
*/ */
function loadModule(module, callback) { function loadModule(module) {
const elements = module.split("/"); const elements = module.split("/");
const moduleName = elements[elements.length - 1]; const moduleName = elements[elements.length - 1];
let moduleFolder = `${__dirname}/../modules/${module}`; let moduleFolder = `${__dirname}/../modules/${module}`;
@ -199,19 +198,17 @@ function App() {
m.setPath(path.resolve(moduleFolder)); m.setPath(path.resolve(moduleFolder));
nodeHelpers.push(m); nodeHelpers.push(m);
m.loaded(callback); m.loaded();
} else {
callback();
} }
} }
/** /**
* Loads all modules. * Loads all modules.
* *
* @param {Module[]} modules All modules to be loaded * @param {string[]} modules All modules to be loaded
* @param {Function} callback Function to be called after loading
*/ */
function loadModules(modules, callback) { async function loadModules(modules) {
return new Promise((resolve) => {
Log.log("Loading module helpers ..."); Log.log("Loading module helpers ...");
/** /**
@ -220,18 +217,18 @@ function App() {
function loadNextModule() { function loadNextModule() {
if (modules.length > 0) { if (modules.length > 0) {
const nextModule = modules[0]; const nextModule = modules[0];
loadModule(nextModule, function () { loadModule(nextModule);
modules = modules.slice(1); modules = modules.slice(1);
loadNextModule(); loadNextModule();
});
} else { } else {
// All modules are loaded // All modules are loaded
Log.log("All module helpers loaded."); Log.log("All module helpers loaded.");
callback(); resolve();
} }
} }
loadNextModule(); loadNextModule();
});
} }
/** /**
@ -272,14 +269,13 @@ function App() {
Log.setLogLevel(config.logLevel); Log.setLogLevel(config.logLevel);
let modules = []; let modules = [];
for (const module of config.modules) { for (const module of config.modules) {
if (!modules.includes(module.module) && !module.disabled) { if (!modules.includes(module.module) && !module.disabled) {
modules.push(module.module); modules.push(module.module);
} }
} }
await loadModules(modules);
loadModules(modules, async function () {
httpServer = new Server(config); httpServer = new Server(config);
const { app, io } = await httpServer.open(); const { app, io } = await httpServer.open();
Log.log("Server started ..."); Log.log("Server started ...");
@ -307,7 +303,6 @@ function App() {
}); });
Log.log("Sockets connected & modules started ..."); Log.log("Sockets connected & modules started ...");
});
return config; return config;
}; };

View File

@ -16,37 +16,9 @@ const Loader = (function () {
/* Private Methods */ /* Private Methods */
/** /**
* Loops thru all modules and requests load for every module. * Loops through all modules and requests start for every module.
*/ */
const loadModules = function () { const startModules = async function () {
let moduleData = getModuleData();
const loadNextModule = function () {
if (moduleData.length > 0) {
const nextModule = moduleData[0];
loadModule(nextModule, function () {
moduleData = moduleData.slice(1);
loadNextModule();
});
} else {
// All modules loaded. Load custom.css
// This is done after all the modules so we can
// overwrite all the defined styles.
loadFile(config.customCss).then(() => {
// custom.css loaded. Start all modules.
startModules();
});
}
};
loadNextModule();
};
/**
* Loops thru all modules and requests start for every module.
*/
const startModules = function () {
const modulePromises = []; const modulePromises = [];
for (const module of moduleObjects) { for (const module of moduleObjects) {
try { try {
@ -57,7 +29,8 @@ const Loader = (function () {
} }
} }
Promise.allSettled(modulePromises).then((results) => { const results = await Promise.allSettled(modulePromises);
// Log errors that happened during async node_helper startup // Log errors that happened during async node_helper startup
results.forEach((result) => { results.forEach((result) => {
if (result.status === "rejected") { if (result.status === "rejected") {
@ -75,7 +48,6 @@ const Loader = (function () {
thisModule.hide(); thisModule.hide();
} }
} }
});
}; };
/** /**
@ -130,32 +102,30 @@ const Loader = (function () {
}; };
/** /**
* Load modules via ajax request and create module objects.s * Load modules via ajax request and create module objects.
* *
* @param {object} module Information about the module we want to load. * @param {object} module Information about the module we want to load.
* @param {Function} callback Function called when done. * @returns {Promise<void>} resolved when module is loaded
*/ */
const loadModule = function (module, callback) { const loadModule = async function (module) {
const url = module.path + module.file; const url = module.path + module.file;
const afterLoad = function () { /**
* @returns {Promise<void>}
*/
const afterLoad = async function () {
const moduleObject = Module.create(module.name); const moduleObject = Module.create(module.name);
if (moduleObject) { if (moduleObject) {
bootstrapModule(module, moduleObject, function () { await bootstrapModule(module, moduleObject);
callback();
});
} else {
callback();
} }
}; };
if (loadedModuleFiles.indexOf(url) !== -1) { if (loadedModuleFiles.indexOf(url) !== -1) {
afterLoad(); await afterLoad();
} else { } else {
loadFile(url).then(() => { await loadFile(url);
loadedModuleFiles.push(url); loadedModuleFiles.push(url);
afterLoad(); await afterLoad();
});
} }
}; };
@ -164,24 +134,21 @@ const Loader = (function () {
* *
* @param {object} module Information about the module we want to load. * @param {object} module Information about the module we want to load.
* @param {Module} mObj Modules instance. * @param {Module} mObj Modules instance.
* @param {Function} callback Function called when done.
*/ */
const bootstrapModule = function (module, mObj, callback) { const bootstrapModule = async function (module, mObj) {
Log.info("Bootstrapping module: " + module.name); Log.info("Bootstrapping module: " + module.name);
mObj.setData(module); mObj.setData(module);
mObj.loadScripts().then(() => { await mObj.loadScripts();
Log.log("Scripts loaded for: " + module.name); Log.log("Scripts loaded for: " + module.name);
mObj.loadStyles().then(() => {
await mObj.loadStyles();
Log.log("Styles loaded for: " + module.name); Log.log("Styles loaded for: " + module.name);
mObj.loadTranslations().then(() => {
await mObj.loadTranslations();
Log.log("Translations loaded for: " + module.name); Log.log("Translations loaded for: " + module.name);
moduleObjects.push(mObj); moduleObjects.push(mObj);
callback();
});
});
});
}; };
/** /**
@ -235,8 +202,28 @@ const Loader = (function () {
/** /**
* Load all modules as defined in the config. * Load all modules as defined in the config.
*/ */
loadModules: function () { loadModules: async function () {
loadModules(); let moduleData = getModuleData();
/**
* @returns {Promise<void>} when all modules are loaded
*/
const loadNextModule = async function () {
if (moduleData.length > 0) {
const nextModule = moduleData[0];
await loadModule(nextModule);
moduleData = moduleData.slice(1);
await loadNextModule();
} else {
// All modules loaded. Load custom.css
// This is done after all the modules so we can
// overwrite all the defined styles.
await loadFile(config.customCss);
// custom.css loaded. Start all modules.
await startModules();
}
};
await loadNextModule();
}, },
/** /**
@ -250,7 +237,7 @@ const Loader = (function () {
loadFileForModule: async function (fileName, module) { loadFileForModule: async function (fileName, module) {
if (loadedFiles.indexOf(fileName.toLowerCase()) !== -1) { if (loadedFiles.indexOf(fileName.toLowerCase()) !== -1) {
Log.log("File already loaded: " + fileName); Log.log("File already loaded: " + fileName);
return Promise.resolve(); return;
} }
if (fileName.indexOf("http://") === 0 || fileName.indexOf("https://") === 0 || fileName.indexOf("/") !== -1) { if (fileName.indexOf("http://") === 0 || fileName.indexOf("https://") === 0 || fileName.indexOf("/") !== -1) {

View File

@ -479,13 +479,14 @@ const MM = (function () {
/** /**
* Main init method. * Main init method.
*/ */
init: function () { init: async function () {
Log.info("Initializing MagicMirror²."); Log.info("Initializing MagicMirror².");
loadConfig(); loadConfig();
Log.setLogLevel(config.logLevel); Log.setLogLevel(config.logLevel);
Translator.loadCoreTranslations(config.language).then(() => Loader.loadModules()); await Translator.loadCoreTranslations(config.language);
await Loader.loadModules();
}, },
/** /**

View File

@ -25,7 +25,7 @@ const Module = Class.extend({
// visibility when hiding and showing module. // visibility when hiding and showing module.
lockStrings: [], lockStrings: [],
// Storage of the nunjuck Environment, // Storage of the nunjucks Environment,
// This should not be referenced directly. // This should not be referenced directly.
// Use the nunjucksEnvironment() to get it. // Use the nunjucksEnvironment() to get it.
_nunjucksEnvironment: null, _nunjucksEnvironment: null,
@ -302,7 +302,7 @@ const Module = Class.extend({
/** /**
* Load all translations. * Load all translations.
*/ */
async loadTranslations() { loadTranslations: async function () {
const translations = this.getTranslations() || {}; const translations = this.getTranslations() || {};
const language = config.language.toLowerCase(); const language = config.language.toLowerCase();

View File

@ -13,9 +13,8 @@ const NodeHelper = Class.extend({
Log.log("Initializing new module helper ..."); Log.log("Initializing new module helper ...");
}, },
loaded(callback) { loaded() {
Log.log(`Module helper loaded: ${this.name}`); Log.log(`Module helper loaded: ${this.name}`);
callback();
}, },
start() { start() {

View File

@ -9,6 +9,9 @@ const path = require("path");
const ipfilter = require("express-ipfilter").IpFilter; const ipfilter = require("express-ipfilter").IpFilter;
const fs = require("fs"); const fs = require("fs");
const helmet = require("helmet"); const helmet = require("helmet");
const socketio = require("socket.io");
const http = require("http");
const https = require("https");
const Log = require("logger"); const Log = require("logger");
const Utils = require("./utils.js"); const Utils = require("./utils.js");
@ -38,11 +41,11 @@ function Server(config) {
key: fs.readFileSync(config.httpsPrivateKey), key: fs.readFileSync(config.httpsPrivateKey),
cert: fs.readFileSync(config.httpsCertificate) cert: fs.readFileSync(config.httpsCertificate)
}; };
server = require("https").Server(options, app); server = https.Server(options, app);
} else { } else {
server = require("http").Server(app); server = http.Server(app);
} }
const io = require("socket.io")(server, { const io = socketio(server, {
cors: { cors: {
origin: /.*$/, origin: /.*$/,
credentials: true credentials: true

2191
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -51,31 +51,31 @@
"devDependencies": { "devDependencies": {
"eslint-config-prettier": "^8.6.0", "eslint-config-prettier": "^8.6.0",
"eslint-plugin-jest": "^27.2.1", "eslint-plugin-jest": "^27.2.1",
"eslint-plugin-jsdoc": "^39.8.0", "eslint-plugin-jsdoc": "^40.0.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"express-basic-auth": "^1.2.1", "express-basic-auth": "^1.2.1",
"husky": "^8.0.3", "husky": "^8.0.3",
"jest": "^29.4.2", "jest": "^29.4.3",
"jsdom": "^21.1.0", "jsdom": "^21.1.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"playwright": "^1.30.0", "playwright": "^1.31.1",
"prettier": "^2.8.4", "prettier": "^2.8.4",
"pretty-quick": "^3.1.3", "pretty-quick": "^3.1.3",
"sinon": "^15.0.1", "sinon": "^15.0.1",
"stylelint": "^15.1.0", "stylelint": "^15.2.0",
"stylelint-config-standard": "^30.0.1", "stylelint-config-standard": "^30.0.1",
"stylelint-prettier": "^2.0.0", "stylelint-prettier": "^3.0.0",
"suncalc": "^1.9.0" "suncalc": "^1.9.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"electron": "^22.2.0" "electron": "^22.3.1"
}, },
"dependencies": { "dependencies": {
"colors": "^1.4.0", "colors": "^1.4.0",
"console-stamp": "^3.1.0", "console-stamp": "^3.1.1",
"digest-fetch": "^2.0.1", "digest-fetch": "^2.0.1",
"envsub": "^4.1.0", "envsub": "^4.1.0",
"eslint": "^8.33.0", "eslint": "^8.35.0",
"express": "^4.18.2", "express": "^4.18.2",
"express-ipfilter": "^1.3.1", "express-ipfilter": "^1.3.1",
"feedme": "^2.0.2", "feedme": "^2.0.2",
@ -86,7 +86,7 @@
"moment": "^2.29.4", "moment": "^2.29.4",
"node-fetch": "^2.6.9", "node-fetch": "^2.6.9",
"node-ical": "^0.15.3", "node-ical": "^0.15.3",
"socket.io": "^4.6.0" "socket.io": "^4.6.1"
}, },
"_moduleAliases": { "_moduleAliases": {
"node_helper": "js/node_helper.js", "node_helper": "js/node_helper.js",

View File

@ -13,7 +13,7 @@ describe("Electron app environment", () => {
it("should open browserwindow", async () => { it("should open browserwindow", async () => {
const module = await helpers.getElement("#module_0_helloworld"); const module = await helpers.getElement("#module_0_helloworld");
expect(await module.textContent()).toContain("Test Display Header"); expect(await module.textContent()).toContain("Test Display Header");
expect(await global.electronApp.windows().length).toBe(1); expect(global.electronApp.windows().length).toBe(1);
}); });
}); });

18
vendor/package-lock.json generated vendored
View File

@ -9,7 +9,7 @@
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.3.0", "@fortawesome/fontawesome-free": "^6.3.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"moment-timezone": "^0.5.40", "moment-timezone": "^0.5.41",
"nunjucks": "^3.2.3", "nunjucks": "^3.2.3",
"suncalc": "^1.9.0", "suncalc": "^1.9.0",
"weathericons": "^2.1.0" "weathericons": "^2.1.0"
@ -51,11 +51,11 @@
} }
}, },
"node_modules/moment-timezone": { "node_modules/moment-timezone": {
"version": "0.5.40", "version": "0.5.41",
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.40.tgz", "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.41.tgz",
"integrity": "sha512-tWfmNkRYmBkPJz5mr9GVDn9vRlVZOTe6yqY92rFxiOdWXbjaR0+9LwQnZGGuNR63X456NqmEkbskte8tWL5ePg==", "integrity": "sha512-e0jGNZDOHfBXJGz8vR/sIMXvBIGJJcqFjmlg9lmE+5KX1U7/RZNMswfD8nKnNCnQdKTIj50IaRKwl1fvMLyyRg==",
"dependencies": { "dependencies": {
"moment": ">= 2.9.0" "moment": "^2.29.4"
}, },
"engines": { "engines": {
"node": "*" "node": "*"
@ -123,11 +123,11 @@
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
}, },
"moment-timezone": { "moment-timezone": {
"version": "0.5.40", "version": "0.5.41",
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.40.tgz", "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.41.tgz",
"integrity": "sha512-tWfmNkRYmBkPJz5mr9GVDn9vRlVZOTe6yqY92rFxiOdWXbjaR0+9LwQnZGGuNR63X456NqmEkbskte8tWL5ePg==", "integrity": "sha512-e0jGNZDOHfBXJGz8vR/sIMXvBIGJJcqFjmlg9lmE+5KX1U7/RZNMswfD8nKnNCnQdKTIj50IaRKwl1fvMLyyRg==",
"requires": { "requires": {
"moment": ">= 2.9.0" "moment": "^2.29.4"
} }
}, },
"nunjucks": { "nunjucks": {

2
vendor/package.json vendored
View File

@ -12,7 +12,7 @@
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.3.0", "@fortawesome/fontawesome-free": "^6.3.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"moment-timezone": "^0.5.40", "moment-timezone": "^0.5.41",
"nunjucks": "^3.2.3", "nunjucks": "^3.2.3",
"suncalc": "^1.9.0", "suncalc": "^1.9.0",
"weathericons": "^2.1.0" "weathericons": "^2.1.0"