const fetch = require('node-fetch')
let lastRequestTimestamp = 0
// Proxy Service Function (main)
exports.proxyService = async (request, response) => {
// block non POST requests
if (request.method !== 'POST') {
return respondWithForbidden(response)
}
// restrict requests when throttling directive is not meet
if (hasExceededThrottling()) {
return respondWithTooManyRequests(response)
}
// save current timestamp (value used by throttling mechanism)
lastRequestTimestamp = Date.now()
// deliver payload to target host
let targetResponse
try {
targetResponse = await fetch(process.env.TARGET_HOST, {
port: process.env.TARGET_HOST_PORT,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request.body)
})
} catch (error) {
// catch unexpected errors : connection aborted errors, invalid payloads ...
return respondWithTooManyRequests(response)
}
// If error ocurred while delivering request to target host, return fail code
if (targetResponse.status !== 200) {
return respondWithTooManyRequests(response)
}
// payload delivered to target host! Close source connection with OK status
return respondWithOk(response)
}
/******************************************************************************
*
* HELPER FUNCTIONS
*
*****************************************************************************/
// End connection with a 200 status
function respondWithOk(response) {
response.status(200).send({ data: 'Enviado!' })
//response.writeHead(200)
//response.end()
}
// End connection with a Forbidden status
function respondWithForbidden(response) {
response.writeHead(403)
response.end()
}
// End connection with a Too many requests status
function respondWithTooManyRequests(response) {
response.writeHead(429, {'Retry-After': 2})
response.end()
}
// Check is throttling directive is meet
function hasExceededThrottling() {
const throttlingInMillis = 1000 / 10 // process.env.REQUESTS_PER_SECONDS
const timeSinceLastRequestInMillis = Date.now() - lastRequestTimestamp
return timeSinceLastRequestInMillis < throttlingInMillis ? true : false
}