From 1ddfc8c769ca094c6e0e4763076ec187f7a388ab Mon Sep 17 00:00:00 2001 From: Christopher Hase Date: Tue, 15 Apr 2025 16:28:48 +0200 Subject: [PATCH 1/6] add http-server part 9.1 --- backend/broker.ts | 17 ++++++++--------- backend/server.ts | 7 +++++-- frontend/event.ts | 4 ++-- frontend/index.html | 5 +++-- start.sh | 0 5 files changed, 18 insertions(+), 15 deletions(-) mode change 100644 => 100755 start.sh diff --git a/backend/broker.ts b/backend/broker.ts index 391235b..5cbee8d 100644 --- a/backend/broker.ts +++ b/backend/broker.ts @@ -22,7 +22,7 @@ export function executeCommand(): void { exec('iching divine', (error, stdout, stderr) => { - console.log(`Begin`); + console.log(`I-Ching-Broker: \'iching divine\' called`); if (error) { console.error(`Error: ${error.message}`); @@ -39,7 +39,7 @@ export function executeCommand(): void { config = loadConfig(); } */ - console.log(`Send E-Mail`); + console.log(`Horoscope received; sending E-Mail next`); sendEmail(stdout); }); } @@ -75,9 +75,11 @@ async function sendEmail(content: string) { html: html(content) }); - console.log("E-Mail sent: ", info.messageId + "\n"); + console.log("E-Mail sent: ", info.messageId + "\n\n"); } catch (error) { - console.error("Error Sending E-Mail:", error); + console.error("Error Sending E-Mail:", error + "\n\n"); + + console.log("Failed to send horoscope: \n", content + "\n"); } } @@ -119,7 +121,7 @@ function parse(input: string): Node { const changingLines: Node = { type: "ChangingLines"}; currentNode.child = changingLines; currentNode = changingLines; - currentNode.value = line; // + "
"; TODO: try without this
+ currentNode.value = line; } else { currentNode.value = currentNode.value + line + "
"; } @@ -132,13 +134,11 @@ function parse(input: string): Node { function render(node: Node): string { if (node == undefined) { - console.log("Rendering of nodes finished!") + console.log("I-Ching-Broker: Rendering of nodes finished!") return ""; } - console.log("Render node" + node.type); - var outputHTML: string = ""; switch (node.type) { @@ -161,7 +161,6 @@ function render(node: Node): string { case "ChangingLines" : const regex = new RegExp("~", "g"); node.value = node.value?.replace(regex, ""); - //outputHTML = "

" + node.value + "


"; outputHTML = "

" + node.value + "


"; outputHTML = outputHTML + render(node.child!); return outputHTML; diff --git a/backend/server.ts b/backend/server.ts index c045e0e..4a76fc7 100644 --- a/backend/server.ts +++ b/backend/server.ts @@ -8,10 +8,13 @@ const port = 8090; app.use(cors()); app.post('/iching/api/command', (req, res) => { + //TODO no logging from inside this method??? + console.log(`Backend-Server: receiving POST to /iching/api/command`); + executeCommand(); - res.status(200).send('Command executed\n'); + res.status(200).send('Backend-Server: Broker was called\n'); }); app.listen(port, '0.0.0.0', () => { - console.log(`Server lรคuft auf http://0.0.0.0:${port}`); + console.log(`Backend-Server running on http://0.0.0.0:${port}`); }); diff --git a/frontend/event.ts b/frontend/event.ts index 4a7a778..3430561 100644 --- a/frontend/event.ts +++ b/frontend/event.ts @@ -3,8 +3,8 @@ function handleClick(): void { fetch("/iching/api/command", { method: "POST" }) .then(res => res.text()) - .then(text => console.log("Server sagt:", text)) - .catch(error => console.error("Fehler:", error)); + .then(text => console.log("HTTP-Server says:", text)) + .catch(error => console.error("HTTP-Server - Error:", error)); } document.addEventListener("DOMContentLoaded", () => { diff --git a/frontend/index.html b/frontend/index.html index e3a618b..373974f 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -53,10 +53,11 @@
-

๐Ÿง˜ My I-Ging Horoscope

+

Do you want to know the future?

+

โ˜๏ธ Look into the future with your personal I-Ging Horoscope! โ˜๏ธ

Click on the Button to receive your personal Horoscope. 100% accuracy guaranteed!

- +
diff --git a/start.sh b/start.sh old mode 100644 new mode 100755 From f5265a4e1d0b07bb52673475b9a23825eda566c6 Mon Sep 17 00:00:00 2001 From: Christopher Hase Date: Wed, 16 Apr 2025 13:53:25 +0200 Subject: [PATCH 2/6] run in docker part 1.0 --- backend/broker.ts | 2 +- deployment.yaml | 8 ++++++++ frontend/deploy.js | 1 + frontend/event.ts | 11 ++++++++++- frontend/index.html | 2 ++ start.sh | 10 ++++++++++ 6 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 frontend/deploy.js diff --git a/backend/broker.ts b/backend/broker.ts index 5cbee8d..fc012a3 100644 --- a/backend/broker.ts +++ b/backend/broker.ts @@ -79,7 +79,7 @@ async function sendEmail(content: string) { } catch (error) { console.error("Error Sending E-Mail:", error + "\n\n"); - console.log("Failed to send horoscope: \n", content + "\n"); + console.log("Failed to send this horoscope: \n", content + "\n"); } } diff --git a/deployment.yaml b/deployment.yaml index e75a70c..6e77607 100644 --- a/deployment.yaml +++ b/deployment.yaml @@ -1,3 +1,11 @@ +#env: +# - name: DEPLOY_MODE +# value: "kubernetes" +# - name: BACKEND_PORT +# value: "8090" + +#--- + # --- DEPLOYMENT -------------------------------------------- apiVersion: apps/v1 diff --git a/frontend/deploy.js b/frontend/deploy.js new file mode 100644 index 0000000..12e8f02 --- /dev/null +++ b/frontend/deploy.js @@ -0,0 +1 @@ +window.DEPLOY_MODE = "k8s" \ No newline at end of file diff --git a/frontend/event.ts b/frontend/event.ts index 3430561..1735143 100644 --- a/frontend/event.ts +++ b/frontend/event.ts @@ -1,7 +1,16 @@ function handleClick(): void { console.log("Der Button wurde geklickt!"); - fetch("/iching/api/command", { method: "POST" }) + const deployMode = (window as { DEPLOY_MODE?: 'docker' | 'k8s' }).DEPLOY_MODE ?? 'k8s'; + + const endpoint = + deployMode === 'docker' + ? 'http://localhost:8090/iching/api/command' + : '/iching/api/command'; + + console.log(`DEPLOY_MODE=${deployMode}, sende POST an: ${endpoint}`); + + fetch(endpoint, { method: 'POST' }) .then(res => res.text()) .then(text => console.log("HTTP-Server says:", text)) .catch(error => console.error("HTTP-Server - Error:", error)); diff --git a/frontend/index.html b/frontend/index.html index 373974f..9c6984a 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -60,6 +60,8 @@ + + \ No newline at end of file diff --git a/start.sh b/start.sh index a48ebb0..1efc7c5 100755 --- a/start.sh +++ b/start.sh @@ -1,3 +1,13 @@ +#!/bin/bash + +# Setze Standard-Wert auf "k8s" wenn DEPLOY_MODE nicht gesetzt ist +DEPLOY_MODE=${DEPLOY_MODE:-k8s} + +echo "DEPLOY_MODE ist: $DEPLOY_MODE" + +# Injektiere ins Frontend +echo "window.DEPLOY_MODE = \"$DEPLOY_MODE\";" > dist/frontend/deploy.js + # start backend in the background node dist/backend/server.js & From 1d62a62f334d6b0828061e75d9adfb06a024722f Mon Sep 17 00:00:00 2001 From: Christopher Hase Date: Wed, 16 Apr 2025 15:37:16 +0200 Subject: [PATCH 3/6] run locally part 1.0 --- README.md | 37 ++++++++++++++++++++++++++++++------- frontend/event.ts | 5 +++-- package.json | 3 ++- start-local.sh | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 10 deletions(-) create mode 100755 start-local.sh diff --git a/README.md b/README.md index 6db6456..0e6ab14 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,6 @@ This app uses the I-Ching library app https://github.com/Velfi/i-ching.git. Properties of the app can be configured in the file config.json. It is possible to configure the mail host and port. It is also possible to configure the intervall of days between the sending of horoscopes and the time of sending. The default is to send one email every seven days at 8 am.--> -## First Start -The app can be deployed by running: - -```bash -$ kubectl apply -f deployment.yaml -``` This will start the deployment of the app in the pod, the service and an ingress for the HTTP frontend server and an ingress for the backend server. When a pod with the app is initally started, one email will be sent to the configured receiver. @@ -44,4 +38,33 @@ The Jest unit tests can be run with ```bash $ npm test ``` ---> \ No newline at end of file +--> + + +## Running the App + +### Locally +The app can be deployed locally by running: +The app can be deployed by running: +```bash +$ ./start-local.sh +``` +Der HTTP-Server can be access in a browser with the address http://localhost:8080/. + +### Locally with Docker +The app can be deployed by running: +```bash +$ docker run -e DEPLOY_MODE=docker -p 8080:8080 -p 8090:8090 --rm my-typescript-app +``` +Der HTTP-Server can be access in a browser with the address http://localhost:8080/. + +### In Kubernetes + +The app can be deployed by running: + +```bash +$ kubectl apply -f deployment.yaml +``` +Der HTTP-Server can be access in a browser with the address https://192-168-197-2.c-one-infra.de/iching/ + + \ No newline at end of file diff --git a/frontend/event.ts b/frontend/event.ts index 1735143..9b464a3 100644 --- a/frontend/event.ts +++ b/frontend/event.ts @@ -1,10 +1,11 @@ function handleClick(): void { console.log("Der Button wurde geklickt!"); - const deployMode = (window as { DEPLOY_MODE?: 'docker' | 'k8s' }).DEPLOY_MODE ?? 'k8s'; + //const deployMode = (window as { DEPLOY_MODE?: 'docker' | 'k8s' }).DEPLOY_MODE ?? 'k8s'; + const deployMode = (window as { DEPLOY_MODE?: 'docker' | 'k8s' | 'local' }).DEPLOY_MODE ?? 'k8s'; const endpoint = - deployMode === 'docker' + deployMode === 'docker' || deployMode === 'local' ? 'http://localhost:8090/iching/api/command' : '/iching/api/command'; diff --git a/package.json b/package.json index d28af51..4bfb90a 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "1.0.0", "main": "broker.js", "scripts": { - "test": "jest --no-cache --force-exit" + "test": "jest --no-cache --force-exit", + "start:local": "tsc -p tsconfig.backend.json && tsc -p tsconfig.frontend.json && DEPLOY_MODE=local node dist/backend/server.js & npx http-server dist/frontend -p 8080 --cors --mime application/javascript=js" }, "keywords": [], "author": "", diff --git a/start-local.sh b/start-local.sh new file mode 100755 index 0000000..1b20eb7 --- /dev/null +++ b/start-local.sh @@ -0,0 +1,35 @@ + +# build +#npm install +#npx tsc -p tsconfig.backend.json +#npx tsc -p tsconfig.frontend.json + +#npm run start:local + +#!/bin/bash + +# Exit on error +set -e + +# 1. Install dependencies +npm install + +# 2. Compile backend and frontend +npx tsc -p tsconfig.backend.json +npx tsc -p tsconfig.frontend.json + +# 3. Ensure dist/frontend exists and copy index.html +mkdir -p dist/frontend +cp frontend/index.html dist/frontend/ + +# 4. Rename compiled frontend .js โ†’ .mjs +find dist/frontend -name "*.js" -exec bash -c 'mv "$0" "${0%.js}.mjs"' {} \; + +# 5. Inject deploy mode +echo "window.DEPLOY_MODE = 'local';" > dist/frontend/deploy.js + +# 6. Start backend +node dist/backend/server.js & + +# 7. Start frontend +npx http-server dist/frontend -p 8080 --cors --mime application/javascript=js From b61a166649d814d2726f09851fa493114371b8ef Mon Sep 17 00:00:00 2001 From: Christopher Hase Date: Thu, 17 Apr 2025 13:50:24 +0200 Subject: [PATCH 4/6] make unit tests runnable again --- README.md | 4 +--- backend/broker.test.ts | 5 ++--- jest.config.ts => old.jest.config.ts | 0 package.json | 9 ++++++--- tsconfig.backend.json | 5 ++--- 5 files changed, 11 insertions(+), 12 deletions(-) rename jest.config.ts => old.jest.config.ts (100%) diff --git a/README.md b/README.md index 0e6ab14..ae36927 100644 --- a/README.md +++ b/README.md @@ -32,14 +32,12 @@ The backend server has a separate ingress, so API requests can get forwarded to The frontend server is running inside the pod on the address http://localhost:8080/iching. It provides an HTML homepage with a button. Upon pressing the button, the backend server will be called (to send an E-Mail). The frontend server has a separate ingress from the backend server, since the frontend server needs the 'rewrite target' annotation: So the Frontend is not running in the root folder but using the sub-path 'iching'. - - ## Running the App diff --git a/backend/broker.test.ts b/backend/broker.test.ts index c4232d1..555a47a 100644 --- a/backend/broker.test.ts +++ b/backend/broker.test.ts @@ -1,5 +1,5 @@ -/*import { html } from "./broker"; -import { test } from "@jest/globals"; +import { html } from "./broker"; +//import { test } from "@jest/globals"; jest.useFakeTimers(); @@ -17,4 +17,3 @@ test("Generate HTML for images", () => { expect(html("Images:\nOver the earth, the lake:\nThe image of Gathering Together.\nThus the superior man renews his weapons\nIn order to meet the unforseen.")) .toBe("

