From ed701dff392857f374186fd1d0b4cd8e197f16c7 Mon Sep 17 00:00:00 2001 From: Ryan Blenis Date: Tue, 5 Nov 2019 00:11:14 -0500 Subject: [PATCH] Promisifying and error handling --- meshuser.js | 18 +++++- pluginHandler.js | 122 ++++++++++++++++++++++----------------- public/styles/style.css | 7 +++ views/default.handlebars | 16 ++++- 4 files changed, 106 insertions(+), 57 deletions(-) diff --git a/meshuser.js b/meshuser.js index 05f0e9b6..a99dc670 100644 --- a/meshuser.js +++ b/meshuser.js @@ -3122,14 +3122,28 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'pluginLatestCheck': { if ((user.siteadmin & 0xFFFFFFFF) == 0 || parent.parent.pluginHandler == null) break; // must be full admin with plugins enabled - parent.parent.pluginHandler.getPluginLatest(function(latest) { + parent.parent.pluginHandler.getPluginLatest() + .then(function(latest) { try { ws.send(JSON.stringify({ action: 'pluginVersionsAvailable', list: latest })); } catch (ex) { } }); break; } case 'addplugin': { if ((user.siteadmin & 0xFFFFFFFF) == 0 || parent.parent.pluginHandler == null) break; // must be full admin, plugins enabled - parent.parent.pluginHandler.addPlugin(command.url); + try { + //parent.parent.pluginHandler.addPlugin(command.url) + parent.parent.pluginHandler.getPluginConfig(command.url) + .then(parent.parent.pluginHandler.addPlugin) + .then(function(docs){ console.log('landed'); + var targets = ['*', 'server-users']; + parent.parent.DispatchEvent(targets, obj, { action: 'updatePluginList', list: docs }); + }) + .catch(function(err) { + if (typeof err == 'object') err = err.message; + try { ws.send(JSON.stringify({ action: 'pluginError', msg: err })); } catch (er) { } + }); + + } catch(e) { console.log('Cannot add plugin: ' + e); } break; } case 'installplugin': { diff --git a/pluginHandler.js b/pluginHandler.js index 92cb9b10..7ea2c6e5 100644 --- a/pluginHandler.js +++ b/pluginHandler.js @@ -13,6 +13,7 @@ /*jshint strict: false */ /*jshint esversion: 6 */ "use strict"; +require('promise'); module.exports.pluginHandler = function (parent) { var obj = {}; @@ -214,54 +215,72 @@ module.exports.pluginHandler = function (parent) { return plugins; } - obj.getPluginConfig = function(configUrl, func) { - var https = require('https'); - if (configUrl.indexOf('://') === -1) return; // @TODO error here - https.get(configUrl, function(res) { - var configStr = ''; - res.on('data', function(chunk){ - configStr += chunk; - }); - res.on('end', function(){ - if (configStr[0] == '{') { // let's be sure we're JSON - try { - var pluginConfig = JSON.parse(configStr); - if (Array.isArray(pluginConfig) && pluginConfig.length == 1) pluginConfig = pluginConfig[0]; - if (obj.isValidConfig(pluginConfig, configUrl)) { - func(pluginConfig); - } - - } catch (e) { console.log('Error getting plugin config. Check that you have valid JSON.', e.stack); } - } - }); - - }).on('error', function(e) { - console.log("Error getting plugin config. Check that the URL is correct.: " + e.message); - }); - }; - - obj.getPluginLatest = function(func) { - parent.db.getPlugins(function(err, plugins){ - plugins.forEach(function(curconf){ - obj.getPluginConfig(curconf.configUrl, function(newconf){ - var s = require('semver'); - func({ - "id": curconf._id, - "installedVersion": curconf.version, - "version": newconf.version, - "hasUpdate": s.gt(newconf.version, curconf.version), - "meshCentralCompat": s.satisfies(s.coerce(parent.currentVer), newconf.meshCentralCompat), - "changelogUrl": curconf.changelogUrl, - "status": curconf.status - }); + obj.getPluginConfig = function(configUrl) { + return new Promise(function(resolve, reject) { + var https = require('https'); + if (configUrl.indexOf('://') === -1) reject('Unable to fetch the config: Bad URL (' + configUrl + ')'); + https.get(configUrl, function(res) { + var configStr = ''; + res.on('data', function(chunk){ + configStr += chunk; }); - }); - }); - + res.on('end', function(){ + if (configStr[0] == '{') { // let's be sure we're JSON + try { + var pluginConfig = JSON.parse(configStr); + if (Array.isArray(pluginConfig) && pluginConfig.length == 1) pluginConfig = pluginConfig[0]; + if (obj.isValidConfig(pluginConfig, configUrl)) { + resolve(pluginConfig); + } else { + reject("This does not appear to be a valid plugin configuration."); + } + + } catch (e) { reject('Error getting plugin config. Check that you have valid JSON.'); } + } else { + reject('Error getting plugin config. Check that you have valid JSON.'); + } + }); + + }).on('error', function(e) { + reject("Error getting plugin config: " + e.message); + }); + }) }; - obj.addPlugin = function(url) { - obj.getPluginConfig(url, function(pluginConfig){ + obj.getPluginLatest = function() { + return new Promise(function(resolve, reject) { + parent.db.getPlugins(function(err, plugins) { + var proms = []; + plugins.forEach(function(curconf) { + proms.push(obj.getPluginConfig(curconf.configUrl)); + }); + var latestRet = []; + Promise.all(proms).then(function(newconfs) { + newconfs.forEach(function(newconf) { + var curconf = null; + plugins.forEach(function(conf) { + if (conf.configUrl == newconf.configUrl) curconf = conf; + }); + if (curconf == null) reject('Some plugin configs could not be parsed'); + var s = require('semver'); + latestRet.push({ + "id": curconf._id, + "installedVersion": curconf.version, + "version": newconf.version, + "hasUpdate": s.gt(newconf.version, curconf.version), + "meshCentralCompat": s.satisfies(s.coerce(parent.currentVer), newconf.meshCentralCompat), + "changelogUrl": curconf.changelogUrl, + "status": curconf.status + }); + resolve(latestRet); + }); + }).catch((e) => { console.log('Error reaching plugins, update call aborted. ', e)}); + }); + }); + }; + + obj.addPlugin = function(pluginConfig) { + return new Promise(function(resolve, reject) { parent.db.addPlugin({ "name": pluginConfig.name, "shortName": pluginConfig.shortName, @@ -279,13 +298,12 @@ module.exports.pluginHandler = function (parent) { "meshCentralCompat": pluginConfig.meshCentralCompat, "status": 0 // 0: disabled, 1: enabled }, function() { - parent.db.getPlugins(function(err, docs){ - var targets = ['*', 'server-users']; - parent.DispatchEvent(targets, obj, { action: 'updatePluginList', list: docs }); - - }); - }); - }); + parent.db.getPlugins(function(err, docs){ + if (err) reject(err); + else resolve(docs); + }); + }); + }); }; obj.installPlugin = function(id, func) { diff --git a/public/styles/style.css b/public/styles/style.css index 11d42602..6bbb2ca1 100644 --- a/public/styles/style.css +++ b/public/styles/style.css @@ -2653,6 +2653,13 @@ a { position: absolute; cursor: pointer; /* Add a pointer on hover */ } +.pluginOverlayContent { + width: 100%; /* Full width (cover the whole page) */ + height: 100%; /* Full height (cover the whole page) */ + background-color: #FFFFFF; /* Black background with opacity */ + z-index: 2; /* Specify a stack order in case you're using a different order for other elements */ + position: relative; +} .pluginTitleBar { padding: 4px; diff --git a/views/default.handlebars b/views/default.handlebars index 5817821d..6ca4b87b 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -2368,6 +2368,10 @@ updatePluginList(message.list); break; } + case 'pluginError': { + setDialogMode(2, 'Oops!', 1, null, message.msg); + break; + } case 'plugin': { if ((pluginHandler == null) || (typeof message.plugin != 'string')) break; try { pluginHandler[message.plugin][message.method](server, message); } catch (e) { console.log('Error loading plugin handler ('+ e + ')'); } @@ -9419,6 +9423,9 @@ } function updatePluginList(versInfo) { + if (Array.isArray(versInfo)) { + versInfo.forEach(function(v) { updatePluginList(v); }); + } if (installedPluginList.length) { if (versInfo != null) { if (installedPluginList['version_info'] == null) installedPluginList['version_info'] = []; @@ -9479,6 +9486,7 @@ if (!vin.meshCentralCompat) { p.upgradeAvail += vers_not_compat; cant_action.push('install'); + cant_action.push('upgrade'); } } @@ -9533,8 +9541,9 @@ } function goPlugin(pname, title) { - let xwin = `
${title}
` + let xwin = `
${title}
`; let dif = document.createElement('div'); + let cdif = document.createElement('div'); dif.classList.add('pluginOverlay'); dif.innerHTML = xwin; let pif = document.createElement('iframe'); @@ -9543,8 +9552,9 @@ pif.style.width = '100%'; pif.style.height = '100%'; pif.setAttribute('frameBorder', '0'); - - dif.append(pif); + cdif.classList.add('pluginOverlayContent'); + cdif.append(pif); + dif.append(cdif); let x = Q('p7'); x.parentNode.insertBefore(dif, x.nextSibling); Q('p7').classList.add('pluginOverlayBg');