diff --git a/src/core/operations/Hexdump.js b/src/core/operations/Hexdump.js index 94014fed..c05a9139 100755 --- a/src/core/operations/Hexdump.js +++ b/src/core/operations/Hexdump.js @@ -92,7 +92,7 @@ const Hexdump = { const w = (width - 13) / 4; // w should be the specified width of the hexdump and therefore a round number if (Math.floor(w) !== w || input.indexOf("\r") !== -1 || output.indexOf(13) !== -1) { - if (app) app.options.attemptHighlight = false; + if (self) self.setOption("attemptHighlight", false); } return output; }, diff --git a/src/web/App.js b/src/web/App.js index 797372ce..e96dafcf 100755 --- a/src/web/App.js +++ b/src/web/App.js @@ -1,5 +1,4 @@ import Utils from "../core/Utils.js"; -import ChefWorker from "worker-loader?inline&fallback=false!../core/ChefWorker.js"; import Manager from "./Manager.js"; import HTMLCategory from "./HTMLCategory.js"; import HTMLOperation from "./HTMLOperation.js"; @@ -44,7 +43,6 @@ const App = function(categories, operations, defaultFavourites, defaultOptions) */ App.prototype.setup = function() { document.dispatchEvent(this.manager.appstart); - this.registerChefWorker(); this.initialiseSplitter(); this.loadLocalStorage(); this.populateOperationsList(); @@ -58,22 +56,6 @@ App.prototype.setup = function() { }; -/** - * Sets up the ChefWorker and associated listeners. - */ -App.prototype.registerChefWorker = function() { - this.chefWorker = new ChefWorker(); - this.chefWorker.addEventListener("message", this.handleChefMessage.bind(this)); - - let docURL = document.location.href.split(/[#?]/)[0]; - const index = docURL.lastIndexOf("/"); - if (index > 0) { - docURL = docURL.substring(0, index); - } - this.chefWorker.postMessage({"action": "docURL", "data": docURL}); -}; - - /** * Fires once all setup activities have completed. * @@ -114,18 +96,6 @@ App.prototype.handleError = function(err) { }; -/** - * Updates the UI to show if baking is in process or not. - * - * @param {bakingStatus} - */ -App.prototype.setBakingStatus = function(bakingStatus) { - this.baking = bakingStatus; - - this.manager.output.toggleLoader(bakingStatus); -}; - - /** * Asks the ChefWorker to bake the current input using the current recipe. * @@ -135,81 +105,13 @@ App.prototype.setBakingStatus = function(bakingStatus) { App.prototype.bake = function(step) { if (this.baking) return; - this.setBakingStatus(true); - - this.chefWorker.postMessage({ - action: "bake", - data: { - input: this.getInput(), // The user's input - recipeConfig: this.getRecipeConfig(), // The configuration of the recipe - options: this.options, // Options set by the user - progress: this.progress, // The current position in the recipe - step: step // Whether or not to take one step or execute the whole recipe - } - }); -}; - - -/** - * Cancels the current bake by terminating the ChefWorker and creating a new one. - */ -App.prototype.cancelBake = function() { - this.chefWorker.terminate(); - this.registerChefWorker(); - this.setBakingStatus(false); - this.manager.controls.showStaleIndicator(); -}; - - -/** - * Handler for messages sent back by the ChefWorker. - * - * @param {MessageEvent} e - */ -App.prototype.handleChefMessage = function(e) { - switch (e.data.action) { - case "bakeSuccess": - this.bakingComplete(e.data.data); - break; - case "bakeError": - this.handleError(e.data.data); - this.setBakingStatus(false); - break; - case "silentBakeComplete": - break; - case "workerLoaded": - this.workerLoaded = true; - this.loaded(); - break; - case "statusMessage": - this.manager.output.setStatusMsg(e.data.data); - break; - default: - console.error("Unrecognised message from ChefWorker", e); - break; - } -}; - - -/** - * Handler for completed bakes. - * - * @param {Object} response - */ -App.prototype.bakingComplete = function(response) { - this.setBakingStatus(false); - - if (!response) return; - - if (response.error) { - this.handleError(response.error); - } - - this.options = response.options; - this.dishStr = response.type === "html" ? Utils.stripHtmlTags(response.result, true) : response.result; - this.progress = response.progress; - this.manager.recipe.updateBreakpointIndicator(response.progress); - this.manager.output.set(response.result, response.type, response.duration); + this.manager.worker.bake( + this.getInput(), // The user's input + this.getRecipeConfig(), // The configuration of the recipe + this.options, // Options set by the user + this.progress, // The current position in the recipe + step // Whether or not to take one step or execute the whole recipe + ); }; @@ -226,8 +128,8 @@ App.prototype.autoBake = function() { /** - * Asks the ChefWorker to run a silent bake, forcing the browser to load and cache all the relevant - * JavaScript code needed to do a real bake. + * Runs a silent bake, forcing the browser to load and cache all the relevant JavaScript code needed + * to do a real bake. * * The output will not be modified (hence "silent" bake). This will only actually execute the recipe * if auto-bake is enabled, otherwise it will just wake up the ChefWorker with an empty recipe. @@ -241,12 +143,7 @@ App.prototype.silentBake = function() { recipeConfig = this.getRecipeConfig(); } - this.chefWorker.postMessage({ - action: "silentBake", - data: { - recipeConfig: recipeConfig - } - }); + this.manager.worker.silentBake(recipeConfig); }; diff --git a/src/web/Manager.js b/src/web/Manager.js index 1942bc5a..fccbc9ff 100755 --- a/src/web/Manager.js +++ b/src/web/Manager.js @@ -1,3 +1,4 @@ +import WorkerWaiter from "./WorkerWaiter.js"; import WindowWaiter from "./WindowWaiter.js"; import ControlsWaiter from "./ControlsWaiter.js"; import RecipeWaiter from "./RecipeWaiter.js"; @@ -49,6 +50,7 @@ const Manager = function(app) { this.statechange = new CustomEvent("statechange", {bubbles: true}); // Define Waiter objects to handle various areas + this.worker = new WorkerWaiter(this.app, this); this.window = new WindowWaiter(this.app); this.controls = new ControlsWaiter(this.app, this); this.recipe = new RecipeWaiter(this.app, this); @@ -70,6 +72,7 @@ const Manager = function(app) { * Sets up the various components and listeners. */ Manager.prototype.setup = function() { + this.worker.registerChefWorker(); this.recipe.initialiseOperationDragNDrop(); this.controls.autoBakeChange(); this.seasonal.load(); diff --git a/src/web/WorkerWaiter.js b/src/web/WorkerWaiter.js new file mode 100644 index 00000000..e01481ae --- /dev/null +++ b/src/web/WorkerWaiter.js @@ -0,0 +1,153 @@ +import Utils from "../core/Utils.js"; +import ChefWorker from "worker-loader?inline&fallback=false!../core/ChefWorker.js"; + +/** + * Waiter to handle conversations with the ChefWorker. + * + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2017 + * @license Apache-2.0 + * + * @constructor + * @param {App} app - The main view object for CyberChef. + * @param {Manager} manager - The CyberChef event manager. + */ +const WorkerWaiter = function(app, manager) { + this.app = app; + this.manager = manager; +}; + + +/** + * Sets up the ChefWorker and associated listeners. + */ +WorkerWaiter.prototype.registerChefWorker = function() { + this.chefWorker = new ChefWorker(); + this.chefWorker.addEventListener("message", this.handleChefMessage.bind(this)); + + let docURL = document.location.href.split(/[#?]/)[0]; + const index = docURL.lastIndexOf("/"); + if (index > 0) { + docURL = docURL.substring(0, index); + } + this.chefWorker.postMessage({"action": "docURL", "data": docURL}); +}; + + +/** + * Handler for messages sent back by the ChefWorker. + * + * @param {MessageEvent} e + */ +WorkerWaiter.prototype.handleChefMessage = function(e) { + switch (e.data.action) { + case "bakeSuccess": + this.bakingComplete(e.data.data); + break; + case "bakeError": + this.app.handleError(e.data.data); + this.setBakingStatus(false); + break; + case "silentBakeComplete": + break; + case "workerLoaded": + this.app.workerLoaded = true; + this.app.loaded(); + break; + case "statusMessage": + this.manager.output.setStatusMsg(e.data.data); + break; + default: + console.error("Unrecognised message from ChefWorker", e); + break; + } +}; + + +/** + * Updates the UI to show if baking is in process or not. + * + * @param {bakingStatus} + */ +WorkerWaiter.prototype.setBakingStatus = function(bakingStatus) { + this.app.baking = bakingStatus; + + this.manager.output.toggleLoader(bakingStatus); +}; + + +/** + * Cancels the current bake by terminating the ChefWorker and creating a new one. + */ +WorkerWaiter.prototype.cancelBake = function() { + this.chefWorker.terminate(); + this.registerChefWorker(); + this.setBakingStatus(false); + this.manager.controls.showStaleIndicator(); +}; + + +/** + * Handler for completed bakes. + * + * @param {Object} response + */ +WorkerWaiter.prototype.bakingComplete = function(response) { + this.setBakingStatus(false); + + if (!response) return; + + if (response.error) { + this.app.handleError(response.error); + } + + this.app.options = response.options; + this.app.dishStr = response.type === "html" ? Utils.stripHtmlTags(response.result, true) : response.result; + this.app.progress = response.progress; + this.manager.recipe.updateBreakpointIndicator(response.progress); + this.manager.output.set(response.result, response.type, response.duration); +}; + + +/** + * Asks the ChefWorker to bake the current input using the current recipe. + * + * @param {string} input + * @param {Object[]} recipeConfig + * @param {Object} options + * @param {number} progress + * @param {boolean} step + */ +WorkerWaiter.prototype.bake = function(input, recipeConfig, options, progress, step) { + this.setBakingStatus(true); + + this.chefWorker.postMessage({ + action: "bake", + data: { + input: input, + recipeConfig: recipeConfig, + options: options, + progress: progress, + step: step + } + }); +}; + + +/** + * Asks the ChefWorker to run a silent bake, forcing the browser to load and cache all the relevant + * JavaScript code needed to do a real bake. + * + * @param {Objectp[]} [recipeConfig] + */ +WorkerWaiter.prototype.silentBake = function(recipeConfig) { + this.chefWorker.postMessage({ + action: "silentBake", + data: { + recipeConfig: recipeConfig + } + }); +}; + + +export default WorkerWaiter;