Images:

Over the earth, the lake:
The image of Gathering Together.
Thus the superior man renews his weapons
In order to meet the unforseen.

"); }); -*/ \ No newline at end of file diff --git a/jest.config.ts b/old.jest.config.ts similarity index 100% rename from jest.config.ts rename to old.jest.config.ts diff --git a/package.json b/package.json index 4bfb90a..ce50417 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,7 @@ "version": "1.0.0", "main": "broker.js", "scripts": { - "test": "jest --no-cache --force-exit", - "start:local": "tsc -p tsconfig.backend.json && tsc -p tsconfig.frontend.json && DEPLOY_MODE=local node dist/backend/server.js & npx http-server dist/frontend -p 8080 --cors --mime application/javascript=js" + "test": "jest --no-cache --force-exit" }, "keywords": [], "author": "", @@ -25,5 +24,9 @@ "express": "^5.1.0", "http-server": "^14.1.1", "nodemailer": "^6.10.0" - } + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node" + } } diff --git a/tsconfig.backend.json b/tsconfig.backend.json index db21beb..c5bc144 100644 --- a/tsconfig.backend.json +++ b/tsconfig.backend.json @@ -8,7 +8,6 @@ "esModuleInterop": true, "skipLibCheck": true }, - "include": [ - "backend/**/*.ts" - ] + "include": ["backend/**/*.ts"], + "exclude": ["backend/**/*.test.ts"] } \ No newline at end of file From 628855b5d92fc9400375ada394d6168d272f8cdd Mon Sep 17 00:00:00 2001 From: Christopher Hase Date: Thu, 17 Apr 2025 14:46:32 +0200 Subject: [PATCH 5/6] add config.json again --- backend/broker.ts | 29 +++++---- dist/backend/broker.js | 137 +++++++++++++++++++++++++++++++++++++++ dist/backend/config.json | 5 ++ dist/backend/server.js | 15 +++++ dist/frontend/deploy.js | 1 + dist/frontend/event.mjs | 18 +++++ dist/frontend/index.html | 67 +++++++++++++++++++ start-local.sh | 7 +- 8 files changed, 266 insertions(+), 13 deletions(-) create mode 100644 dist/backend/broker.js create mode 100644 dist/backend/config.json create mode 100644 dist/backend/server.js create mode 100644 dist/frontend/deploy.js create mode 100644 dist/frontend/event.mjs create mode 100644 dist/frontend/index.html diff --git a/backend/broker.ts b/backend/broker.ts index fc012a3..e672cb6 100644 --- a/backend/broker.ts +++ b/backend/broker.ts @@ -1,13 +1,15 @@ import { exec } from 'child_process'; import * as fs from 'fs'; import * as nodemailer from 'nodemailer'; +import { fileURLToPath } from 'url'; +import * as path from 'path'; // Config for scheduling the next time the main process (sending of horoscope) is run -/*interface Config { +interface Config { emailReceiver: string; mailHost: string; mailPort: number; -}*/ +} // Node structure for the Parse Tree (it's a degenerated tree with one or zero children per node) interface Node { @@ -16,7 +18,7 @@ interface Node { value?: string; } -//var config : Config; +var config : Config; export function executeCommand(): void { @@ -35,9 +37,9 @@ export function executeCommand(): void { } //Load config once - /*if (config == undefined) { + if (config == undefined) { config = loadConfig(); - } */ + } console.log(`Horoscope received; sending E-Mail next`); sendEmail(stdout); @@ -48,28 +50,33 @@ export function executeCommand(): void { executeCommand(); // Load the Configuration -/*function loadConfig(): Config { +function loadConfig(): Config { console.log(`Load Config`); - const data = fs.readFileSync('config.json', 'utf-8'); + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + const configPath = path.join(__dirname, 'config.json'); + + const data = fs.readFileSync(configPath, 'utf-8'); + return JSON.parse(data); -}*/ +} // Send E-Mail async function sendEmail(content: string) { // Create Transporter const transporter = nodemailer.createTransport({ - host: "mailhog.mailhog.svc.cluster.local", //config.mailHost, - port: 1025, //config.mailPort, + host: config.mailHost, //"mailhog.mailhog.svc.cluster.local", //config.mailHost, + port: config.mailPort, //1025, //config.mailPort, secure: false }); try { const info = await transporter.sendMail({ from: '"The Oracle" ', - to: "test@mailhog.local", //config.emailReceiver, + to: config.emailReceiver, //"test@mailhog.local", //config.emailReceiver, subject: "Your Horoscope Is Ready", text: content, html: html(content) diff --git a/dist/backend/broker.js b/dist/backend/broker.js new file mode 100644 index 0000000..3977cc9 --- /dev/null +++ b/dist/backend/broker.js @@ -0,0 +1,137 @@ +import { exec } from 'child_process'; +import * as fs from 'fs'; +import * as nodemailer from 'nodemailer'; +import { fileURLToPath } from 'url'; +import * as path from 'path'; +var config; +export function executeCommand() { + exec('iching divine', (error, stdout, stderr) => { + console.log(`I-Ching-Broker: \'iching divine\' called`); + if (error) { + console.error(`Error: ${error.message}`); + return; + } + if (stderr) { + console.error(`Stderr: ${stderr}`); + return; + } + //Load config once + if (config == undefined) { + config = loadConfig(); + } + console.log(`Horoscope received; sending E-Mail next`); + sendEmail(stdout); + }); +} +// Run function once initially, called from Dockerfile +executeCommand(); +// Load the Configuration +function loadConfig() { + console.log(`Load Config`); + //const data = fs.readFileSync('config.json', 'utf-8'); + //const configPath = path.join(__dirname, 'config.json'); + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + const configPath = path.join(__dirname, 'config.json'); + const data = fs.readFileSync(configPath, 'utf-8'); + return JSON.parse(data); +} +// Send E-Mail +async function sendEmail(content) { + // Create Transporter + const transporter = nodemailer.createTransport({ + host: config.mailHost, //"mailhog.mailhog.svc.cluster.local", //config.mailHost, + port: config.mailPort, //1025, //config.mailPort, + secure: false + }); + try { + const info = await transporter.sendMail({ + from: '"The Oracle" ', + to: config.emailReceiver, //"test@mailhog.local", //config.emailReceiver, + subject: "Your Horoscope Is Ready", + text: content, + html: html(content) + }); + console.log("E-Mail sent: ", info.messageId + "\n\n"); + } + catch (error) { + console.error("Error Sending E-Mail:", error + "\n\n"); + console.log("Failed to send this horoscope: \n", content + "\n"); + } +} +// Generate 1) Parse Tree and 2) HTML +export function html(inputText) { + const parseTree = parse(inputText); + const htmlOutput = render(parseTree); + return htmlOutput; +} +// Generate the Parse Tree +function parse(input) { + console.log("Parse input text"); + const root = { type: "Root" }; + var currentNode = root; + const lines = input.split("\n"); + for (const line of lines) { + if (line.startsWith("Hexagram")) { + const hexagram = { type: "Hexagram" }; + currentNode.child = hexagram; + currentNode = hexagram; + currentNode.value = "

