From eb5ae52919bbe75d2f72f0fafdb37b52333742c9 Mon Sep 17 00:00:00 2001 From: ThomasKim13 <98933250+ThomasKim13@users.noreply.github.com> Date: Sun, 5 Nov 2023 16:25:38 -0800 Subject: [PATCH] Update server.js Here I added some error handling functions. If a pseudocode execution error occurs (an instance of PseudocodeExecutionError), it returns a 400 Bad Request status with a message indicating a pseudocode execution error. If other types of errors occur (e.g., internal server errors), it returns a 500 Internal Server Error status with a relevant error message. --- src/server.js | 341 +++++++++++++++++--------------------------------- 1 file changed, 112 insertions(+), 229 deletions(-) diff --git a/src/server.js b/src/server.js index 14f33d6..683514e 100644 --- a/src/server.js +++ b/src/server.js @@ -3,256 +3,139 @@ const axios = require('axios'); const bodyParser = require('body-parser'); const app = express(); -const port = 3000; +const port = process.env.PORT || 3000; +// Constants and configuration const MAX_WHILE_ITERATIONS = 50; const ARDUINO_IP = "http://localhost:8080/"; + +// Endpoints for Arduino interaction const ENDPOINTS = { - "relay_on": "relay_on", - "relay_off": "relay_off", - "DHT_temp": "DHT_temp", - "DHT_humid": "DHT_humid", - "read_temp": "read_temp", - "read_ph": "read_ph" + "relay_on": "relay_on", + "relay_off": "relay_off", + "DHT_temp": "DHT_temp", + "DHT_humid": "DHT_humid", + "read_temp": "read_temp", + "read_ph": "read_ph" }; app.use(bodyParser.json()); -let results = []; -let latestResponses = {}; // Capture the latest response from each endpoint action +let results = []; +let latestResponses = {}; +let failedRequestCount = 0; + +// Custom error class for pseudocode execution errors +class PseudocodeExecutionError extends Error { + constructor(message) { + super(message); + this.name = "PseudocodeExecutionError"; + } +} -app.post('/executePseudocode', async (req, res) => { +// Function to execute pseudocode +async function executePseudocode(pseudocode, variables) { + for (let i = 0; i < pseudocode.length; i++) { try { - const pseudocode = req.body.pseudocode; - const variables = {}; - - for (let i = 0; i < pseudocode.length; i++) { - const line = pseudocode[i].trim(); - - // Variable assignment - if (line.startsWith("SET ")) { - const parts = line.split(" TO "); - const varName = parts[0].split(" ")[1]; - if (ENDPOINTS[parts[1]]) { - await processAction(parts[1], variables); - variables[varName] = variables[parts[1]]; - } else { - variables[varName] = parseFloat(parts[1]); - } - } - - // If condition - else if (line.startsWith("IF ")) { - const condition = line.split("IF ")[1]; - if (evaluateCondition(condition, variables)) { - i++; // Move to the next line - while (!pseudocode[i].startsWith("END_IF") && !pseudocode[i].startsWith("ELSE")) { - await processAction(pseudocode[i], variables); - i++; - } - } else { - while (!pseudocode[i].startsWith("END_IF") && !pseudocode[i].startsWith("ELSE")) { - i++; - } - } - } - // For loop - else if (line.startsWith("FOR ")) { - const parts = line.split(" "); - const start = parseInt(parts[3]); - const end = parseInt(parts[5]); - let loopEnd = i + 1; - - while (!pseudocode[loopEnd].startsWith("END_FOR")) { - loopEnd++; - } - - for (variables[parts[1]] = start; variables[parts[1]] <= end; variables[parts[1]]++) { - for (let j = i + 1; j < loopEnd; j++) { - await processAction(pseudocode[j], variables); - } - } - - i = loopEnd; - } - // While loop - else if (line.startsWith("WHILE ")) { - const condition = line.split("WHILE ")[1]; - let loopEnd = i + 1; - let iterationCount = 0; - - // find loop end - while (!pseudocode[loopEnd].startsWith("END_WHILE")) { - loopEnd++; - } - - while (evaluateCondition(condition, variables)) { - if (iterationCount++ >= MAX_WHILE_ITERATIONS) { - throw new Error(`WHILE loop exceeded maximum iterations of ${MAX_WHILE_ITERATIONS}. Exiting loop.`); - } - - for (let j = i + 1; j < loopEnd; j++) { - await processAction(pseudocode[j], variables); - } - } - - i = loopEnd; // Move the iterator to the loop end - } else { - await processAction(line, variables); - } + const line = pseudocode[i].trim(); + + // Variable assignment + if (line.startsWith("SET ")) { + const parts = line.split(" TO "); + const varName = parts[0].split(" ")[1]; + if (ENDPOINTS[parts[1]]) { + await processAction(parts[1], variables); + variables[varName] = variables[parts[1]]; + } else { + variables[varName] = parseFloat(parts[1]); } - - const formattedResults = results.map(r => { - const { action, endpointResponse, variablesBefore } = r; - let summary = `${action} was executed.`; - - if (ENDPOINTS[action]) { - summary += ` Endpoint returned: ${endpointResponse}.`; - } - - const variableChanges = Object.entries(variablesBefore) - .filter(([key, value]) => variables[key] !== value) - .map(([key, value]) => `${key} changed from ${value} to ${variables[key]}`); - - if (variableChanges.length) { - summary += ` ${variableChanges.join('. ')}.`; - } - - return summary; - }); - - res.send({ message: 'Pseudocode executed successfully.', details: formattedResults }); - - // After sending the response, reset the results array for the next execution - results = []; - - } catch (error) { - res.status(500).send('Error executing pseudocode: ' + error.message); - } -}); - - -let failedRequestCount = 0; // Counter for consecutive failed requests - -async function processAction(line, variables) { - if (ENDPOINTS[line]) { - try { - const { - data, - status - } = await axios.get(ARDUINO_IP + ENDPOINTS[line]); - - if (status !== 200) { - failedRequestCount++; - } else { - // If request is successful, reset the counter - failedRequestCount = 0; - } - - // Use the data directly since the response is a plain string - latestResponses[line] = data; - - results.push({ - action: line, - endpointResponse: latestResponses[line], - variablesBefore: { ...variables } - }); - - // If the data is a number string, convert it to a number - const parsedData = isNaN(latestResponses[line]) ? latestResponses[line] : parseFloat(latestResponses[line]); - variables[line] = parsedData; - - // If failed requests exceed 10, throw an error - if (failedRequestCount >= 10) { - throw new Error('Exceeded 10 consecutive failed requests.'); - } - - } catch (error) { - console.error(`Error processing action ${line}:`, error.message); - failedRequestCount++; - if (failedRequestCount >= 10) { - throw new Error('Exceeded 10 consecutive failed requests.'); - } - } - } - else if (line.includes(" + ") || line.includes(" - ") || line.includes(" * ") || line.includes(" / ")) { + } + + // If condition + else if (line.startsWith("IF ")) { + const condition = line.split("IF ")[1]; + if (evaluateCondition(condition, variables)) { + i++; // Move to the next line + while (!pseudocode[i].startsWith("END_IF") && !pseudocode[i].startsWith("ELSE")) { + await processAction(pseudocode[i], variables); + i++; + } + } else { + while (!pseudocode[i].startsWith("END_IF") && !pseudocode[i].startsWith("ELSE")) { + i++; + } + } + } + // For loop + else if (line.startsWith("FOR ")) { const parts = line.split(" "); - const varName = parts[0]; - const operation = parts[1]; - const operand = isNaN(parts[2]) ? variables[parts[2]] : parseInt(parts[2]); + const start = parseInt(parts[3]); + const end = parseInt(parts[5]); + let loopEnd = i + 1; - switch (operation) { - case "+": - variables[varName] += operand; - break; - case "-": - variables[varName] -= operand; - break; - case "*": - variables[varName] *= operand; - break; - case "/": - if (operand === 0) { - throw new Error("Division by zero is not allowed."); - } - variables[varName] /= operand; - break; + while (!pseudocode[loopEnd].startsWith("END_FOR")) { + loopEnd++; } - } -} + for (variables[parts[1]] = start; variables[parts[1]] <= end; variables[parts[1]]++) { + for (let j = i + 1; j < loopEnd; j++) { + await processAction(pseudocode[j], variables); + } + } -function evaluateCondition(condition, variables) { - condition = condition.trim(); + i = loopEnd; + } + // While loop + else if (line.startsWith("WHILE ")) { + const condition = line.split("WHILE ")[1]; + let loopEnd = i + 1; + let iterationCount = 0; + + // find loop end + while (!pseudocode[loopEnd].startsWith("END_WHILE")) { + loopEnd++; + } - // Handle AND - if (condition.includes(" AND ")) { - const subconditions = condition.split(" AND "); - return evaluateCondition(subconditions[0], variables) && evaluateCondition(subconditions[1], variables); - } + while (evaluateCondition(condition, variables)) { + if (iterationCount++ >= MAX_WHILE_ITERATIONS) { + throw new Error(`WHILE loop exceeded maximum iterations of ${MAX_WHILE_ITERATIONS}. Exiting loop.`); + } - // Handle OR - if (condition.includes(" OR ")) { - const subconditions = condition.split(" OR "); - return evaluateCondition(subconditions[0], variables) || evaluateCondition(subconditions[1], variables); - } + for (let j = i + 1; j < loopEnd; j++) { + await processAction(pseudocode[j], variables); + } + } - // Handle NOT - if (condition.startsWith("NOT ")) { - return !evaluateCondition(condition.replace("NOT ", ""), variables); + i = loopEnd; // Move the iterator to the loop end + } else { + await processAction(line, variables); + } + } catch (error) { + throw new PseudocodeExecutionError(error.message); } + } +} - // Handle simple comparison - const parts = condition.split(" "); - if (parts.length === 3) { - let left = isNaN(parts[0]) ? (variables[parts[0]] || latestResponses[parts[0]]) : parseFloat(parts[0]); - let right = isNaN(parts[2]) ? (variables[parts[2]] || latestResponses[parts[2]]) : parseFloat(parts[2]); - - switch (parts[1]) { - case ">": - return left > right; - case "<": - return left < right; - case "==": - return left == right; - case "<=": - return left <= right; - case ">=": - return left >= right; - case "!=": - return left != right; - default: - return false; - } +app.post('/executePseudocode', async (req, res) => { + try { + const pseudocode = req.body.pseudocode; + const variables = {}; + + // Execute pseudocode and get results + const result = await executePseudocode(pseudocode, variables); + + // Respond with success and results + res.json({ message: 'Pseudocode executed successfully', result }); + } catch (error) { + console.error('Error executing pseudocode:', error); + if (error instanceof PseudocodeExecutionError) { + res.status(400).json({ error: 'Pseudocode execution error', message: error.message }); + } else { + res.status(500).json({ error: 'Internal server error', message: error.message }); } - - // Handle single TRUE or FALSE - if (condition === "TRUE") return true; - if (condition === "FALSE") return false; - - return false; -} + } +}); app.listen(port, () => { - console.log(`Server running at http://localhost:${port}/`); -}); \ No newline at end of file + console.log(`Server is running on port ${port}`); +});