mirror of
https://github.com/Lissy93/web-check.git
synced 2025-05-30 23:15:45 +02: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-router-dom": "^5.3.3",
|
||||||
"@types/react-simple-maps": "^3.0.0",
|
"@types/react-simple-maps": "^3.0.0",
|
||||||
"@types/styled-components": "^5.1.26",
|
"@types/styled-components": "^5.1.26",
|
||||||
"aws-serverless-express": "^3.4.0",
|
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"cheerio": "^1.0.0-rc.12",
|
"cheerio": "^1.0.0-rc.12",
|
||||||
"chrome-aws-lambda": "^10.1.0",
|
"chrome-aws-lambda": "^10.1.0",
|
||||||
|
156
server.js
156
server.js
@ -1,5 +1,4 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const awsServerlessExpress = require('aws-serverless-express');
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
@ -8,87 +7,89 @@ require('dotenv').config();
|
|||||||
|
|
||||||
const app = express();
|
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 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 dirPath = path.join(__dirname, API_DIR); // Path to the lambda functions dir
|
||||||
const guiPath = path.join(__dirname, 'build');
|
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
|
// Enable CORS
|
||||||
app.use(cors({
|
app.use(cors({
|
||||||
origin: process.env.API_CORS_ORIGIN || '*',
|
origin: process.env.API_CORS_ORIGIN || '*',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Execute the lambda function
|
// Read and register each API function as an Express routes
|
||||||
const executeHandler = async (handler, req) => {
|
fs.readdirSync(dirPath, { withFileTypes: true })
|
||||||
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 })
|
|
||||||
.filter(dirent => dirent.isFile() && dirent.name.endsWith('.js'))
|
.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 => {
|
// Create a single API endpoint to execute all lambda functions
|
||||||
const routeName = file.split('.')[0];
|
app.get('/api', async (req, res) => {
|
||||||
const route = `${API_DIR}/${routeName}`;
|
const results = {};
|
||||||
const handler = require(path.join(dirPath, file)).handler;
|
const { url } = req.query;
|
||||||
|
const maxExecutionTime = process.env.API_TIMEOUT_LIMIT || 20000;
|
||||||
handlers[route] = handler;
|
|
||||||
|
|
||||||
app.get(route, async (req, res) => {
|
const executeHandler = async (handler, req, res) => {
|
||||||
try {
|
return new Promise(async (resolve, reject) => {
|
||||||
const { statusCode = 200, body = '' } = await executeHandler(handler, req);
|
try {
|
||||||
res.status(statusCode).json(JSON.parse(body));
|
const mockRes = {
|
||||||
} catch (err) {
|
status: (statusCode) => mockRes,
|
||||||
res.status(500).json({ error: err.message });
|
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
|
// Handle SPA routing
|
||||||
app.use(historyApiFallback({
|
app.use(historyApiFallback({
|
||||||
rewrites: [
|
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));
|
app.use(express.static(guiPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create serverless express server
|
// Print nice welcome message to user
|
||||||
const port = process.env.PORT || 3000;
|
const printMessage = () => {
|
||||||
const server = awsServerlessExpress.createServer(app).listen(port, () => {
|
console.log(
|
||||||
console.log(`Server is running on port ${port}`);
|
`\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"
|
"@typescript-eslint/types" "5.62.0"
|
||||||
eslint-visitor-keys "^3.3.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":
|
"@vercel/nft@^0.22.0":
|
||||||
version "0.22.6"
|
version "0.22.6"
|
||||||
resolved "https://registry.npmjs.org/@vercel/nft/-/nft-0.22.6.tgz"
|
resolved "https://registry.npmjs.org/@vercel/nft/-/nft-0.22.6.tgz"
|
||||||
@ -6612,15 +6604,6 @@ avvio@^8.2.0:
|
|||||||
debug "^4.0.0"
|
debug "^4.0.0"
|
||||||
fastq "^1.6.1"
|
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:
|
axe-core@^4.6.2:
|
||||||
version "4.7.2"
|
version "4.7.2"
|
||||||
resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz"
|
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"
|
resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz"
|
||||||
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
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:
|
binary-extensions@^2.0.0:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
|
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"
|
resolved "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz"
|
||||||
integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==
|
integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==
|
||||||
|
|
||||||
type-is@^1.6.16, type-is@~1.6.18:
|
type-is@~1.6.18:
|
||||||
version "1.6.18"
|
version "1.6.18"
|
||||||
resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz"
|
resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz"
|
||||||
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
|
||||||
|
Loading…
x
Reference in New Issue
Block a user