" + line + "

"; + } + else if (line.startsWith("Judgement")) { + const judgement = { type: "Judgement" }; + currentNode.child = judgement; + currentNode = judgement; + currentNode.value = "

" + line + "

"; + } + else if (line.startsWith("Images")) { + const images = { type: "Images" }; + currentNode.child = images; + currentNode = images; + currentNode.value = "

" + line + "

"; + } + else if (line.startsWith("~") && currentNode.type != "ChangingLines") { + const changingLines = { type: "ChangingLines" }; + currentNode.child = changingLines; + currentNode = changingLines; + currentNode.value = line; + } + else { + currentNode.value = currentNode.value + line + "
"; + } + } + return root; +} +// Generate HTML from Parse Tree +function render(node) { + if (node == undefined) { + console.log("I-Ching-Broker: Rendering of nodes finished!"); + return ""; + } + var outputHTML = ""; + switch (node.type) { + case "Root": + return render(node.child); + case "Hexagram": + node.value = node.value?.replace("

", "

"); + node.value = node.value?.replace("

", "

"); + node.value = node.value?.replace("
", " - "); + outputHTML = "

" + node.value + "

"; + outputHTML = outputHTML + render(node.child); + return outputHTML; + case "Images": + outputHTML = "

" + node.value + "

"; //EXTRA closing div (was opened at beginning of hexagram) + outputHTML = outputHTML + render(node.child); + return outputHTML; + case "ChangingLines": + const regex = new RegExp("~", "g"); + node.value = node.value?.replace(regex, ""); + outputHTML = "

