This is an automated email from the ASF dual-hosted git repository.

ejones pushed a commit to branch karapace-router
in repository https://gitbox.apache.org/repos/asf/flagon-useralejs.git

commit 38d3c37683d26a9d47177ea18d8edff558ce01cb
Author: Evan Jones <evan.a.jon...@gmail.com>
AuthorDate: Thu Jul 25 15:16:09 2024 -0400

    feat(examples): add karapace router server to examples
---
 Dockerfile                 |   4 +-
 example/karapace-router.js | 123 +++++++++++++++++++++++++++++++++++++++++++++
 package-lock.json          |  17 ++++++-
 package.json               |   3 +-
 tsconfig.json              |  26 ++++++++--
 5 files changed, 163 insertions(+), 10 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 5dd4369..18d2464 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -25,6 +25,6 @@ RUN 
--mount=type=bind,target=./package.json,src=./package.json \
 COPY ./src src/
 COPY ./example example/
 
-EXPOSE 8000
 
-CMD ["node", "example/server.js"]
+EXPOSE 8000 
+ENTRYPOINT ["node"]
diff --git a/example/karapace-router.js b/example/karapace-router.js
new file mode 100644
index 0000000..835616b
--- /dev/null
+++ b/example/karapace-router.js
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const commander = require('commander');
+const { program } = require('commander');
+const express  = require('express');
+const bodyParser  =  require('body-parser');
+
+// Functions.
+const myParseInt = (value, _dummyPrevious) =>  {
+  // parseInt takes a string and a radix
+  const parsedValue = parseInt(value, 10);
+  if (isNaN(parsedValue)) {
+    throw new commander.InvalidArgumentError('Not a number.');
+  }
+  return parsedValue;
+}
+
+const configureCors = (req, res, next) => {
+  res.header("Access-Control-Allow-Origin", "*");
+  res.header("Access-Control-Allow-Methods", "POST,OPTIONS");
+  res.header(
+    "Access-Control-Allow-Headers",
+    "Content-Type, Authorization, Content-Length, X-Requested-With",
+  );
+
+  // intercept OPTIONS method
+  if ("OPTIONS" == req.method) {
+    res.sendStatus(200);
+  } else {
+    next();
+  }
+};
+
+const transformAndForward = async (req, res) => {
+  try {
+    const body = typeof req.body === "string" ? JSON.parse(req.body) : 
req.body;
+
+    // Sometimes UserALE sends empty buffers or empty objects, these need to 
be filtered out
+    const isEmptyArray = Array.isArray(body) && body.length === 0;
+    const isEmptyObject =
+      typeof body === "object" &&
+      body !== null &&
+      Object.keys(body).length === 0;
+    if (isEmptyArray || isEmptyObject) return;
+
+    const transformedPayload = {
+      records: body.forEach((log) => ({
+        key: log["sessionId"],
+        value: log,
+      })),
+    };
+
+    if (options.verbose) console.log(transformedPayload);
+
+    const response = await fetch(options.forwardTo, {
+      method: "POST",
+      body: JSON.stringify(transformedPayload),
+      headers: { "Content-Type": "application/json" },
+    });
+
+    const statusCode = response.status;
+
+    res.status(statusCode).send(`Forwarded status code: ${statusCode}`);
+  } catch (error) {
+    console.error("Error: ", error);
+    res.status(500).send("Internal service error");
+  }
+};
+
+const gracefulShutdown = () => {
+  process.exit();
+};
+
+// Args
+program
+  .requiredOption("-f, --forward-to <forward-address>", "Forwarding address")
+  .option("-p, --port <port>", "Port number", myParseInt, 8000)
+  .option("-v, --verbose", "Enable verbose mode", false)
+  .parse(process.argv);
+const options = program.opts();
+console.log(options);
+
+// Configure app
+const app = express();
+
+app.set("port", options.port);
+app.use(configureCors);
+app.use(bodyParser.urlencoded({ extended: true, limit: "100mb" }));
+app.use(bodyParser.json({ limit: "100mb" }));
+app.use(bodyParser.text());
+
+// Routes
+app.post("/", transformAndForward);
+
+// Server
+app.listen(app.get("port"), () => {
+  console.log(
+    "UserALE Karapace Router started...",
+    `\n\tPort: ${app.get("port")}`,
+    `\n\tForwarding address: ${options.forwardTo}`,
+    `\n\tVerbose: ${options.verbose}`,
+  );
+});
+
+process.on("SIGTERM", () => gracefulShutdown());
+process.on("SIGINT", () => gracefulShutdown());
diff --git a/package-lock.json b/package-lock.json
index ccf853c..0ab7165 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -34,6 +34,7 @@
         "@typescript/lib-dom": "npm:@types/web@^0.0.144",
         "babel-jest": "^29.7.0",
         "body-parser": "^1.20.2",
