import { Request, Response } from 'express' import GenericHandlerEvent, { GenericHandlerEventResponse } from './GenericHandlerEvent.js' import WapiRequest from '../../../API/Request.js' import Globals from '../../../Globals.js' import Logger from '../../../Logger/Logger.js' import Utils from '../../../Util/Utils.js' import Server from '../Server.js' const logger = new Logger({ logLevel: 'INFO' }, 'proxy-container') /** * Creates an async function that handles serverless events and sends a response. * @param {Server['handleServerlessEvent']} serverlessHandler - The serverless handler function. * @returns {Function} - An async function that handles the request and sends a response. */ export default (serverlessHandler: Server['handleServerlessEvent']) => { /** * Handles an HTTP request by invoking a serverless function and processing the response. * @param {Request} request - The HTTP request object. * @param {Response} res - The HTTP response object. * @returns None */ return async (request: Request, res: Response) => { const startTime = Date.now() try { // Generate event with request stuff (http to serverless translation) const event = new GenericHandlerEvent(request, serverlessHandler) // Invoke const invokationResp = await event.invoke() // Respond processServerlessResponse(invokationResp, res) } catch (e) { logger.error('[Proxy] - Exception during execution!', e) logger.error((e as Error).stack) res.status(Globals.Resp_STATUSCODE_EXCEPTION).json({ ...(e instanceof Error ? { message: e.message, stack: e.stack } : (e as object)), err: Globals.Resp_MSG_EXCEPTION, errCode: Globals.Resp_CODE_EXCEPTION, }) } if (!WapiRequest.isHealthCheckPath(request.path)) { logger.info(`[Proxy] - Request took ${Date.now() - startTime}ms`) } } } /** * Processes the response received from a serverless function invocation and sends the appropriate response back to the client. * @param {GenericHandlerEventResponse} invokation - The response object received from the serverless function invocation. * @param {Response} res - The response object to send back to the client. * @returns The response object to send back to the client. */ const processServerlessResponse = (invokation: GenericHandlerEventResponse, res: Response) => { // translate answer to http layer if (invokation && invokation.err) { // err came return res.json({ err: invokation.err }).status(400) } else if (!invokation || !invokation.data) { // invalid response came return res.status(Globals.Resp_STATUSCODE_INVALIDRESP).json({ err: Globals.Resp_MSG_INVALIDRESP, errCode: Globals.Resp_CODE_INVALIDRESP, }) } else { // Check for headers if (invokation.data.headers) { for (const hKey of Object.keys(invokation.data.headers)) { res.header(hKey, invokation.data.headers[hKey]) } } // let response = res.status(invokation.data.statusCode) // check for stream if (invokation.data?.body?.pipe) { invokation.data.body.pipe(response) } else { response = response.json(Utils.parseObjectNullIfEmpty(invokation.data.body) || {}) } return response } }