" + node.value + "


"; + outputHTML = outputHTML + render(node.child); + return outputHTML; + default: + outputHTML = "

" + node.value + "

"; + outputHTML = outputHTML + render(node.child); + return outputHTML; + } +} diff --git a/dist/backend/config.json b/dist/backend/config.json new file mode 100644 index 0000000..121311d --- /dev/null +++ b/dist/backend/config.json @@ -0,0 +1,5 @@ +{ + "emailReceiver": "test@mailhog.local", + "mailHost": "mailhog.mailhog.svc.cluster.local", + "mailPort": 1025 +} \ No newline at end of file diff --git a/dist/backend/server.js b/dist/backend/server.js new file mode 100644 index 0000000..b0f87f6 --- /dev/null +++ b/dist/backend/server.js @@ -0,0 +1,15 @@ +import express from 'express'; +import cors from 'cors'; +import { executeCommand } from './broker.js'; +const app = express(); +const port = 8090; +app.use(cors()); +app.post('/iching/api/command', (req, res) => { + //TODO no logging from inside this method??? + console.log(`Backend-Server: receiving POST to /iching/api/command`); + executeCommand(); + res.status(200).send('Backend-Server: Broker was called\n'); +}); +app.listen(port, '0.0.0.0', () => { + console.log(`Backend-Server running on http://0.0.0.0:${port}`); +}); diff --git a/dist/frontend/deploy.js b/dist/frontend/deploy.js new file mode 100644 index 0000000..402c906 --- /dev/null +++ b/dist/frontend/deploy.js @@ -0,0 +1 @@ +window.DEPLOY_MODE = 'local'; diff --git a/dist/frontend/event.mjs b/dist/frontend/event.mjs new file mode 100644 index 0000000..c0fa2db --- /dev/null +++ b/dist/frontend/event.mjs @@ -0,0 +1,18 @@ +"use strict"; +function handleClick() { + console.log("Der Button wurde geklickt!"); + //const deployMode = (window as { DEPLOY_MODE?: 'docker' | 'k8s' }).DEPLOY_MODE ?? 'k8s'; + const deployMode = window.DEPLOY_MODE ?? 'k8s'; + const endpoint = deployMode === 'docker' || deployMode === 'local' + ? 'http://localhost:8090/iching/api/command' + : '/iching/api/command'; + console.log(`DEPLOY_MODE=${deployMode}, sende POST an: ${endpoint}`); + fetch(endpoint, { method: 'POST' }) + .then(res => res.text()) + .then(text => console.log("HTTP-Server says:", text)) + .catch(error => console.error("HTTP-Server - Error:", error)); +} +document.addEventListener("DOMContentLoaded", () => { + const button = document.getElementById("myButton"); + button?.addEventListener("click", handleClick); +}); diff --git a/dist/frontend/index.html b/dist/frontend/index.html new file mode 100644 index 0000000..9c6984a --- /dev/null +++ b/dist/frontend/index.html @@ -0,0 +1,67 @@ + + + + + + Your I-Ging Horoscope + + + +
+

