From 76e37354e1e00b815764c4b3f998789f7a8a0378 Mon Sep 17 00:00:00 2001 From: Felix Kaspar Date: Tue, 17 Oct 2023 01:31:00 +0200 Subject: [PATCH] node based backend --- public/index.html | 15 ++- public/index.js | 194 +++++++++++++++++++++++++++++-- public/organizeWaitOperations.js | 43 +++++++ public/testWorkflow.js | 71 +++++++++++ 4 files changed, 313 insertions(+), 10 deletions(-) create mode 100644 public/organizeWaitOperations.js create mode 100644 public/testWorkflow.js diff --git a/public/index.html b/public/index.html index 0b1c102c..ac937236 100644 --- a/public/index.html +++ b/public/index.html @@ -12,6 +12,19 @@ - + + + + + + + \ No newline at end of file diff --git a/public/index.js b/public/index.js index 504be83c..8190ca76 100644 --- a/public/index.js +++ b/public/index.js @@ -1,16 +1,192 @@ import { scaleContent } from "./functions/scaleContent.js"; import { scalePage, PageSize } from "./functions/scalePage.js"; +import { organizeWaitOperations } from "./organizeWaitOperations.js"; +import { testWorkflow } from "./testWorkflow.js"; -(async () => { +(async (workflow) => { const pdfFileInput = document.getElementById('pdfFile'); + const doneButton = document.getElementById("doneButton"); - pdfFileInput.addEventListener('change', async (e) => { - const file = e.target.files[0]; - if (file) { - let pdfBuffer = new Uint8Array(await file.arrayBuffer()); - pdfBuffer = await scaleContent(pdfBuffer, 2); - pdfBuffer = await scalePage(pdfBuffer, PageSize.letter); - download(pdfBuffer, "pdf-lib_creation_example.pdf", "application/pdf"); + doneButton.addEventListener('click', async (e) => { + const files = Array.from(pdfFileInput.files); + console.log(files); + const pdfBuffers = await Promise.all(files.map(async file => { + return { + originalFileName: file.name.replace(/\.[^/.]+$/, ""), + fileName: file.name.replace(/\.[^/.]+$/, ""), + buffer: new Uint8Array(await file.arrayBuffer()) + } + })); + console.log(pdfBuffers); + + const waitOperations = organizeWaitOperations(workflow.operations); + + nextOperation(workflow.operations, pdfBuffers); + + async function nextOperation(operations, input) { + if(Array.isArray(operations) && operations.length == 0) { // isEmpty + console.log("operation done: " + input.fileName); + //TODO: Download Restult + return; + } + + for (let i = 0; i < operations.length; i++) { + console.warn(input); + await computeOperation(operations[i], structuredClone(input)); // break references + } } + + async function computeOperation(operation, input) { + switch (operation.type) { + case "done": + console.log("Done operation will get called if all waits are done. Skipping for now.") + break; + case "wait": + const waitOperation = waitOperations[operation.values.id]; + waitOperation.input.push(input); + waitOperation.waitCount--; + if(waitOperation.waitCount == 0) { + await nextOperation(waitOperation.doneOperation.operations, waitOperation.input); + } + break; + case "removeObjects": + if(Array.isArray(input)) { + for (let i = 0; i < input.length; i++) { + // TODO: modfiy input + input[i].fileName += "_removedObjects"; + await nextOperation(operation.operations, input[i]); + } + } + else { + // TODO: modfiy input + input.fileName += "_removedObjects"; + await nextOperation(operation.operations, input); + } + break; + case "extract": + if(Array.isArray(input)) { + for (let i = 0; i < input.length; i++) { + // TODO: modfiy input + input[i].fileName += "_extractedPages"; + await nextOperation(operation.operations, input[i]); + } + } + else { + // TODO: modfiy input + input.fileName += "_extractedPages"; + await nextOperation(operation.operations, input); + } + break; + case "fillField": + if(Array.isArray(input)) { + for (let i = 0; i < input.length; i++) { + // TODO: modfiy input + input[i].fileName += "_filledField"; + await nextOperation(operation.operations, input[i]); + } + } + else { + // TODO: modfiy input + input.fileName += "_filledField"; + await nextOperation(operation.operations, input); + } + break; + case "extractImages": + if(Array.isArray(input)) { + for (let i = 0; i < input.length; i++) { + // TODO: modfiy input + input[i].fileName += "_extractedImages"; + await nextOperation(operation.operations, input[i]); + } + } + else { + // TODO: modfiy input + input.fileName += "_extractedImages"; + await nextOperation(operation.operations, input); + } + break; + case "merge": + if(Array.isArray(input)) { + input = { + originalFileName: input.map(input => input.originalFileName).join("_and_"), + fileName: input.map(input => input.fileName).join("_and_") + "_merged", + buffer: input[0].buffer // TODO: merge inputs + } + } + else { + // TODO: modfiy input + input.fileName += "_merged"; + } + await nextOperation(operation.operations, input); + break; + case "transform": { + if(Array.isArray(input)) { + for (let i = 0; i < input.length; i++) { + // TODO: modfiy input + input[i].fileName += "_transformed"; + await nextOperation(operation.operations, input[i]); + } + } + else { + // TODO: modfiy input + input.fileName += "_transformed"; + await nextOperation(operation.operations, input); + } + break; + } + default: + console.log("operation type unknown: ", operation.type); + break; + } + } + + + + + + // if(selectedElementsList[0].textContent == "mergePDFs") { + + // } + + // // TODO: This can also be run serverside + // if(files.length > 1) { + // files.forEach(file => { + + // }); + // } + // else { + // const file = files[0]; + // let pdfBuffer = new Uint8Array(await file.arrayBuffer()); + // if (file) { + // for (let i = 0; i < selectedElementsList.length; i++) { + // const selectedOption = selectedElementsList[i]; + + // // Perform actions based on the selected option using the switch statement + // switch (selectedOption.textContent) { + // case "scaleContent": + // pdfBuffer = await scaleContent(pdfBuffer, 2); + // break; + // case "changePageSize": + // pdfBuffer = await scalePage(pdfBuffer, PageSize.letter); + // break; + // default: + // // Handle any other actions or errors here + // throw new Error(`This action ${selectedOption.value} has not been implemented.`); + // } + // } + // download(pdfBuffer, file.name.replace(/\.[^/.]+$/, "") + "_mod.pdf", "application/pdf"); + // } + // } }); -})(); + + // document.getElementById("addButton").addEventListener("click", function() { + // const selectedOption = document.getElementById("pdfOptions").value; + // const operations = document.getElementById("operations"); + + // if (selectedOption) { + // const listItem = document.createElement("li"); + // listItem.textContent = selectedOption; + // operations.appendChild(listItem); + // } + // }); +})(testWorkflow); diff --git a/public/organizeWaitOperations.js b/public/organizeWaitOperations.js new file mode 100644 index 00000000..c994502a --- /dev/null +++ b/public/organizeWaitOperations.js @@ -0,0 +1,43 @@ + +export function organizeWaitOperations(operations) { + + // Initialize an object to store the counts and associated "done" operations + const waitCounts = {}; + const doneOperations = {}; + + // Function to count "type: wait" operations and associate "done" operations per id + function countWaitOperationsAndDone(operations) { + for (const operation of operations) { + if (operation.type === "wait") { + const id = operation.values.id; + if (id in waitCounts) { + waitCounts[id]++; + } else { + waitCounts[id] = 1; + } + } + if (operation.type === "done") { + const id = operation.values.id; + doneOperations[id] = operation; + } + if (operation.operations) { + countWaitOperationsAndDone(operation.operations); + } + } + } + + // Start counting and associating from the root operations + countWaitOperationsAndDone(operations); + + // Combine counts and associated "done" operations + const result = {}; + for (const id in waitCounts) { + result[id] = { + waitCount: waitCounts[id], + doneOperation: doneOperations[id], + input: [] + }; + } + return result; +} + diff --git a/public/testWorkflow.js b/public/testWorkflow.js new file mode 100644 index 00000000..673dfbc3 --- /dev/null +++ b/public/testWorkflow.js @@ -0,0 +1,71 @@ +// JSON Representation of this Node Tree: +// https://discord.com/channels/1068636748814483718/1099390571493195898/1118192754103693483 +// https://cdn.discordapp.com/attachments/1099390571493195898/1118192753759764520/image.png?ex=6537dba7&is=652566a7&hm=dc46820ef7c34bc37424794966c5f66f93ba0e15a740742c364d47d31ea119a9& + +export const testWorkflow = { + outputOptions: { + zip: false, + awaitAllDone: true + }, + operations: [ + { + type: "extract", + values: { "index": "1" }, + operations: [ + { + type: "removeObjects", + values: { "objectNames": "photo, josh" }, + operations: [ + { + type: "wait", + values: { "id": 1 } + } + ] + } + ] + }, + { + type: "extract", + values: { "index": "2-5" }, + operations: [ + { + type: "fillField", + values: { "objectName": "name", "inputValue": "Josh" }, + operations: [ + { + type: "wait", + values: { "id": 1 } + } + ] + } + ] + }, + { + type: "done", // This gets called when the other merge-ops with the same id finish. + values: { "id": 1 }, + operations: [ + { + type: "merge", // This gets called when the other merge-ops with the same id finish. + values: {}, + operations: [] + } + ] + }, + { + type: "extractImages", + values: {}, + operations: [] + }, + { + type: "merge", // This gets called when the other merge-ops with the same id finish. + values: {}, + operations: [ + { + type: "transform", + values: { "scale": "2x", "rotation": "90deg" }, + operations: [] + } + ] + } + ] +} \ No newline at end of file