Files

142 lines
4.3 KiB
JavaScript

const express = require('express');
const axios = require('axios');
const app = express();
const port = 7000;
app.use(express.json({
limit: '500mb'
}));
const API_KEY = process.env.API_KEY || "silly!"
const RETRY_ERROR_CODES = [408, 500, 502, 503, 504, 522, 524, 599];
async function main() {
const responses = [];
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
async function RegisterResponse(instanceId, response) {
if (!responses[instanceId]) {
responses[instanceId] = []
}
responses[instanceId].push({
id: response.id,
data: response.data,
error: response.error,
status: response.status
})
//console.log(`Response registered for instance ${instanceId}`);
setTimeout(() => {
if (!responses[instanceId]) {
return;
}
responses[instanceId] = responses[instanceId].filter(resp => resp.id !== response.id);
//console.log(`Response ${response.id} removed from instance ${instanceId}`);
}, 60_000);
}
async function DoRequest(instanceId, requestObj, retriesLeft = 3) {
const requestParams = requestObj.request || {};
const method = requestParams.Method?.toLowerCase() || 'get';
const url = requestParams.Url || '';
const body = requestParams.Body || '';
let headers = requestParams.Headers || null;
// if headers is a an array or is an empty object, convert it to null
if (headers && (Array.isArray(headers) || Object.keys(headers).length === 0)) {
headers = null;
}
const shouldHaveBody = ['post', 'put', 'patch'].includes(method);
console.log("DoRequest",instanceId,requestObj)
try {
const response = await axios({
method: method,
url: url,
headers: headers,
data: shouldHaveBody ? body : null
});
RegisterResponse(instanceId, {
id: requestObj.id,
data: response.data
});
} catch (error) {
const statusCode = error.response?.status;
if (RETRY_ERROR_CODES.includes(statusCode) && retriesLeft > 0) {
console.log(`Retrying request ${requestObj.id} for instance ${instanceId}, HTTP ${statusCode}`);
setTimeout(() => {
DoRequest(instanceId, requestObj, retriesLeft - 1);
}, 1000);
} else {
RegisterResponse(instanceId, {
id: requestObj.id,
data: error.response?.data,
status: statusCode,
error: {
message: error.message || 'Unknown error',
}
});
}
}
}
function getToSend(instanceId, waiting) {
const toSend = [];
const instanceResponses = responses[instanceId] || [];
instanceResponses.forEach(respObj => {
if (waiting.includes(respObj.id)) {
toSend.push(respObj);
}
});
return toSend;
}
app.post('/:instanceId', async (req, res) => {
const apikey = req.headers['x-batchhttp-api-key'];
if (apikey !== API_KEY) {
res.status(401).send({
error: "Invalid API Key"
});
return;
}
const instanceId = req.params.instanceId;
//console.log(`Instance ID: ${instanceId}`);
const body = req.body;
const requests = body.requests || [];
const waiting = body.waiting || []
//console.log(body);
requests.forEach(requestObj => {
DoRequest(instanceId,requestObj);
});
const startTime = Date.now();
let toSend = []
while (toSend.length === 0 && Date.now() - startTime < 1_000) {
toSend = getToSend(instanceId, waiting);
await new Promise(resolve => setTimeout(resolve, 10));
}
console.log(`${toSend.length} responses ready for instance ${instanceId}`);
res.send({
responses: toSend
});
})
}
main();