Do you want to know the future?

+

โ˜๏ธ Look into the future with your personal I-Ging Horoscope! โ˜๏ธ

+

Click on the Button to receive your personal Horoscope. 100% accuracy guaranteed!

+ + +
+ + + + + + \ No newline at end of file diff --git a/start-local.sh b/start-local.sh index 1b20eb7..93cdbc5 100755 --- a/start-local.sh +++ b/start-local.sh @@ -22,8 +22,11 @@ npx tsc -p tsconfig.frontend.json mkdir -p dist/frontend cp frontend/index.html dist/frontend/ -# 4. Rename compiled frontend .js โ†’ .mjs -find dist/frontend -name "*.js" -exec bash -c 'mv "$0" "${0%.js}.mjs"' {} \; +mkdir -p dist/backend +cp backend/config.json dist/backend/ + +# 4. Rename compiled frontend event.js โ†’ event.mjs +find dist/frontend -name "event.js" -exec bash -c 'mv "$0" "${0%.js}.mjs"' {} \; # 5. Inject deploy mode echo "window.DEPLOY_MODE = 'local';" > dist/frontend/deploy.js From bbad13f570c9298d40e60e7f2bfd4abd9bf2ed81 Mon Sep 17 00:00:00 2001 From: Christopher Hase Date: Thu, 17 Apr 2025 16:11:34 +0200 Subject: [PATCH 6/6] add config.json again, part 2 --- README.md | 7 +- dist/backend/broker.js | 137 --------------------------------------- dist/backend/config.json | 5 -- dist/backend/server.js | 15 ----- dist/frontend/deploy.js | 1 - dist/frontend/event.mjs | 18 ----- dist/frontend/index.html | 67 ------------------- 7 files changed, 2 insertions(+), 248 deletions(-) delete mode 100644 dist/backend/broker.js delete mode 100644 dist/backend/config.json delete mode 100644 dist/backend/server.js delete mode 100644 dist/frontend/deploy.js delete mode 100644 dist/frontend/event.mjs delete mode 100644 dist/frontend/index.html diff --git a/README.md b/README.md index ae36927..9de1b6b 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,9 @@ This app will send an I-Ching horoscope to the pre-configured mailhog instance i This app uses the I-Ching library app https://github.com/Velfi/i-ching.git. - - +It is also possible to configure the intervall of days between the sending of horoscopes and the time of sending. The default is to send one email every seven days at 8 am. This will start the deployment of the app in the pod, the service and an ingress for the HTTP frontend server and an ingress for the backend server. When a pod with the app is initally started, one email will be sent to the configured receiver. @@ -64,5 +63,3 @@ The app can be deployed by running: $ kubectl apply -f deployment.yaml ``` Der HTTP-Server can be access in a browser with the address https://192-168-197-2.c-one-infra.de/iching/ - - \ No newline at end of file diff --git a/dist/backend/broker.js b/dist/backend/broker.js deleted file mode 100644 index 3977cc9..0000000 --- a/dist/backend/broker.js +++ /dev/null @@ -1,137 +0,0 @@ -import { exec } from 'child_process'; -import * as fs from 'fs'; -import * as nodemailer from 'nodemailer'; -import { fileURLToPath } from 'url'; -import * as path from 'path'; -var config; -export function executeCommand() { - exec('iching divine', (error, stdout, stderr) => { - console.log(`I-Ching-Broker: \'iching divine\' called`); - if (error) { - console.error(`Error: ${error.message}`); - return; - } - if (stderr) { - console.error(`Stderr: ${stderr}`); - return; - } - //Load config once - if (config == undefined) { - config = loadConfig(); - } - console.log(`Horoscope received; sending E-Mail next`); - sendEmail(stdout); - }); -} -// Run function once initially, called from Dockerfile -executeCommand(); -// Load the Configuration -function loadConfig() { - console.log(`Load Config`); - //const data = fs.readFileSync('config.json', 'utf-8'); - //const configPath = path.join(__dirname, 'config.json'); - const __filename = fileURLToPath(import.meta.url); - const __dirname = path.dirname(__filename); - const configPath = path.join(__dirname, 'config.json'); - const data = fs.readFileSync(configPath, 'utf-8'); - return JSON.parse(data); -} -// Send E-Mail -async function sendEmail(content) { - // Create Transporter - const transporter = nodemailer.createTransport({ - host: config.mailHost, //"mailhog.mailhog.svc.cluster.local", //config.mailHost, - port: config.mailPort, //1025, //config.mailPort, - secure: false - }); - try { - const info = await transporter.sendMail({ - from: '"The Oracle" ', - to: config.emailReceiver, //"test@mailhog.local", //config.emailReceiver, - subject: "Your Horoscope Is Ready", - text: content, - html: html(content) - }); - console.log("E-Mail sent: ", info.messageId + "\n\n"); - } - catch (error) { - console.error("Error Sending E-Mail:", error + "\n\n"); - console.log("Failed to send this horoscope: \n", content + "\n"); - } -} -// Generate 1) Parse Tree and 2) HTML -export function html(inputText) { - const parseTree = parse(inputText); - const htmlOutput = render(parseTree); - return htmlOutput; -} -// Generate the Parse Tree -function parse(input) { - console.log("Parse input text"); - const root = { type: "Root" }; - var currentNode = root; - const lines = input.split("\n"); - for (const line of lines) { - if (line.startsWith("Hexagram")) { - const hexagram = { type: "Hexagram" }; - currentNode.child = hexagram; - currentNode = hexagram; - currentNode.value = "

