Change baking to send all inputs individually.

Re-enable go to tab button.
Active tab is now autobaked on load completion.
Handle (ish) loaderWorker errors.
Improve load performance.
This commit is contained in:
j433866 2019-04-26 15:15:44 +01:00
parent f638bd4ded
commit 1cf83c2485
6 changed files with 206 additions and 154 deletions

View File

@ -120,7 +120,6 @@ class App {
* *
* @param {boolean} [step] - Set to true if we should only execute one operation instead of the * @param {boolean} [step] - Set to true if we should only execute one operation instead of the
* whole recipe. * whole recipe.
* @param input - The inputs to bake
*/ */
bake(step=false, input) { bake(step=false, input) {
// if (this.baking) return; // if (this.baking) return;
@ -132,7 +131,6 @@ class App {
this.manager.recipe.updateBreakpointIndicator(false); this.manager.recipe.updateBreakpointIndicator(false);
this.manager.worker.bake( this.manager.worker.bake(
input, // The user's input
this.getRecipeConfig(), // The configuration of the recipe this.getRecipeConfig(), // The configuration of the recipe
this.options, // Options set by the user this.options, // Options set by the user
this.progress, // The current position in the recipe this.progress, // The current position in the recipe

View File

@ -215,9 +215,6 @@ class InputWaiter {
case "terminateLoaderWorker": case "terminateLoaderWorker":
this.removeLoaderWorker(this.getLoaderWorker(r.data)); this.removeLoaderWorker(this.getLoaderWorker(r.data));
break; break;
case "allInputs":
this.app.bake(false, r.data);
break;
case "refreshTabs": case "refreshTabs":
this.refreshTabs(r.data.nums, r.data.activeTab); this.refreshTabs(r.data.nums, r.data.activeTab);
break; break;
@ -234,7 +231,7 @@ class InputWaiter {
this.showLoadingInfo(r.data); this.showLoadingInfo(r.data);
break; break;
case "setInput": case "setInput":
this.set(r.data, true); this.set(r.data.inputObj, r.data.silent);
break; break;
case "inputAdded": case "inputAdded":
this.inputAdded(r.data.changeTab, r.data.inputNum); this.inputAdded(r.data.changeTab, r.data.inputNum);
@ -242,6 +239,12 @@ class InputWaiter {
case "addInputs": case "addInputs":
this.addInputs(r.data); this.addInputs(r.data);
break; break;
case "queueInput":
this.manager.worker.queueInput(r.data);
break;
case "bake":
this.app.bake(false);
break;
default: default:
log.error(`Unknown action ${r.action}.`); log.error(`Unknown action ${r.action}.`);
} }
@ -281,10 +284,11 @@ class InputWaiter {
* @param {boolean} [silent=false] * @param {boolean} [silent=false]
*/ */
set(inputData, silent=false) { set(inputData, silent=false) {
const inputText = document.getElementById("input-text");
const activeTab = this.getActiveTab(); const activeTab = this.getActiveTab();
if (inputData.inputNum !== activeTab) return; if (inputData.inputNum !== activeTab) return;
const inputText = document.getElementById("input-text");
if (typeof inputData.input === "string") { if (typeof inputData.input === "string") {
inputText.value = inputData.input; inputText.value = inputData.input;
// close file // close file
@ -370,16 +374,19 @@ class InputWaiter {
fileLoaded.textContent = progress + "%"; fileLoaded.textContent = progress + "%";
if (progress < 100) { if (progress < 100) {
// setTimeout(function() { setTimeout(function() {
// this.inputWorker.postMessage({ this.inputWorker.postMessage({
// action: "getInputProgress", action: "getInputProgress",
// data: activeTab data: activeTab
// }); });
// }.bind(this), 100); }.bind(this), 100);
} else { } else {
this.inputWorker.postMessage({ this.inputWorker.postMessage({
action: "setInput", action: "setInput",
data: inputNum data: {
inputNum: inputNum,
silent: true
}
}); });
} }
} }
@ -531,21 +538,35 @@ class InputWaiter {
} }
/** /**
* Load files from the UI into the inputWorker, creating tabs if needed * Load files from the UI into the inputWorker
* *
* @param files * @param files
*/ */
loadUIFiles(files) { loadUIFiles(files) {
const numFiles = files.length; const numFiles = files.length;
const activeTab = this.getActiveTab();
log.debug(`Loading ${numFiles} files.`); log.debug(`Loading ${numFiles} files.`);
// Show something in the UI to make it clear we're loading files // Show something in the UI to make it clear we're loading files
this.inputWorker.postMessage({ this.hideLoadingMessage();
action: "loadUIFiles", this.showLoadingInfo({
data: files pending: numFiles,
loading: 0,
loaded: 0,
total: numFiles,
activeProgress: {
inputNum: activeTab,
progress: 0
}
}); });
this.hideLoadingMessage(); this.inputWorker.postMessage({
action: "loadUIFiles",
data: {
files: files,
activeTab: activeTab
}
});
} }
/** /**
@ -601,7 +622,14 @@ class InputWaiter {
// setinputInfo // setinputInfo
/** /**
* Display the loaded files information in the input header * Display the loaded files information in the input header
* @param loadedData * @param {object} loadedData
* @param {number} loadedData.pending
* @param {number} loadedData.loading
* @param {number} loadedData.loaded
* @param {number} loadedData.total
* @param {object} loadedData.activeProgress
* @param {number} loadedData.activeProgress.inputNum
* @param {number} loadedData.activeProgress.progress
*/ */
showLoadingInfo(loadedData) { showLoadingInfo(loadedData) {
const pending = loadedData.pending; const pending = loadedData.pending;
@ -629,6 +657,15 @@ class InputWaiter {
document.getElementById("input-files-info").innerHTML = msg; document.getElementById("input-files-info").innerHTML = msg;
this.updateFileProgress(loadedData.activeProgress.inputNum, loadedData.activeProgress.progress); this.updateFileProgress(loadedData.activeProgress.inputNum, loadedData.activeProgress.progress);
if (loaded < total) {
setTimeout(function() {
this.inputWorker.postMessage({
action: "getLoadProgress",
data: this.getActiveTab()
});
}.bind(this), 100);
}
} }
// displayTabInfo // displayTabInfo
// simple getInput for each tab // simple getInput for each tab
@ -754,7 +791,10 @@ class InputWaiter {
} else { } else {
this.inputWorker.postMessage({ this.inputWorker.postMessage({
action: "setInput", action: "setInput",
data: inputNum data: {
inputNum: inputNum,
silent: true
}
}); });
} }
@ -890,10 +930,19 @@ class InputWaiter {
* @param {array} inputNums * @param {array} inputNums
*/ */
addInputs(inputNums) { addInputs(inputNums) {
const activeTab = this.getActiveTab();
for (let i = 0; i < inputNums.length; i++) { for (let i = 0; i < inputNums.length; i++) {
if (inputNums[i] === activeTab) continue;
this.manager.output.addOutput(inputNums[i], false); this.manager.output.addOutput(inputNums[i], false);
} }
this.changeTab(inputNums[inputNums.length - 1], this.app.options.syncTabs); // this.changeTab(inputNums[inputNums.length - 1], this.app.options.syncTabs);
this.inputWorker.postMessage({
action: "refreshTabs",
data: {
inputNum: this.getActiveTab(),
direction: "left"
}
});
} }
/** /**
@ -959,6 +1008,14 @@ class InputWaiter {
} }
}); });
} }
/**
* Handler for go to tab button clicked
*/
goToTab() {
const tabNum = parseInt(window.prompt("Enter tab number:", this.getActiveTab().toString()), 10);
this.changeTab(tabNum, this.app.options.syncTabs);
}
} }
export default InputWaiter; export default InputWaiter;

View File

@ -13,6 +13,9 @@ self.pendingFiles = [];
self.inputs = {}; self.inputs = {};
self.loaderWorkerPorts = []; self.loaderWorkerPorts = [];
self.currentInputNum = 1; self.currentInputNum = 1;
self.numInputs = 0;
self.pendingInputs = 0;
self.loadingInputs = 0;
/** /**
* Respond to message from parent thread. * Respond to message from parent thread.
@ -82,21 +85,10 @@ self.addEventListener("message", function(e) {
}); });
self.getLoadProgress = function(inputNum) { self.getLoadProgress = function(inputNum) {
const inputNums = Object.keys(self.inputs); const total = self.numInputs;
const total = inputNums.length;
const pending = self.pendingFiles.length; const pending = self.pendingFiles.length;
let loaded = 0; const loading = self.loadingInputs;
let loading = 0; const loaded = total - pending - loading;
for (let i = 0; i < inputNums.length; i++) {
switch (self.inputs[inputNums[i]].status) {
case "loading":
loading++;
break;
case "loaded":
loaded++;
}
}
self.postMessage({ self.postMessage({
action: "loadingInfo", action: "loadingInfo",
@ -111,12 +103,6 @@ self.getLoadProgress = function(inputNum) {
} }
} }
}); });
if (loaded < total) {
setTimeout(function(inputNum) {
self.getLoadProgress(inputNum);
}, 100);
}
}; };
self.autoBake = function(inputNum) { self.autoBake = function(inputNum) {
@ -127,17 +113,19 @@ self.autoBake = function(inputNum) {
inputData = inputData.fileBuffer; inputData = inputData.fileBuffer;
} }
self.postMessage({ self.postMessage({
action: "allInputs", action: "queueInput",
data: [{ data: {
input: inputData, input: inputData,
inputNum: parseInt(inputNum, 10) inputNum: parseInt(inputNum, 10)
}] }
});
self.postMessage({
action: "bake"
}); });
} }
}; };
self.getAllInputs = function() { self.getAllInputs = function() {
const inputs = [];
const inputNums = Object.keys(self.inputs); const inputNums = Object.keys(self.inputs);
for (let i = 0; i < inputNums.length; i++) { for (let i = 0; i < inputNums.length; i++) {
@ -146,16 +134,17 @@ self.getAllInputs = function() {
if (typeof inputData !== "string") { if (typeof inputData !== "string") {
inputData = inputData.fileBuffer; inputData = inputData.fileBuffer;
} }
inputs.push({ self.postMessage({
input: inputData, action: "queueInput",
inputNum: inputNums[i] data: {
input: inputData,
inputNum: inputNums[i]
}
}); });
} }
} }
self.postMessage({ self.postMessage({
action: "allInputs", action: "bake"
data: inputs
}); });
}; };
@ -165,15 +154,11 @@ self.getInputObj = function(inputNum) {
}; };
self.getInputValue = function(inputNum) { self.getInputValue = function(inputNum) {
for (let i = 0; i < self.inputs.length; i++) { if (self.inputs[inputNum]) {
if (self.inputs[i].inputNum === inputNum) { if (typeof self.inputs[inputNum].data === "string") {
if (self.inputs[i].status === "loaded") { return self.inputs[inputNum].data;
let inputData = self.inputs[i].data; } else {
if (typeof inputData !== "string") { return self.inputs[inputNum].fileBuffer;
inputData = inputData.fileBuffer;
}
return inputData;
}
} }
} }
return ""; return "";
@ -308,7 +293,9 @@ self.updateTabHeader = function(inputNum) {
}); });
}; };
self.setInput = function(inputNum) { self.setInput = function(inputData) {
const inputNum = inputData.inputNum;
const silent = inputData.silent;
const input = self.getInputObj(inputNum); const input = self.getInputObj(inputNum);
if (input === undefined || input === null) return; if (input === undefined || input === null) return;
@ -327,7 +314,10 @@ self.setInput = function(inputNum) {
self.postMessage({ self.postMessage({
action: "setInput", action: "setInput",
data: inputObj data: {
inputObj: inputObj,
silent: silent
}
}); });
self.getInputProgress(inputNum); self.getInputProgress(inputNum);
}; };
@ -426,12 +416,29 @@ self.handleLoaderMessage = function(e) {
inputNum = r.inputNum; inputNum = r.inputNum;
} }
if (r.hasOwnProperty("error")) {
self.updateInputStatus(r.inputNum, "error");
self.updateInputProgress(r.inputNum, 0);
log.error(r.error);
self.loadingInputs--;
self.terminateLoaderWorker(r.id);
self.activateLoaderWorker();
return;
}
if (r.hasOwnProperty("fileBuffer")) { if (r.hasOwnProperty("fileBuffer")) {
log.debug(`Input file ${inputNum} loaded.`); log.debug(`Input file ${inputNum} loaded.`);
self.loadingInputs--;
self.updateInputValue({ self.updateInputValue({
inputNum: inputNum, inputNum: inputNum,
value: r.fileBuffer value: r.fileBuffer
}); });
self.setInput({inputNum: inputNum, silent: false});
const idx = self.getLoaderWorkerIdx(r.id); const idx = self.getLoaderWorkerIdx(r.id);
self.loadNextFile(idx); self.loadNextFile(idx);
} else if (r.hasOwnProperty("progress")) { } else if (r.hasOwnProperty("progress")) {
@ -450,6 +457,7 @@ self.loadNextFile = function(workerIdx) {
const nextFile = self.pendingFiles.splice(0, 1)[0]; const nextFile = self.pendingFiles.splice(0, 1)[0];
self.loaderWorkerPorts[workerIdx].inputNum = nextFile.inputNum; self.loaderWorkerPorts[workerIdx].inputNum = nextFile.inputNum;
self.loadingInputs++;
port.postMessage({ port.postMessage({
action: "loadInput", action: "loadInput",
data: { data: {
@ -484,16 +492,31 @@ self.terminateLoaderWorker = function(id) {
/** /**
* Loads files using LoaderWorkers * Loads files using LoaderWorkers
*
* @param {object} filesData
* @param filesData.files
* @param {number} filesData.activeTab
*/ */
self.loadFiles = function(files) { self.loadFiles = function(filesData) {
const files = filesData.files;
const activeTab = filesData.activeTab;
let lastInputNum = -1; let lastInputNum = -1;
const inputNums = []; const inputNums = [];
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
lastInputNum = self.addInput(false, "file", { if (i === 0 && self.getInputValue(activeTab) === "") {
name: files[i].name, self.removeInput(activeTab);
size: files[i].size.toLocaleString(), lastInputNum = self.addInput(false, "file", {
type: files[i].type || "unknown" name: files[i].name,
}); size: files[i].size.toLocaleString(),
type: files[i].type || "unknown"
}, activeTab);
} else {
lastInputNum = self.addInput(false, "file", {
name: files[i].name,
size: files[i].size.toLocaleString(),
type: files[i].type || "unknown"
});
}
inputNums.push(lastInputNum); inputNums.push(lastInputNum);
self.pendingFiles.push({ self.pendingFiles.push({
@ -526,9 +549,10 @@ self.loadFiles = function(files) {
* @param {string} fileData.name * @param {string} fileData.name
* @param {string} fileData.size * @param {string} fileData.size
* @param {string} fileData.type * @param {string} fileData.type
* @param {number} inputNum
*/ */
self.addInput = function(changeTab=false, type, fileData={name: "unknown", size: "unknown", type: "unknown"}) { self.addInput = function(changeTab=false, type, fileData={name: "unknown", size: "unknown", type: "unknown"}, inputNum = self.currentInputNum++) {
const inputNum = self.currentInputNum++; self.numInputs++;
const newInputObj = { const newInputObj = {
inputNum: inputNum inputNum: inputNum
}; };
@ -571,15 +595,24 @@ self.addInput = function(changeTab=false, type, fileData={name: "unknown", size:
self.removeInput = function(removeInputData) { self.removeInput = function(removeInputData) {
const inputNum = removeInputData.inputNum; const inputNum = removeInputData.inputNum;
const refreshTabs = removeInputData.refreshTabs; const refreshTabs = removeInputData.refreshTabs;
self.numInputs--;
delete self.inputs[inputNum]; delete self.inputs[inputNum];
for (let i = 0; i < self.loaderWorkerPorts.length; i++) { for (let i = 0; i < self.loaderWorkerPorts.length; i++) {
if (self.loaderWorkerPorts[i].inputNum === inputNum) { if (self.loaderWorkerPorts[i].inputNum === inputNum) {
self.loadingInputs--;
self.terminateLoaderWorker(self.loaderWorkerPorts[i].id); self.terminateLoaderWorker(self.loaderWorkerPorts[i].id);
} }
} }
for (let i = 0; i < self.pendingFiles.length; i++) {
if (self.pendingFiles[i].inputNum === inputNum) {
self.pendingFiles.splice(i, 1);
break;
}
}
if (refreshTabs) { if (refreshTabs) {
self.refreshTabs(inputNum, "left"); self.refreshTabs(inputNum, "left");
} }

View File

@ -160,7 +160,7 @@ class Manager {
document.getElementById("btn-new-tab").addEventListener("click", this.input.addInput.bind(this.input)); document.getElementById("btn-new-tab").addEventListener("click", this.input.addInput.bind(this.input));
document.getElementById("btn-previous-input-tab").addEventListener("click", this.input.changeTabLeft.bind(this.input)); document.getElementById("btn-previous-input-tab").addEventListener("click", this.input.changeTabLeft.bind(this.input));
document.getElementById("btn-next-input-tab").addEventListener("click", this.input.changeTabRight.bind(this.input)); document.getElementById("btn-next-input-tab").addEventListener("click", this.input.changeTabRight.bind(this.input));
// document.getElementById("btn-go-to-input-tab").addEventListener("click", this.input.goToTab.bind(this.input)); document.getElementById("btn-go-to-input-tab").addEventListener("click", this.input.goToTab.bind(this.input));
// document.getElementById("btn-find-input-tab").addEventListener("click", this.input.findTab.bind(this.input)); // document.getElementById("btn-find-input-tab").addEventListener("click", this.input.findTab.bind(this.input));
this.addDynamicListener("#input-tabs li .btn-close-tab i", "click", this.input.removeTabClick, this.input); this.addDynamicListener("#input-tabs li .btn-close-tab i", "click", this.input.removeTabClick, this.input);
this.addDynamicListener("#input-tabs li .input-tab-content", "click", this.input.changeTabClick, this.input); this.addDynamicListener("#input-tabs li .input-tab-content", "click", this.input.changeTabClick, this.input);

View File

@ -27,6 +27,7 @@ class OutputWaiter {
this.manager = manager; this.manager = manager;
this.outputs = {}; this.outputs = {};
this.activeTab = -1;
this.maxTabs = 4; // Calculate this this.maxTabs = 4; // Calculate this
} }
@ -466,6 +467,7 @@ class OutputWaiter {
for (let i = 0; i < tabs.length; i++) { for (let i = 0; i < tabs.length; i++) {
if (tabs.item(i).getAttribute("inputNum") === inputNum.toString()) { if (tabs.item(i).getAttribute("inputNum") === inputNum.toString()) {
tabs.item(i).classList.add("active-output-tab"); tabs.item(i).classList.add("active-output-tab");
this.activeTab = inputNum;
found = true; found = true;
} else { } else {
tabs.item(i).classList.remove("active-output-tab"); tabs.item(i).classList.remove("active-output-tab");
@ -482,6 +484,7 @@ class OutputWaiter {
tabs.item(i).setAttribute("inputNum", newOutputs[i].toString()); tabs.item(i).setAttribute("inputNum", newOutputs[i].toString());
this.displayTabInfo(newOutputs[i]); this.displayTabInfo(newOutputs[i]);
if (newOutputs[i] === inputNum) { if (newOutputs[i] === inputNum) {
this.activeTab = inputNum;
tabs.item(i).classList.add("active-output-tab"); tabs.item(i).classList.add("active-output-tab");
} }
} }
@ -740,13 +743,7 @@ class OutputWaiter {
* @returns {number} * @returns {number}
*/ */
getActiveTab() { getActiveTab() {
const activeTabs = document.getElementsByClassName("active-output-tab"); return this.activeTab;
if (activeTabs.length > 0) {
const activeTab = activeTabs.item(0);
const tabNum = activeTab.getAttribute("inputNum");
return parseInt(tabNum, 10);
}
return -1;
} }
/** /**

View File

@ -310,53 +310,46 @@ class WorkerWaiter {
this.chefWorkers[workerIdx].inputNum = nextInput.inputNum; this.chefWorkers[workerIdx].inputNum = nextInput.inputNum;
this.chefWorkers[workerIdx].active = true; this.chefWorkers[workerIdx].active = true;
this.chefWorkers[workerIdx].worker.postMessage({ const input = nextInput.input;
action: "bake", if (typeof input === "string") {
data: { this.chefWorkers[workerIdx].worker.postMessage({
input: nextInput.input, action: "bake",
recipeConfig: this.recipeConfig, data: {
options: this.options, input: input,
progress: this.progress, recipeConfig: this.recipeConfig,
step: this.step, options: this.options,
inputNum: nextInput.inputNum progress: this.progress,
} step: this.step,
}); inputNum: nextInput.inputNum
}
});
} else {
this.chefWorkers[workerIdx].worker.postMessage({
action: "bake",
data: {
input: input,
recipeConfig: this.recipeConfig,
options: this.options,
progress: this.progress,
step: this.step,
inputNum: nextInput.inputNum
}
}, [nextInput.input]);
}
} }
/** /**
* Bakes the current input using the current recipe. * Bakes the current input using the current recipe.
* *
* @param {string | Array} input
* @param {Object[]} recipeConfig * @param {Object[]} recipeConfig
* @param {Object} options * @param {Object} options
* @param {number} progress * @param {number} progress
* @param {boolean} step * @param {boolean} step
*/ */
bake(input, recipeConfig, options, progress, step) { bake(recipeConfig, options, progress, step) {
this.setBakingStatus(true); this.setBakingStatus(true);
this.bakeStartTime = new Date().getTime(); this.bakeStartTime = new Date().getTime();
if (typeof input === "string") {
input = [{
input: input,
inputNum: this.manager.input.getActiveTab()
}];
}
for (let i = 0; i < input.length; i++) {
this.manager.output.updateOutputStatus("pending", input[i].inputNum);
for (let x = 0; x < this.inputs.length; x++) {
if (this.inputs[x].inputNum === input[i].inputNum) {
this.inputs.splice(x, 1);
break;
}
}
}
this.totalOutputs += input.length;
this.inputs = input;
this.recipeConfig = recipeConfig; this.recipeConfig = recipeConfig;
this.options = options; this.options = options;
this.progress = progress; this.progress = progress;
@ -368,49 +361,20 @@ class WorkerWaiter {
this.bakeNextInput(workerIdx); this.bakeNextInput(workerIdx);
} }
this.displayProgress(); this.displayProgress();
return; }
/**
* Queues an input ready to be baked
*
* @param {object} inputData
* @param {string | ArrayBuffer} inputData.input
* @param {number} inputData.inputNum
*/
queueInput(inputData) {
this.manager.output.updateOutputStatus("pending", inputData.inputNum);
for (let i = 0; i < input.length; i++) { this.totalOutputs++;
this.totalOutputs++; this.inputs.push(inputData);
this.manager.output.updateOutputStatus("pending", input[i].inputNum);
this.manager.output.updateOutputMessage(`Input ${input[i].inputNum} has not been baked yet.`, input[i].inputNum);
// If an input exists for the current inputNum, remove it
for (let x = 0; x < this.inputs.length; x++) {
if (this.inputs[x].inputNum === input[i].inputNum) {
this.inputs.splice(x, 1);
}
}
const workerId = this.addChefWorker();
if (workerId !== -1) {
// Send the input to the ChefWorker
this.manager.output.updateOutputStatus("baking", input[i].inputNum);
this.manager.output.updateOutputMessage("Baking...", input[i].inputNum);
this.chefWorkers[workerId].active = true;
this.chefWorkers[workerId].inputNum = input[i].inputNum;
this.chefWorkers[workerId].worker.postMessage({
action: "bake",
data: {
input: input[i].input,
recipeConfig: recipeConfig,
options: options,
progress: progress,
step: step,
inputNum: input[i].inputNum
}
});
} else {
// Add the input to inputs so it can be processed when ready
this.inputs.push({
input: input[i].input,
recipeConfig: recipeConfig,
options: options,
progress: progress,
step: step,
inputNum: input[i].inputNum
});
}
}
} }
/** /**
@ -474,6 +438,9 @@ class WorkerWaiter {
*/ */
displayProgress() { displayProgress() {
const progress = this.getBakeProgress(); const progress = this.getBakeProgress();
if (progress.total === progress.baked) return;
const percentComplete = ((progress.pending + progress.baking) / progress.total) * 100; const percentComplete = ((progress.pending + progress.baking) / progress.total) * 100;
const bakeButton = document.getElementById("bake"); const bakeButton = document.getElementById("bake");
if (this.app.baking) { if (this.app.baking) {