Promisifying and error handling

Ryan Blenis committed Nov 5, 2019 at 00:11 UTC ed701dff392857f374186fd1d0b4cd8e197f16c7
4 files changed +104 -55
meshuser.js
+16 -2
@@ -3122,14 +3122,28 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3122 }
3123 case 'pluginLatestCheck': {
3124 if ((user.siteadmin & 0xFFFFFFFF) == 0 || parent.parent.pluginHandler == null) break; // must be full admin with plugins enabled
3125 - parent.parent.pluginHandler.getPluginLatest(function(latest) {
3125 + parent.parent.pluginHandler.getPluginLatest()
3126 + .then(function(latest) {
3127 try { ws.send(JSON.stringify({ action: 'pluginVersionsAvailable', list: latest })); } catch (ex) { }
3128 });
3129 break;
3130 }
3131 case 'addplugin': {
3132 if ((user.siteadmin & 0xFFFFFFFF) == 0 || parent.parent.pluginHandler == null) break; // must be full admin, plugins enabled
3132 - parent.parent.pluginHandler.addPlugin(command.url);
3133 + try {
3134 + //parent.parent.pluginHandler.addPlugin(command.url)
3135 + parent.parent.pluginHandler.getPluginConfig(command.url)
3136 + .then(parent.parent.pluginHandler.addPlugin)
3137 + .then(function(docs){ console.log('landed');
3138 + var targets = ['*', 'server-users'];
3139 + parent.parent.DispatchEvent(targets, obj, { action: 'updatePluginList', list: docs });
3140 + })
3141 + .catch(function(err) {
3142 + if (typeof err == 'object') err = err.message;
3143 + try { ws.send(JSON.stringify({ action: 'pluginError', msg: err })); } catch (er) { }
3144 + });
3145 +
3146 + } catch(e) { console.log('Cannot add plugin: ' + e); }
3147 break;
3148 }
3149 case 'installplugin': {
pluginHandler.js
+68 -50
@@ -13,6 +13,7 @@
13 /*jshint strict: false */
14 /*jshint esversion: 6 */
15 "use strict";
16 +require('promise');
17
18 module.exports.pluginHandler = function (parent) {
19 var obj = {};
@@ -214,54 +215,72 @@ module.exports.pluginHandler = function (parent) {
215 return plugins;
216 }
217
217 - obj.getPluginConfig = function(configUrl, func) {
218 - var https = require('https');
219 - if (configUrl.indexOf('://') === -1) return; // @TODO error here
220 - https.get(configUrl, function(res) {
221 - var configStr = '';
222 - res.on('data', function(chunk){
223 - configStr += chunk;
224 - });
225 - res.on('end', function(){
226 - if (configStr[0] == '{') { // let's be sure we're JSON
227 - try {
228 - var pluginConfig = JSON.parse(configStr);
229 - if (Array.isArray(pluginConfig) && pluginConfig.length == 1) pluginConfig = pluginConfig[0];
230 - if (obj.isValidConfig(pluginConfig, configUrl)) {
231 - func(pluginConfig);
232 - }
233 -
234 - } catch (e) { console.log('Error getting plugin config. Check that you have valid JSON.', e.stack); }
235 - }
236 - });
237 -
238 - }).on('error', function(e) {
239 - console.log("Error getting plugin config. Check that the URL is correct.: " + e.message);
240 - });
218 + obj.getPluginConfig = function(configUrl) {
219 + return new Promise(function(resolve, reject) {
220 + var https = require('https');
221 + if (configUrl.indexOf('://') === -1) reject('Unable to fetch the config: Bad URL (' + configUrl + ')');
222 + https.get(configUrl, function(res) {
223 + var configStr = '';
224 + res.on('data', function(chunk){
225 + configStr += chunk;
226 + });
227 + res.on('end', function(){
228 + if (configStr[0] == '{') { // let's be sure we're JSON
229 + try {
230 + var pluginConfig = JSON.parse(configStr);
231 + if (Array.isArray(pluginConfig) && pluginConfig.length == 1) pluginConfig = pluginConfig[0];
232 + if (obj.isValidConfig(pluginConfig, configUrl)) {
233 + resolve(pluginConfig);
234 + } else {
235 + reject("This does not appear to be a valid plugin configuration.");
236 + }
237 +
238 + } catch (e) { reject('Error getting plugin config. Check that you have valid JSON.'); }
239 + } else {
240 + reject('Error getting plugin config. Check that you have valid JSON.');
241 + }
242 + });
243 +
244 + }).on('error', function(e) {
245 + reject("Error getting plugin config: " + e.message);
246 + });
247 + })
248 };
249
243 - obj.getPluginLatest = function(func) {
244 - parent.db.getPlugins(function(err, plugins){
245 - plugins.forEach(function(curconf){
246 - obj.getPluginConfig(curconf.configUrl, function(newconf){
247 - var s = require('semver');
248 - func({
249 - "id": curconf._id,
250 - "installedVersion": curconf.version,
251 - "version": newconf.version,
252 - "hasUpdate": s.gt(newconf.version, curconf.version),
253 - "meshCentralCompat": s.satisfies(s.coerce(parent.currentVer), newconf.meshCentralCompat),
254 - "changelogUrl": curconf.changelogUrl,
255 - "status": curconf.status
256 - });
257 - });
258 - });
250 + obj.getPluginLatest = function() {
251 + return new Promise(function(resolve, reject) {
252 + parent.db.getPlugins(function(err, plugins) {
253 + var proms = [];
254 + plugins.forEach(function(curconf) {
255 + proms.push(obj.getPluginConfig(curconf.configUrl));
256 + });
257 + var latestRet = [];
258 + Promise.all(proms).then(function(newconfs) {
259 + newconfs.forEach(function(newconf) {
260 + var curconf = null;
261 + plugins.forEach(function(conf) {
262 + if (conf.configUrl == newconf.configUrl) curconf = conf;
263 + });
264 + if (curconf == null) reject('Some plugin configs could not be parsed');
265 + var s = require('semver');
266 + latestRet.push({
267 + "id": curconf._id,
268 + "installedVersion": curconf.version,
269 + "version": newconf.version,
270 + "hasUpdate": s.gt(newconf.version, curconf.version),
271 + "meshCentralCompat": s.satisfies(s.coerce(parent.currentVer), newconf.meshCentralCompat),
272 + "changelogUrl": curconf.changelogUrl,
273 + "status": curconf.status
274 + });
275 + resolve(latestRet);
276 + });
277 + }).catch((e) => { console.log('Error reaching plugins, update call aborted. ', e)});
278 + });
279 });
260 -
280 };
281
263 - obj.addPlugin = function(url) {
264 - obj.getPluginConfig(url, function(pluginConfig){
282 + obj.addPlugin = function(pluginConfig) {
283 + return new Promise(function(resolve, reject) {
284 parent.db.addPlugin({
285 "name": pluginConfig.name,
286 "shortName": pluginConfig.shortName,
@@ -279,13 +298,12 @@ module.exports.pluginHandler = function (parent) {
298 "meshCentralCompat": pluginConfig.meshCentralCompat,
299 "status": 0 // 0: disabled, 1: enabled
300 }, function() {
282 - parent.db.getPlugins(function(err, docs){
283 - var targets = ['*', 'server-users'];
284 - parent.DispatchEvent(targets, obj, { action: 'updatePluginList', list: docs });
285 -
286 - });
287 - });
288 - });
301 + parent.db.getPlugins(function(err, docs){
302 + if (err) reject(err);
303 + else resolve(docs);
304 + });
305 + });
306 + });
307 };
308
309 obj.installPlugin = function(id, func) {
public/styles/style.css
+7
@@ -2653,6 +2653,13 @@ a {
2653 position: absolute;
2654 cursor: pointer; /* Add a pointer on hover */
2655 }
2656 +.pluginOverlayContent {
2657 + width: 100%; /* Full width (cover the whole page) */
2658 + height: 100%; /* Full height (cover the whole page) */
2659 + background-color: #FFFFFF; /* Black background with opacity */
2660 + z-index: 2; /* Specify a stack order in case you're using a different order for other elements */
2661 + position: relative;
2662 +}
2663
2664 .pluginTitleBar {
2665 padding: 4px;
views/default.handlebars
+13 -3
@@ -2368,6 +2368,10 @@
2368 updatePluginList(message.list);
2369 break;
2370 }
2371 + case 'pluginError': {
2372 + setDialogMode(2, 'Oops!', 1, null, message.msg);
2373 + break;
2374 + }
2375 case 'plugin': {
2376 if ((pluginHandler == null) || (typeof message.plugin != 'string')) break;
2377 try { pluginHandler[message.plugin][message.method](server, message); } catch (e) { console.log('Error loading plugin handler ('+ e + ')'); }
@@ -9419,6 +9423,9 @@
9423 }
9424
9425 function updatePluginList(versInfo) {
9426 + if (Array.isArray(versInfo)) {
9427 + versInfo.forEach(function(v) { updatePluginList(v); });
9428 + }
9429 if (installedPluginList.length) {
9430 if (versInfo != null) {
9431 if (installedPluginList['version_info'] == null) installedPluginList['version_info'] = [];
@@ -9479,6 +9486,7 @@
9486 if (!vin.meshCentralCompat) {
9487 p.upgradeAvail += vers_not_compat;
9488 cant_action.push('install');
9489 + cant_action.push('upgrade');
9490 }
9491 }
9492
@@ -9533,8 +9541,9 @@
9541 }
9542
9543 function goPlugin(pname, title) {
9536 - let xwin = `<div class="pluginTitleBar"><span>${title}</span><span class="pluginCloseBtn"><button onclick="return noGoPlugin(this);">X</button></span></div>`
9544 + let xwin = `<div class="pluginTitleBar"><span>${title}</span><span class="pluginCloseBtn"><button onclick="return noGoPlugin(this);">X</button></span></div>`;
9545 let dif = document.createElement('div');
9546 + let cdif = document.createElement('div');
9547 dif.classList.add('pluginOverlay');
9548 dif.innerHTML = xwin;
9549 let pif = document.createElement('iframe');
@@ -9543,8 +9552,9 @@
9552 pif.style.width = '100%';
9553 pif.style.height = '100%';
9554 pif.setAttribute('frameBorder', '0');
9546 -
9547 - dif.append(pif);
9555 + cdif.classList.add('pluginOverlayContent');
9556 + cdif.append(pif);
9557 + dif.append(cdif);
9558 let x = Q('p7');
9559 x.parentNode.insertBefore(dif, x.nextSibling);
9560 Q('p7').classList.add('pluginOverlayBg');