import RequestResponseContext from "./RequestResponseContext"; import APISample from "../common/data/APISample"; import RegisteredApiBufferManager from "../buffer/RegisteredApiBufferManager"; import DiscoveredApiBufferManager from "../buffer/DiscoveredApiBufferManager"; import BufferManagerWorker from "../buffer/BufferManagerWorker"; import ApiBufferKey from "../buffer/ApiBufferKey"; import { HttpRequestMethod } from "../common/constant/ShortloopCommonConstant"; import HttpResponse from "./HttpResponse"; import SDKLogger from "../SDKLogger"; class ApiProcessor { private readonly registeredApiBufferManager: RegisteredApiBufferManager; private readonly discoveredApiBufferManager: DiscoveredApiBufferManager; private size = 10; private apiSamples: APISample[] = new Array(this.size); private index = 0; constructor( registeredApiBufferManager: RegisteredApiBufferManager, discoveredApiBufferManager: DiscoveredApiBufferManager ) { this.registeredApiBufferManager = registeredApiBufferManager; this.discoveredApiBufferManager = discoveredApiBufferManager; } public processRegisteredApi( context: RequestResponseContext, req: any, res: any, next: Function ): void { // let worker: BufferManagerWorker | null = // this.registeredApiBufferManager.getWorker(); // if (!worker) { // next(); // return; // } context.setPayloadCaptureAttempted(true); // let canOffer: boolean = worker.canOffer(context.getApiBufferKey()); let canOffer: boolean = true; let requestPayloadCaptureAttempted: boolean = true; let responsePayloadCaptureAttempted: boolean = true; if (!canOffer) { next(); return; } requestPayloadCaptureAttempted = true; if (requestPayloadCaptureAttempted) { try { if (typeof req.body === "object") { context.getRequest().setBody(JSON.stringify(req.body)); } else { context.getRequest().setBody(req.body); } } catch (err) { SDKLogger.error("reading request body" + err); } } let startTime: number = Date.now(); responsePayloadCaptureAttempted = true; context.setRequestPayloadCaptureAttempted(requestPayloadCaptureAttempted); context.setResponsePayloadCaptureAttempted(responsePayloadCaptureAttempted); const _end = res.end; const _write = res.write; const chunks: any = []; res.write = function (chunk: any) { if (responsePayloadCaptureAttempted) { if (chunk) chunks.push(chunk); } _write.apply(res, arguments); }; const call = () => { return new Promise((resolve, reject) => { res.end = function (chunk: any) { try { if (responsePayloadCaptureAttempted) { if (chunk) chunks.push(chunk); } context.setResponse( new HttpResponse(res.getHeaders(), res.statusCode) ); context.setLatency(Date.now() - startTime); if (responsePayloadCaptureAttempted) { const body = Buffer.concat(chunks).toString("utf8"); context.getResponse()?.setBody(body); } } catch (err) { SDKLogger.error("reading response body of captured api" + err); } _end.apply(res, arguments); resolve(); }; next(); }); }; call().then(() => { if (canOffer) { this.tryOffering(context); } }); } private tryOffering( context: RequestResponseContext ): void { try { // SDKLogger.log("offering api sample to buffer " + context.getApiBufferKey()) let apiSample: APISample = this.getBufferEntryForApiSample(context); this.apiSamples[this.index] = apiSample; this.index = (this.index + 1) % this.size; } catch (e) { SDKLogger.error("while offering api sample to buffer" + e); } } // print apiSamples every 30 seconds public printApiSamples(): void { setInterval(() => { SDKLogger.log("len: " + this.apiSamples.length); SDKLogger.log("apiSamples arr: " + this.apiSamples); for (let i = 0; i < this.apiSamples.length; i++) { SDKLogger.log("apiSample: " + JSON.stringify(this.apiSamples[i])); } }, 30000); } private shouldCaptureRequest(context: RequestResponseContext): boolean { return ( context && context.getApiConfig() && context.getApiConfig().getCaptureSampleRequest() ); } private shouldCaptureResponse(context: RequestResponseContext): boolean { return ( context && context.getApiConfig() && context.getApiConfig().getCaptureSampleResponse() ); } private getBufferEntryForApiSample( context: RequestResponseContext ): APISample { let apiSample: APISample = new APISample({ rawUri: context.getRequest()?.getRawUri(), method: context.getRequest()?.getMethod() as HttpRequestMethod, applicationName: context.getApplicationName(), hostName: context.getRequest()?.getHostName(), port: context.getRequest()?.getPort(), scheme: context.getRequest()?.getScheme(), parameters: context.getRequest()?.getParams(), requestHeaders: context.getRequest()?.getHeaders(), responseHeaders: context.getResponse()?.getHeaders(), statusCode: context.getResponse()?.getStatusCode(), requestPayload: context.getRequest()?.getBody(), responsePayload: context.getResponse()?.getBody(), uncaughtExceptionMessage: null, payloadCaptureAttempted: context.isPayloadCaptureAttempted(), requestPayloadCaptureAttempted: context.isRequestPayloadCaptureAttempted(), responsePayloadCaptureAttempted: context.isResponsePayloadCaptureAttempted(), latency: context.getLatency(), }); if (context.getApiConfig()) { apiSample.setMethod(context.getApiConfig().getMethod()); } else { apiSample.setMethod(context.getObservedApi().getMethod()); } return apiSample; } } export default ApiProcessor;