" + line + "

"; - } - else if (line.startsWith("Judgement")) { - const judgement = { type: "Judgement" }; - currentNode.child = judgement; - currentNode = judgement; - currentNode.value = "

" + line + "

"; - } - else if (line.startsWith("Images")) { - const images = { type: "Images" }; - currentNode.child = images; - currentNode = images; - currentNode.value = "

" + line + "

"; - } - else if (line.startsWith("~") && currentNode.type != "ChangingLines") { - const changingLines = { type: "ChangingLines" }; - currentNode.child = changingLines; - currentNode = changingLines; - currentNode.value = line; - } - else { - currentNode.value = currentNode.value + line + "
"; - } - } - return root; -} -// Generate HTML from Parse Tree -function render(node) { - if (node == undefined) { - console.log("I-Ching-Broker: Rendering of nodes finished!"); - return ""; - } - var outputHTML = ""; - switch (node.type) { - case "Root": - return render(node.child); - case "Hexagram": - node.value = node.value?.replace("

", "

"); - node.value = node.value?.replace("

", "

"); - node.value = node.value?.replace("
", " - "); - outputHTML = "

" + node.value + "

"; - outputHTML = outputHTML + render(node.child); - return outputHTML; - case "Images": - outputHTML = "

" + node.value + "

"; //EXTRA closing div (was opened at beginning of hexagram) - outputHTML = outputHTML + render(node.child); - return outputHTML; - case "ChangingLines": - const regex = new RegExp("~", "g"); - node.value = node.value?.replace(regex, ""); - outputHTML = "