+        "commander": "^12.1.0",
         "cypress": "^13.6.0",
         "cz-conventional-changelog": "^3.3.0",
         "detect-browser": "^5.3.0",
@@ -4498,11 +4499,13 @@
       }
     },
     "node_modules/commander": {
-      "version": "6.2.1",
+      "version": "12.1.0",
+      "resolved": 
"https://registry.npmjs.org/commander/-/commander-12.1.0.tgz";,
+      "integrity": 
"sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
       "dev": true,
       "license": "MIT",
       "engines": {
-        "node": ">= 6"
+        "node": ">=18"
       }
     },
     "node_modules/commenting": {
@@ -4972,6 +4975,16 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/cypress/node_modules/commander": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz";,
+      "integrity": 
"sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/cypress/node_modules/has-flag": {
       "version": "4.0.0",
       "dev": true,
diff --git a/package.json b/package.json
index df03057..1657233 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
     "clean": "rm -rf ./build",
     "test": "npm run test:unit && npm run test:e2e",
     "test:unit": "jest -c ./test/unit/jest.config.ts",
-    "test:e2e": "playwright test -c ./test/e2e/playwright.config.ts",
+    "test:e2e": "xvfb-run playwright test -c ./test/e2e/playwright.config.ts",
     "pretest:e2e": "rm -rf ./test/e2e/chromeData/*",
     "posttest:e2e": "rm -rf ./test/e2e/chromeData/*",
     "example:run": "node example/server.js",
@@ -84,6 +84,7 @@
     "@typescript/lib-dom": "npm:@types/web@^0.0.144",
     "babel-jest": "^29.7.0",
     "body-parser": "^1.20.2",
+    "commander": "^12.1.0",
     "cypress": "^13.6.0",
     "cz-conventional-changelog": "^3.3.0",
     "detect-browser": "^5.3.0",
diff --git a/tsconfig.json b/tsconfig.json
index 853b8a4..7b86f3b 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,7 +13,11 @@
         "isolatedModules": true,
         "incremental": true,
         "jsx": "preserve",
-        "lib": ["dom", "dom.iterable", "esnext"],
+        "lib": [
+            "dom",
+            "dom.iterable",
+            "esnext"
+        ],
         "module": "esnext",
         "moduleResolution": "node",
         "noEmit": true,
@@ -22,7 +26,9 @@
         "noUnusedLocals": true,
         "noUnusedParameters": false,
         "paths": {
-            "@/*": ["./src/*"]
+            "@/*": [
+                "./src/*"
+            ]
         },
         "pretty": true,
         "resolveJsonModule": true,
@@ -30,8 +36,18 @@
         "sourceMap": true,
         "strict": true,
         "target": "es2015",
-        "typeRoots": ["node_modules/@types/"],
+        "typeRoots": [
+            "node_modules/@types/"
+        ],
     },
-    "include": ["src", "test", "src/types.d.ts"],
-    "exclude": ["node_modules", "build", "logs", "example"],
+    "include": [
+        "src",
+        "test",
+        "src/types.d.ts"
+    ],
+    "exclude": [
+        "node_modules",
+        "build",
+        "logs"
+    ],
 }

Reply via email to