Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup more callback things #3051

Merged
merged 13 commits into from
Feb 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@ _This release is scheduled to be released on 2023-04-01._
- Update dates in Calendar widgets every minute
- Cleanup jest coverage for patches
- Update `stylelint` dependencies, switch to `stylelint-config-standard` and handle `stylelint` issues
- Convert load callbacks to async/await
- Convert module start to async/await
- Convert translator callbacks to async/await
- Convert app-start/-stop callbacks to async/awaits
- Convert lots of callbacks to async/await

### Fixed

Expand Down
95 changes: 45 additions & 50 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,8 @@ function App() {
* Loads a specific module.
*
* @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 moduleName = elements[elements.length - 1];
let moduleFolder = `${__dirname}/../modules/${module}`;
Expand Down Expand Up @@ -199,39 +198,37 @@ function App() {
m.setPath(path.resolve(moduleFolder));
nodeHelpers.push(m);

m.loaded(callback);
} else {
callback();
m.loaded();
}
}

/**
* Loads all modules.
*
* @param {Module[]} modules All modules to be loaded
* @param {Function} callback Function to be called after loading
* @param {string[]} modules All modules to be loaded
*/
function loadModules(modules, callback) {
Log.log("Loading module helpers ...");

/**
*
*/
function loadNextModule() {
if (modules.length > 0) {
const nextModule = modules[0];
loadModule(nextModule, function () {
async function loadModules(modules) {
return new Promise((resolve) => {
Log.log("Loading module helpers ...");

/**
*
*/
function loadNextModule() {
if (modules.length > 0) {
const nextModule = modules[0];
loadModule(nextModule);
modules = modules.slice(1);
loadNextModule();
});
} else {
// All modules are loaded
Log.log("All module helpers loaded.");
callback();
} else {
// All modules are loaded
Log.log("All module helpers loaded.");
resolve();
}
}
}

loadNextModule();
loadNextModule();
});
}

/**
Expand Down Expand Up @@ -272,43 +269,41 @@ function App() {
Log.setLogLevel(config.logLevel);

let modules = [];

for (const module of config.modules) {
if (!modules.includes(module.module) && !module.disabled) {
modules.push(module.module);
}
}
await loadModules(modules);

loadModules(modules, async function () {
httpServer = new Server(config);
const { app, io } = await httpServer.open();
Log.log("Server started ...");

const nodePromises = [];
for (let nodeHelper of nodeHelpers) {
nodeHelper.setExpressApp(app);
nodeHelper.setSocketIO(io);

try {
nodePromises.push(nodeHelper.start());
} catch (error) {
Log.error(`Error when starting node_helper for module ${nodeHelper.name}:`);
Log.error(error);
}
}
httpServer = new Server(config);
const { app, io } = await httpServer.open();
Log.log("Server started ...");

const results = await Promise.allSettled(nodePromises);
const nodePromises = [];
for (let nodeHelper of nodeHelpers) {
nodeHelper.setExpressApp(app);
nodeHelper.setSocketIO(io);

// Log errors that happened during async node_helper startup
results.forEach((result) => {
if (result.status === "rejected") {
Log.error(result.reason);
}
});
try {
nodePromises.push(nodeHelper.start());
} catch (error) {
Log.error(`Error when starting node_helper for module ${nodeHelper.name}:`);
Log.error(error);
}
}

const results = await Promise.allSettled(nodePromises);

Log.log("Sockets connected & modules started ...");
// Log errors that happened during async node_helper startup
results.forEach((result) => {
if (result.status === "rejected") {
Log.error(result.reason);
}
});

Log.log("Sockets connected & modules started ...");

return config;
};

Expand Down
141 changes: 64 additions & 77 deletions js/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,9 @@ const Loader = (function () {
/* 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 () {
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 startModules = async function () {
const modulePromises = [];
for (const module of moduleObjects) {
try {
Expand All @@ -57,25 +29,25 @@ const Loader = (function () {
}
}

Promise.allSettled(modulePromises).then((results) => {
// Log errors that happened during async node_helper startup
results.forEach((result) => {
if (result.status === "rejected") {
Log.error(result.reason);
}
});

// Notify core of loaded modules.
MM.modulesStarted(moduleObjects);
const results = await Promise.allSettled(modulePromises);

// Starting modules also hides any modules that have requested to be initially hidden
for (const thisModule of moduleObjects) {
if (thisModule.data.hiddenOnStartup) {
Log.info("Initially hiding " + thisModule.name);
thisModule.hide();
}
// Log errors that happened during async node_helper startup
results.forEach((result) => {
if (result.status === "rejected") {
Log.error(result.reason);
}
});

// Notify core of loaded modules.
MM.modulesStarted(moduleObjects);

// Starting modules also hides any modules that have requested to be initially hidden
for (const thisModule of moduleObjects) {
if (thisModule.data.hiddenOnStartup) {
Log.info("Initially hiding " + thisModule.name);
thisModule.hide();
}
}
};

/**
Expand Down Expand Up @@ -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 {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 afterLoad = function () {
/**
* @returns {Promise<void>}
*/
const afterLoad = async function () {
const moduleObject = Module.create(module.name);
if (moduleObject) {
bootstrapModule(module, moduleObject, function () {
callback();
});
} else {
callback();
await bootstrapModule(module, moduleObject);
}
};

if (loadedModuleFiles.indexOf(url) !== -1) {
afterLoad();
await afterLoad();
} else {
loadFile(url).then(() => {
loadedModuleFiles.push(url);
afterLoad();
});
await loadFile(url);
loadedModuleFiles.push(url);
await afterLoad();
}
};

Expand All @@ -164,24 +134,21 @@ const Loader = (function () {
*
* @param {object} module Information about the module we want to load.
* @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);

mObj.setData(module);

mObj.loadScripts().then(() => {
Log.log("Scripts loaded for: " + module.name);
mObj.loadStyles().then(() => {
Log.log("Styles loaded for: " + module.name);
mObj.loadTranslations().then(() => {
Log.log("Translations loaded for: " + module.name);
moduleObjects.push(mObj);
callback();
});
});
});
await mObj.loadScripts();
Log.log("Scripts loaded for: " + module.name);

await mObj.loadStyles();
Log.log("Styles loaded for: " + module.name);

await mObj.loadTranslations();
Log.log("Translations loaded for: " + module.name);

moduleObjects.push(mObj);
};

/**
Expand Down Expand Up @@ -235,8 +202,28 @@ const Loader = (function () {
/**
* Load all modules as defined in the config.
*/
loadModules: function () {
loadModules();
loadModules: async function () {
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();
},

/**
Expand All @@ -250,7 +237,7 @@ const Loader = (function () {
loadFileForModule: async function (fileName, module) {
if (loadedFiles.indexOf(fileName.toLowerCase()) !== -1) {
Log.log("File already loaded: " + fileName);
return Promise.resolve();
return;
}

if (fileName.indexOf("http://") === 0 || fileName.indexOf("https://") === 0 || fileName.indexOf("/") !== -1) {
Expand Down
5 changes: 3 additions & 2 deletions js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -479,13 +479,14 @@ const MM = (function () {
/**
* Main init method.
*/
init: function () {
init: async function () {
Log.info("Initializing MagicMirror².");
loadConfig();

Log.setLogLevel(config.logLevel);

Translator.loadCoreTranslations(config.language).then(() => Loader.loadModules());
await Translator.loadCoreTranslations(config.language);
await Loader.loadModules();
},

/**
Expand Down
4 changes: 2 additions & 2 deletions js/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const Module = Class.extend({
// visibility when hiding and showing module.
lockStrings: [],

// Storage of the nunjuck Environment,
// Storage of the nunjucks Environment,
// This should not be referenced directly.
// Use the nunjucksEnvironment() to get it.
_nunjucksEnvironment: null,
Expand Down Expand Up @@ -302,7 +302,7 @@ const Module = Class.extend({
/**
* Load all translations.
*/
async loadTranslations() {
loadTranslations: async function () {
const translations = this.getTranslations() || {};
const language = config.language.toLowerCase();

Expand Down
3 changes: 1 addition & 2 deletions js/node_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ const NodeHelper = Class.extend({
Log.log("Initializing new module helper ...");
},

loaded(callback) {
loaded() {
Log.log(`Module helper loaded: ${this.name}`);
callback();
},

start() {
Expand Down
Loading