clients/request-client.ts (80 lines of code) (raw):

/* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ import { IAsyncCommandChain, IClient } from "../core/ext-types.js" import express from "express"; import { IExecutionResult } from "../core/pipeline-types.js"; function makeCommandChain() { const exposeResolve = function (resolve) { this.resolveNext = resolve; }; const commandChainTemplate: any = { command: null, resolveNext: function (_: IAsyncCommandChain) {}, }; commandChainTemplate.next = new Promise<IAsyncCommandChain>( exposeResolve.bind(commandChainTemplate) ); return commandChainTemplate as IAsyncCommandChain; } /* * Corresponding environment variables * CLIENT_REQUEST_PORT=<request path> * | default_value: 3333 * CLIENT_REQUEST_ACCESS_TOKEN=<access token> * | default_value: none */ const requestClient: IClient = { name: "request", makeCommandGenerator: () => { /* * Utilize function closure to spin up server and * stream commands to generator */ /* Create a command chain to notify async generator with commands */ const asyncCommandChain: IAsyncCommandChain = makeCommandChain(); let serverCommandChainLink: IAsyncCommandChain = asyncCommandChain; const app = express(); app.use(express.json()); const defaultPort = 3333; const port = process.env.CLIENT_REQUEST_PORT ?? defaultPort; /* security */ app.use(function (req, res, next) { if (process.env.CLIENT_REQUEST_ACCESS_TOKEN === undefined) { next(); return; } let bearerToken = ""; if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { bearerToken = req.headers.authorization.split(' ')[1]; } if (bearerToken == process.env.CLIENT_REQUEST_ACCESS_TOKEN) { next(); return; } res.status(401); res.json({ "status": "Unauthorized, please include bearer token.", }); }) /* accept execution requests via post endpoint */ let testId = 1; app.post('/execute', async function (req, res) { const config = req.body; const handleExecutionResult = async (executionResult: IExecutionResult) => { res.json({ testId, status: `Execution ${(executionResult.isExecutionSuccess) ? "success" : "failed"}. Validation ${(executionResult.isValidationSuccess) ? "success" : "failed"}`, metrics: [], /* Add metrics evaluation */ testConfiguration: config, executionResult, }); ++testId; }; let nextServerCommandChainLink = makeCommandChain(); nextServerCommandChainLink.command = { pipelineConfiguration: config, handleExecutionResult: handleExecutionResult, }; serverCommandChainLink.resolveNext(nextServerCommandChainLink); serverCommandChainLink = nextServerCommandChainLink; return; }); /* launch server */ const server = app.listen(port, function () { console.log(`Listening for test configurations on port: ${port}`); }); /* wrap server in generator, stream from command chain */ return (async function*() { let asyncCommandChainLink = asyncCommandChain; while (true) { if (asyncCommandChainLink.command !== null) { yield asyncCommandChainLink.command; } asyncCommandChainLink = await asyncCommandChainLink.next; } })(); } }; export default requestClient;