No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

eventarcEmulator.js 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.EventarcEmulator = void 0;
  4. const express = require("express");
  5. const constants_1 = require("./constants");
  6. const types_1 = require("./types");
  7. const utils_1 = require("../utils");
  8. const emulatorLogger_1 = require("./emulatorLogger");
  9. const registry_1 = require("./registry");
  10. const error_1 = require("../error");
  11. const eventarcEmulatorUtils_1 = require("./eventarcEmulatorUtils");
  12. class EventarcEmulator {
  13. constructor(args) {
  14. this.args = args;
  15. this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.EVENTARC);
  16. this.customEvents = {};
  17. }
  18. createHubServer() {
  19. const registerTriggerRoute = `/emulator/v1/projects/:project_id/triggers/:trigger_name(*)`;
  20. const registerTriggerHandler = (req, res) => {
  21. const projectId = req.params.project_id;
  22. const triggerName = req.params.trigger_name;
  23. if (!projectId || !triggerName) {
  24. const error = "Missing project ID or trigger name.";
  25. this.logger.log("ERROR", error);
  26. res.status(400).send({ error });
  27. return;
  28. }
  29. const bodyString = req.rawBody.toString();
  30. const substituted = bodyString.replaceAll("${PROJECT_ID}", projectId);
  31. const body = JSON.parse(substituted);
  32. const eventTrigger = body.eventTrigger;
  33. if (!eventTrigger) {
  34. const error = `Missing event trigger for ${triggerName}.`;
  35. this.logger.log("ERROR", error);
  36. res.status(400).send({ error });
  37. return;
  38. }
  39. const key = `${eventTrigger.eventType}-${eventTrigger.channel}`;
  40. this.logger.logLabeled("BULLET", "eventarc", `Registering custom event trigger for ${key} with trigger name ${triggerName}.`);
  41. const customEventTriggers = this.customEvents[key] || [];
  42. customEventTriggers.push({ projectId, triggerName, eventTrigger });
  43. this.customEvents[key] = customEventTriggers;
  44. res.status(200).send({ res: "OK" });
  45. };
  46. const publishEventsRoute = `/projects/:project_id/locations/:location/channels/:channel::publishEvents`;
  47. const publishEventsHandler = (req, res) => {
  48. const channel = `projects/${req.params.project_id}/locations/${req.params.location}/channels/${req.params.channel}`;
  49. const body = JSON.parse(req.rawBody.toString());
  50. for (const event of body.events) {
  51. if (!event.type) {
  52. res.sendStatus(400);
  53. return;
  54. }
  55. this.logger.log("INFO", `Received custom event at channel ${channel}: ${JSON.stringify(event, null, 2)}`);
  56. this.triggerCustomEventFunction(channel, event);
  57. }
  58. res.sendStatus(200);
  59. };
  60. const dataMiddleware = (req, _, next) => {
  61. const chunks = [];
  62. req.on("data", (chunk) => {
  63. chunks.push(chunk);
  64. });
  65. req.on("end", () => {
  66. req.rawBody = Buffer.concat(chunks);
  67. next();
  68. });
  69. };
  70. const hub = express();
  71. hub.post([registerTriggerRoute], dataMiddleware, registerTriggerHandler);
  72. hub.post([publishEventsRoute], dataMiddleware, publishEventsHandler);
  73. hub.all("*", (req, res) => {
  74. this.logger.log("DEBUG", `Eventarc emulator received unknown request at path ${req.path}`);
  75. res.sendStatus(404);
  76. });
  77. return hub;
  78. }
  79. async triggerCustomEventFunction(channel, event) {
  80. if (!registry_1.EmulatorRegistry.isRunning(types_1.Emulators.FUNCTIONS)) {
  81. this.logger.log("INFO", "Functions emulator not found. This should not happen.");
  82. return Promise.reject();
  83. }
  84. const key = `${event.type}-${channel}`;
  85. const triggers = this.customEvents[key] || [];
  86. return await Promise.all(triggers
  87. .filter((trigger) => !trigger.eventTrigger.eventFilters ||
  88. this.matchesAll(event, trigger.eventTrigger.eventFilters))
  89. .map((trigger) => registry_1.EmulatorRegistry.client(types_1.Emulators.FUNCTIONS)
  90. .request({
  91. method: "POST",
  92. path: `/functions/projects/${trigger.projectId}/triggers/${trigger.triggerName}`,
  93. body: JSON.stringify((0, eventarcEmulatorUtils_1.cloudEventFromProtoToJson)(event)),
  94. responseType: "stream",
  95. resolveOnHTTPError: true,
  96. })
  97. .then((res) => {
  98. if (res.status >= 400) {
  99. throw new error_1.FirebaseError(`Received non-200 status code: ${res.status}`);
  100. }
  101. })
  102. .catch((err) => {
  103. this.logger.log("ERROR", `Failed to trigger Functions emulator for ${trigger.triggerName}: ${err}`);
  104. })));
  105. }
  106. matchesAll(event, eventFilters) {
  107. return Object.entries(eventFilters).every(([key, value]) => {
  108. var _a, _b;
  109. let attr = (_a = event[key]) !== null && _a !== void 0 ? _a : event.attributes[key];
  110. if (typeof attr === "object" && !Array.isArray(attr)) {
  111. attr = (_b = attr.ceTimestamp) !== null && _b !== void 0 ? _b : attr.ceString;
  112. }
  113. return attr === value;
  114. });
  115. }
  116. async start() {
  117. const { host, port } = this.getInfo();
  118. const server = this.createHubServer().listen(port, host);
  119. this.destroyServer = (0, utils_1.createDestroyer)(server);
  120. return Promise.resolve();
  121. }
  122. async connect() {
  123. return Promise.resolve();
  124. }
  125. async stop() {
  126. if (this.destroyServer) {
  127. await this.destroyServer();
  128. }
  129. }
  130. getInfo() {
  131. const host = this.args.host || constants_1.Constants.getDefaultHost();
  132. const port = this.args.port || constants_1.Constants.getDefaultPort(types_1.Emulators.EVENTARC);
  133. return {
  134. name: this.getName(),
  135. host,
  136. port,
  137. };
  138. }
  139. getName() {
  140. return types_1.Emulators.EVENTARC;
  141. }
  142. }
  143. exports.EventarcEmulator = EventarcEmulator;