UNPKG

serverless-spy

Version:

CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.

181 lines (179 loc) 5.97 kB
const __dirname = import.meta.dirname; import { envVariableNames, init_envVariableNames } from "../src/common/envVariableNames.mjs"; import { getConnection } from "../listener/iot-connection.mjs"; import { getTopic } from "../listener/topic.mjs"; import v4_default from "../node_modules/uuid/dist/esm-node/v4.mjs"; import { unmarshall } from "@aws-sdk/util-dynamodb"; //#region common/SpyEventSender.ts init_envVariableNames(); var SpyEventSender = class { constructor(params) { this.debugMode = process.env[envVariableNames.SSPY_DEBUG] === "true"; if (params.log) this.log = params.log; if (params.logError) this.logError = params.logError; this.scope = params.scope; this.iotEndpoint = params.iotEndpoint; } async close() { this.connection?.end(); } async connect() { this.connection = await getConnection(this.debugMode, this.iotEndpoint); } async publishSpyEvent(event) { this.log("Event", JSON.stringify(event)); const mapping = JSON.parse(process.env[envVariableNames.SSPY_INFRA_MAPPING]); this.log("ARN to names mapping", JSON.stringify(mapping)); const postDataPromises = []; if (event?.Records && event.Records[0]?.Sns) { const eventSns = event; for (const record of eventSns.Records) { const subscriptionArn = record.EventSubscriptionArn; let serviceKey; if (mapping[subscriptionArn]) serviceKey = mapping[subscriptionArn]; else serviceKey = mapping[record.Sns.TopicArn]; let message; try { message = JSON.parse(record.Sns.Message); } catch { message = record.Sns.Message; } const fluentEvent = { data: { spyEventType: this.getSpyEventType(serviceKey), message, subject: record.Sns.Subject, timestamp: record.Sns.Timestamp, topicArn: record.Sns.TopicArn, messageId: record.Sns.MessageId, messageAttributes: record.Sns.MessageAttributes }, serviceKey }; postDataPromises.push(this.postData(fluentEvent)); } } else if (event?.Records && event.Records[0]?.eventSource === "aws:sqs") { const eventSqs = event; for (const record of eventSqs.Records) { const serviceKey = mapping[record.eventSourceARN]; let body; try { body = JSON.parse(record.body); } catch { body = record.body; } const fluentEvent = { data: { spyEventType: "Sqs", body, messageAttributes: record.messageAttributes }, serviceKey }; postDataPromises.push(this.postData(fluentEvent)); } } else if (event?.Records && event.Records[0]?.s3) { const eventS3 = event; for (const record of eventS3.Records) { const bucketArn = record.s3.bucket.arn; const fluentEvent = { data: { spyEventType: "S3", eventName: record.eventName, eventTime: record.eventTime, bucket: record.s3.bucket.name, key: record.s3.object.key }, serviceKey: mapping[bucketArn] }; postDataPromises.push(this.postData(fluentEvent)); } } else if (event.Records && event.Records[0]?.dynamodb) { const eventDynamoDB = event; for (const record of eventDynamoDB.Records) { let arn = record.eventSourceARN; arn = arn.substring(0, arn.indexOf("/stream/")); const fluentEvent = { data: { spyEventType: "DynamoDB", eventName: record.eventName, newImage: record.dynamodb?.NewImage ? unmarshall(record.dynamodb?.NewImage) : void 0, keys: unmarshall(record.dynamodb?.Keys), oldImage: record.dynamodb?.OldImage ? unmarshall(record.dynamodb?.OldImage) : void 0 }, serviceKey: mapping[arn] }; postDataPromises.push(this.postData(fluentEvent)); } } else if (event.detail && event["detail-type"] && event.version && event.source) { const eventEb = event; const serviceKey = mapping.eventBridge; const fluentEvent = { data: { spyEventType: this.getSpyEventType(serviceKey), detail: eventEb.detail, detailType: eventEb["detail-type"], eventBridgeId: eventEb["id"], source: eventEb.source, time: eventEb.time, account: eventEb.account }, serviceKey }; postDataPromises.push(this.postData(fluentEvent)); } else { const fluentEvent = event; postDataPromises.push(this.postData(fluentEvent)); } await Promise.all(postDataPromises); } encode(input) { const parts = JSON.stringify(input).match(/.{1,50000}/g); if (!parts) return []; this.log(`Encoded iot message, ${parts.length}`); const id = v4_default(); return parts.map((part, index) => ({ id, index, count: parts.length, data: part })); } async postData(spyMessage) { if (this.connection === void 0) throw new Error("No IoT connection created yet, did you forget to call connect()?"); const withTimeStamp = { ...spyMessage, timestamp: spyMessage.timestamp || (/* @__PURE__ */ new Date()).toISOString() }; this.log("Post spy message", JSON.stringify(withTimeStamp)); const connection = this.connection; const topic = getTopic(this.scope); try { for (const fragment of this.encode(withTimeStamp)) { await new Promise((resolve) => { connection.publish(topic, JSON.stringify(fragment), { qos: 1 }, () => { this.log("Publishing finished"); resolve(); }); }); this.log(`Published fragment ${fragment.index} out of ${fragment.count} to topic ${topic}`); } } catch (e) { this.logError(`Failed to send payload to iot: ${e}`); } this.log("Send spy message finish"); } getSpyEventType(serviceKey) { if (!serviceKey) throw new Error("Missing serviceKey"); return serviceKey.substring(0, serviceKey.indexOf("#")); } log(message, ...optionalParams) { if (this.debugMode) console.debug("SSPY EXTENSION", message, ...optionalParams); } logError(message, ...optionalParams) { if (this.debugMode) console.error("SSPY EXTENSION", message, ...optionalParams); } }; //#endregion export { SpyEventSender }; //# sourceMappingURL=SpyEventSender.mjs.map