web-check/server.js

101 lines
2.9 KiB
JavaScript
Raw Normal View History

const express = require('express');
const awsServerlessExpress = require('aws-serverless-express');
const fs = require('fs');
const path = require('path');
2023-08-10 00:29:58 +02:00
const historyApiFallback = require('connect-history-api-fallback');
require('dotenv').config();
const app = express();
2023-08-10 00:29:58 +02:00
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
// 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);
2023-08-10 00:29:58 +02:00
if (promise && typeof promise.then === 'function') {
promise.then(resolve).catch(reject);
}
});
};
2023-08-10 00:29:58 +02:00
// Array of all the lambda function file names
const fileNames = fs.readdirSync(dirPath, { withFileTypes: true })
.filter(dirent => dirent.isFile() && dirent.name.endsWith('.js'))
.map(dirent => dirent.name);
2023-08-10 00:29:58 +02:00
const handlers = {};
fileNames.forEach(file => {
2023-08-10 00:29:58 +02:00
const routeName = file.split('.')[0];
const route = `${API_DIR}/${routeName}`;
const handler = require(path.join(dirPath, file)).handler;
handlers[route] = handler;
app.get(route, async (req, res) => {
try {
2023-08-10 00:29:58 +02:00
const { statusCode = 200, body = '' } = await executeHandler(handler, req);
res.status(statusCode).json(JSON.parse(body));
} catch (err) {
res.status(500).json({ error: err.message });
}
});
});
2023-08-10 00:29:58 +02:00
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` : ''}`));
2023-08-10 00:29:58 +02:00
}, ms);
});
}
app.get('/api', async (req, res) => {
const results = {};
2023-08-10 00:29:58 +02:00
const { url } = req.query;
const maxExecutionTime = process.env.API_TIMEOUT_LIMIT || 15000;
2023-08-10 00:29:58 +02:00
const handlerPromises = Object.entries(handlers).map(async ([route, handler]) => {
2023-08-10 00:29:58 +02:00
const routeName = route.replace(`${API_DIR}/`, '');
try {
2023-08-10 00:29:58 +02:00
const result = await Promise.race([
executeHandler(handler, { query: { url } }),
timeout(maxExecutionTime, routeName)
]);
results[routeName] = JSON.parse((result || {}).body);
} catch (err) {
2023-08-10 00:29:58 +02:00
results[routeName] = { error: err.message };
}
});
await Promise.all(handlerPromises);
res.json(results);
});
2023-08-10 00:29:58 +02:00
// Handle SPA routing
app.use(historyApiFallback({
rewrites: [
{ from: /^\/api\/.*$/, to: function(context) { return context.parsedUrl.path; } },
]
}));
// Serve React App (static files from ./build)
app.use(express.static(path.join(__dirname, 'build')));
// Create serverless express server
2023-08-10 00:29:58 +02:00
const port = process.env.API_PORT || 3000;
const server = awsServerlessExpress.createServer(app).listen(port, () => {
console.log(`Server is running on port ${port}`);
});
exports.handler = (event, context) => {
awsServerlessExpress.proxy(server, event, context);
};