mirror of
https://github.com/Lissy93/web-check.git
synced 2024-11-25 09:43:13 +01:00
Removed the need for lambda handler, added status message to server, refactored
This commit is contained in:
parent
e23347a936
commit
63db1dbd85
@ -37,7 +37,6 @@
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-simple-maps": "^3.0.0",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"aws-serverless-express": "^3.4.0",
|
||||
"axios": "^1.4.0",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"chrome-aws-lambda": "^10.1.0",
|
||||
|
156
server.js
156
server.js
@ -1,5 +1,4 @@
|
||||
const express = require('express');
|
||||
const awsServerlessExpress = require('aws-serverless-express');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const cors = require('cors');
|
||||
@ -8,87 +7,89 @@ require('dotenv').config();
|
||||
|
||||
const app = express();
|
||||
|
||||
const port = process.env.PORT || 3000; // The port to run the server on
|
||||
const API_DIR = '/api'; // Name of the dir containing the lambda functions
|
||||
const dirPath = path.join(__dirname, API_DIR); // Path to the lambda functions dir
|
||||
const guiPath = path.join(__dirname, 'build');
|
||||
const handlers = {}; // Will store list of API endpoints
|
||||
process.env.WC_SERVER = 'true'; // Tells middleware to return in non-lambda mode
|
||||
|
||||
// Enable CORS
|
||||
app.use(cors({
|
||||
origin: process.env.API_CORS_ORIGIN || '*',
|
||||
}));
|
||||
|
||||
// Execute the lambda function
|
||||
const executeHandler = async (handler, req) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = (err, response) => err ? reject(err) : resolve(response);
|
||||
const promise = handler(req, {}, callback);
|
||||
|
||||
if (promise && typeof promise.then === 'function') {
|
||||
promise.then(resolve).catch(reject);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Array of all the lambda function file names
|
||||
const fileNames = fs.readdirSync(dirPath, { withFileTypes: true })
|
||||
// Read and register each API function as an Express routes
|
||||
fs.readdirSync(dirPath, { withFileTypes: true })
|
||||
.filter(dirent => dirent.isFile() && dirent.name.endsWith('.js'))
|
||||
.map(dirent => dirent.name);
|
||||
.forEach(dirent => {
|
||||
const routeName = dirent.name.split('.')[0];
|
||||
const route = `${API_DIR}/${routeName}`;
|
||||
const handler = require(path.join(dirPath, dirent.name));
|
||||
handlers[route] = handler;
|
||||
|
||||
const handlers = {};
|
||||
app.get(route, async (req, res) => {
|
||||
try {
|
||||
await handler(req, res);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
fileNames.forEach(file => {
|
||||
const routeName = file.split('.')[0];
|
||||
const route = `${API_DIR}/${routeName}`;
|
||||
const handler = require(path.join(dirPath, file)).handler;
|
||||
|
||||
handlers[route] = handler;
|
||||
// Create a single API endpoint to execute all lambda functions
|
||||
app.get('/api', async (req, res) => {
|
||||
const results = {};
|
||||
const { url } = req.query;
|
||||
const maxExecutionTime = process.env.API_TIMEOUT_LIMIT || 20000;
|
||||
|
||||
app.get(route, async (req, res) => {
|
||||
try {
|
||||
const { statusCode = 200, body = '' } = await executeHandler(handler, req);
|
||||
res.status(statusCode).json(JSON.parse(body));
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
const executeHandler = async (handler, req, res) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const mockRes = {
|
||||
status: (statusCode) => mockRes,
|
||||
json: (body) => resolve({ body }),
|
||||
};
|
||||
await handler({ ...req, query: { url } }, mockRes);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const timeout = (ms, jobName = null) => {
|
||||
return new Promise((_, reject) => {
|
||||
setTimeout(() => {
|
||||
reject(new Error(
|
||||
`Timed out after ${ms/1000} seconds${jobName ? `, when executing ${jobName}` : ''}`
|
||||
));
|
||||
}, ms);
|
||||
});
|
||||
};
|
||||
|
||||
const handlerPromises = Object.entries(handlers).map(async ([route, handler]) => {
|
||||
const routeName = route.replace(`${API_DIR}/`, '');
|
||||
|
||||
try {
|
||||
const result = await Promise.race([
|
||||
executeHandler(handler, req, res),
|
||||
timeout(maxExecutionTime, routeName)
|
||||
]);
|
||||
results[routeName] = result.body;
|
||||
} catch (err) {
|
||||
results[routeName] = { error: err.message };
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(handlerPromises);
|
||||
res.json(results);
|
||||
});
|
||||
});
|
||||
|
||||
const timeout = (ms, jobName = null) => {
|
||||
return new Promise((_, reject) => {
|
||||
setTimeout(() => {
|
||||
reject(new Error(`Timed out after the ${ms/1000} second limit${jobName ? `, when executing the ${jobName} task` : ''}`));
|
||||
}, ms);
|
||||
});
|
||||
}
|
||||
|
||||
app.get('/api', async (req, res) => {
|
||||
const results = {};
|
||||
const { url } = req.query;
|
||||
const maxExecutionTime = process.env.API_TIMEOUT_LIMIT || 15000;
|
||||
|
||||
const handlerPromises = Object.entries(handlers).map(async ([route, handler]) => {
|
||||
const routeName = route.replace(`${API_DIR}/`, '');
|
||||
|
||||
try {
|
||||
const result = await Promise.race([
|
||||
executeHandler(handler, { query: { url } }),
|
||||
timeout(maxExecutionTime, routeName)
|
||||
]);
|
||||
results[routeName] = JSON.parse((result || {}).body);
|
||||
|
||||
} catch (err) {
|
||||
results[routeName] = { error: err.message };
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(handlerPromises);
|
||||
res.json(results);
|
||||
});
|
||||
|
||||
|
||||
// Handle SPA routing
|
||||
app.use(historyApiFallback({
|
||||
rewrites: [
|
||||
{ from: /^\/api\/.*$/, to: function(context) { return context.parsedUrl.path; } },
|
||||
{ from: /^\/api\/.*$/, to: (context) => context.parsedUrl.path },
|
||||
]
|
||||
}));
|
||||
|
||||
@ -111,12 +112,25 @@ if (process.env.DISABLE_GUI && process.env.DISABLE_GUI !== 'false') {
|
||||
app.use(express.static(guiPath));
|
||||
}
|
||||
|
||||
// Create serverless express server
|
||||
const port = process.env.PORT || 3000;
|
||||
const server = awsServerlessExpress.createServer(app).listen(port, () => {
|
||||
console.log(`Server is running on port ${port}`);
|
||||
// Print nice welcome message to user
|
||||
const printMessage = () => {
|
||||
console.log(
|
||||
`\x1b[36m\n` +
|
||||
' __ __ _ ___ _ _ \n' +
|
||||
' \\ \\ / /__| |__ ___ / __| |_ ___ __| |__\n' +
|
||||
' \\ \\/\\/ / -_) \'_ \\___| (__| \' \\/ -_) _| / /\n' +
|
||||
' \\_/\\_/\\___|_.__/ \\___|_||_\\___\\__|_\\_\\\n' +
|
||||
`\x1b[0m\n`,
|
||||
`\x1b[1m\x1b[32m🚀 Web-Check is up and running at http://localhost:${port} \x1b[0m\n\n`,
|
||||
`\x1b[2m\x1b[36m🛟 For documentation and support, visit the GitHub repo: ` +
|
||||
`https://github.com/lissy93/web-check \n`,
|
||||
`💖 Found Web-Check useful? Consider sponsoring us on GitHub ` +
|
||||
`to help fund maintenance & development.\x1b[0m`
|
||||
);
|
||||
};
|
||||
|
||||
// Create server
|
||||
app.listen(port, () => {
|
||||
printMessage();
|
||||
});
|
||||
|
||||
exports.handler = (event, context) => {
|
||||
awsServerlessExpress.proxy(server, event, context);
|
||||
};
|
||||
|
24
yarn.lock
24
yarn.lock
@ -5793,14 +5793,6 @@
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@vendia/serverless-express@^3.4.0":
|
||||
version "3.4.0"
|
||||
resolved "https://registry.npmjs.org/@vendia/serverless-express/-/serverless-express-3.4.0.tgz"
|
||||
integrity sha512-/UAAbi9qRjUtjRISt5MJ1sfhtrHb26hqQ0nvE5qhMLsAdR5H7ErBwPD8Q/v2OENKm0iWsGwErIZEg7ebUeFDjQ==
|
||||
dependencies:
|
||||
binary-case "^1.0.0"
|
||||
type-is "^1.6.16"
|
||||
|
||||
"@vercel/nft@^0.22.0":
|
||||
version "0.22.6"
|
||||
resolved "https://registry.npmjs.org/@vercel/nft/-/nft-0.22.6.tgz"
|
||||
@ -6612,15 +6604,6 @@ avvio@^8.2.0:
|
||||
debug "^4.0.0"
|
||||
fastq "^1.6.1"
|
||||
|
||||
aws-serverless-express@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.npmjs.org/aws-serverless-express/-/aws-serverless-express-3.4.0.tgz"
|
||||
integrity sha512-YG9ZjAOI9OpwqDDWzkRc3kKJYJuR7gTMjLa3kAWopO17myoprxskCUyCEee+RKe34tcR4UNrVtgAwW5yDe74bw==
|
||||
dependencies:
|
||||
"@vendia/serverless-express" "^3.4.0"
|
||||
binary-case "^1.0.0"
|
||||
type-is "^1.6.16"
|
||||
|
||||
axe-core@^4.6.2:
|
||||
version "4.7.2"
|
||||
resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz"
|
||||
@ -6866,11 +6849,6 @@ big.js@^5.2.2:
|
||||
resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz"
|
||||
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
||||
|
||||
binary-case@^1.0.0:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/binary-case/-/binary-case-1.1.4.tgz"
|
||||
integrity sha512-9Kq8m6NZTAgy05Ryuh7U3Qc4/ujLQU1AZ5vMw4cr3igTdi5itZC6kCNrRr2X8NzPiDn2oUIFTfa71DKMnue/Zg==
|
||||
|
||||
binary-extensions@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
|
||||
@ -18272,7 +18250,7 @@ type-fest@^3.0.0:
|
||||
resolved "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz"
|
||||
integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==
|
||||
|
||||
type-is@^1.6.16, type-is@~1.6.18:
|
||||
type-is@~1.6.18:
|
||||
version "1.6.18"
|
||||
resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz"
|
||||
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
||||
|
Loading…
Reference in New Issue
Block a user