diff --git a/CHANGELOG b/CHANGELOG index 420f5aab10a202c21949d790756188d6e6d26855..08487c32b0c65e351a7a3ce5be0dbc8008fe2d9e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -31,6 +31,8 @@ minerva (12.3.0~alpha.0) unstable; urgency=low (#591) * Small improvement: uploading sbml file should automatically discover a file type (#784) + * Small improvement: when plugin listeners crash the system notifies user + about problem with a plugin (#767) * Bug fix: progress bar of gene genome mapping upload is refreshing properly (#728) * Bug fix: when editing project Disease and Organism could not be removed diff --git a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js index 1e1b8673c49f6690f59252f2a1227e5de4b89185..feb8595972e90ab798740266b46cb9be27baf90a 100644 --- a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js +++ b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js @@ -12,6 +12,8 @@ var Configuration = require('../Configuration'); var Bounds = require('../map/canvas/Bounds'); var Point = require('../map/canvas/Point'); +var GuiConnector = require('../GuiConnector'); + // noinspection JSUnusedLocalSymbols var logger = require('../logger'); @@ -453,7 +455,7 @@ function createProjectMap(options) { return dbOverlay.searchByQuery(params.query, params.perfect, params.fitBounds); } else if (dbOverlay instanceof SearchDbOverlay) { var zoom = params.zoom; - if (zoom ===undefined) { + if (zoom === undefined) { zoom = map.getSubmapById(params.modelId).getZoom(); } return dbOverlay.searchByCoordinates({ @@ -582,10 +584,26 @@ function createProjectMap(options) { throw new Error("Invalid argument"); } + var wrapper = function (e) { + try { + return Promise.resolve(listenerWrapper(e)).catch(function (error) { + GuiConnector.warn("Plugin " + options.plugin.getName() + " crashed"); + if (typeof options.plugin.getLoadedPluginData().notifyError === "function") { + options.plugin.getLoadedPluginData().notifyError({listener: param, data: e, error: error}); + } + }); + } catch (error) { + GuiConnector.warn("Plugin " + options.plugin.getName() + " crashed"); + if (typeof options.plugin.getLoadedPluginData().notifyError === "function") { + options.plugin.getLoadedPluginData().notifyError({listener: param, data: e, error: error}); + } + } + }; + for (var i = 0; i < objects.length; i++) { var object = objects[i]; - object.addListener(listenerType, listenerWrapper); - listenersData.push({listener: param.callback, wrapper: listenerWrapper, object: object, type: listenerType}); + object.addListener(listenerType, wrapper); + listenersData.push({listener: param.callback, wrapper: wrapper, object: object, type: listenerType}); } }, /** diff --git a/frontend-js/src/main/js/plugin/Plugin.js b/frontend-js/src/main/js/plugin/Plugin.js index 409d9d68c786c6a3d4c699f794906bad21fd5e82..c513e2839d1593b6869f83a2809ab84d84f8bcea 100644 --- a/frontend-js/src/main/js/plugin/Plugin.js +++ b/frontend-js/src/main/js/plugin/Plugin.js @@ -24,6 +24,7 @@ var pluginId = 0; * @typedef {Object} UserPluginObject * @property {function(Object):void} register * @property {function():void} unregister + * @property {function(Object):void} [notifyError] * @property {function():string} getName * @property {function():string} getVersion * @property {function():(number|string)|number|string} minWidth diff --git a/frontend-js/src/test/js/plugin/Plugin-test.js b/frontend-js/src/test/js/plugin/Plugin-test.js index adbf4c968546a73102228882c0480cf9a0b01b82..ac0671033a85d53c8e44fbb8640e8db75bcb4950 100644 --- a/frontend-js/src/test/js/plugin/Plugin-test.js +++ b/frontend-js/src/test/js/plugin/Plugin-test.js @@ -5,6 +5,7 @@ require("../mocha-config"); // noinspection JSUnusedLocalSymbols var Promise = require("bluebird"); var Plugin = require('../../../main/js/plugin/Plugin'); +var Point = require('../../../main/js/map/canvas/Point'); var ServerConnector = require('../ServerConnector-mock'); var logger = require('../logger'); @@ -106,4 +107,14 @@ describe('Plugin', function () { }); }); }); + it('plugin listener crash', function () { + var map = helper.createCustomMap(); + + var plugin = createPlugin("./testFiles/plugin/listener-crash.js", map); + return plugin.load().then(function () { + return map.callListeners("onCenterChanged", new Point(0, 0)); + }).then(function () { + assert.equal(1, logger.getWarnings().length); + }); + }); }); diff --git a/frontend-js/testFiles/apiCalls/plugins/POST_hash=a794c40b7ed8f56406f66f2913543915&isPublic=false&name=test%20plugin&url=.%2FtestFiles%2Fplugin%2Flistener-crash.js&version=0.0.1&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/plugins/POST_hash=a794c40b7ed8f56406f66f2913543915&isPublic=false&name=test%20plugin&url=.%2FtestFiles%2Fplugin%2Flistener-crash.js&version=0.0.1&token=MOCK_TOKEN_ID& new file mode 100644 index 0000000000000000000000000000000000000000..02a0838194fc09c68eaaced9fc942eea364ac0ba --- /dev/null +++ b/frontend-js/testFiles/apiCalls/plugins/POST_hash=a794c40b7ed8f56406f66f2913543915&isPublic=false&name=test%20plugin&url=.%2FtestFiles%2Fplugin%2Flistener-crash.js&version=0.0.1&token=MOCK_TOKEN_ID& @@ -0,0 +1,8 @@ +{ + "hash": "d5d652ac0e0f6467d4cb6a742f99d3f7", + "name": "test plugin", + "urls": [ + "./testFiles/plugin-invalid/invalid_register.js" + ], + "version": "0.0.1" +} \ No newline at end of file diff --git a/frontend-js/testFiles/plugin/listener-crash.js b/frontend-js/testFiles/plugin/listener-crash.js new file mode 100644 index 0000000000000000000000000000000000000000..d93a9d0a8921a758e1c04fb4f72989d1e879586f --- /dev/null +++ b/frontend-js/testFiles/plugin/listener-crash.js @@ -0,0 +1,23 @@ +minervaDefine(function () { + return { + register: function (minervaObject) { + var options = { + object: "map", + type: "onCenterChanged", + callback: function () { + throw new Error("Let's crash"); + } + }; + minervaObject.project.map.addListener(options); + }, + unregister: function () { + console.log("unregistering test plugin"); + }, + getName: function () { + return "test plugin"; + }, + getVersion: function () { + return "0.0.1"; + } + }; +}); \ No newline at end of file