" + node.value + "


"; - outputHTML = outputHTML + render(node.child); - return outputHTML; - default: - outputHTML = "

" + node.value + "

"; - outputHTML = outputHTML + render(node.child); - return outputHTML; - } -} diff --git a/dist/backend/config.json b/dist/backend/config.json deleted file mode 100644 index 121311d..0000000 --- a/dist/backend/config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "emailReceiver": "test@mailhog.local", - "mailHost": "mailhog.mailhog.svc.cluster.local", - "mailPort": 1025 -} \ No newline at end of file diff --git a/dist/backend/server.js b/dist/backend/server.js deleted file mode 100644 index b0f87f6..0000000 --- a/dist/backend/server.js +++ /dev/null @@ -1,15 +0,0 @@ -import express from 'express'; -import cors from 'cors'; -import { executeCommand } from './broker.js'; -const app = express(); -const port = 8090; -app.use(cors()); -app.post('/iching/api/command', (req, res) => { - //TODO no logging from inside this method??? - console.log(`Backend-Server: receiving POST to /iching/api/command`); - executeCommand(); - res.status(200).send('Backend-Server: Broker was called\n'); -}); -app.listen(port, '0.0.0.0', () => { - console.log(`Backend-Server running on http://0.0.0.0:${port}`); -}); diff --git a/dist/frontend/deploy.js b/dist/frontend/deploy.js deleted file mode 100644 index 402c906..0000000 --- a/dist/frontend/deploy.js +++ /dev/null @@ -1 +0,0 @@ -window.DEPLOY_MODE = 'local'; diff --git a/dist/frontend/event.mjs b/dist/frontend/event.mjs deleted file mode 100644 index c0fa2db..0000000 --- a/dist/frontend/event.mjs +++ /dev/null @@ -1,18 +0,0 @@ -"use strict"; -function handleClick() { - console.log("Der Button wurde geklickt!"); - //const deployMode = (window as { DEPLOY_MODE?: 'docker' | 'k8s' }).DEPLOY_MODE ?? 'k8s'; - const deployMode = window.DEPLOY_MODE ?? 'k8s'; - const endpoint = deployMode === 'docker' || deployMode === 'local' - ? 'http://localhost:8090/iching/api/command' - : '/iching/api/command'; - console.log(`DEPLOY_MODE=${deployMode}, sende POST an: ${endpoint}`); - fetch(endpoint, { method: 'POST' }) - .then(res => res.text()) - .then(text => console.log("HTTP-Server says:", text)) - .catch(error => console.error("HTTP-Server - Error:", error)); -} -document.addEventListener("DOMContentLoaded", () => { - const button = document.getElementById("myButton"); - button?.addEventListener("click", handleClick); -}); diff --git a/dist/frontend/index.html b/dist/frontend/index.html deleted file mode 100644 index 9c6984a..0000000 --- a/dist/frontend/index.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - Your I-Ging Horoscope - - - -
-

Do you want to know the future?

-

โ˜๏ธ Look into the future with your personal I-Ging Horoscope! โ˜๏ธ

-

Click on the Button to receive your personal Horoscope. 100% accuracy guaranteed!

- - -
- - - - - - \ No newline at end of file