2025-03-25 08:54:22 +00:00
|
|
|
import { exec } from 'child_process';
|
2025-03-28 12:04:35 +00:00
|
|
|
import * as fs from 'fs';
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
// Config for scheduling the next time the main process (sending of horoscope) is run
|
2025-03-28 12:04:35 +00:00
|
|
|
interface Config {
|
|
|
|
daysInterval: number;
|
|
|
|
timeOfDay: string;
|
2025-03-31 08:14:08 +00:00
|
|
|
emailReceiver: string;
|
2025-03-31 09:06:14 +00:00
|
|
|
mailHost: string;
|
|
|
|
mailPort: number;
|
2025-03-28 12:04:35 +00:00
|
|
|
}
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
// Node structure for the Parse Tree (it's a degenerated tree with one or zero children per node)
|
|
|
|
interface Node {
|
|
|
|
type: "Root" | "Hexagram" | "Judgement" | "Images" | "ChangingLines" ;
|
|
|
|
child?: Node;
|
|
|
|
value?: string;
|
|
|
|
}
|
|
|
|
|
2025-03-28 12:04:35 +00:00
|
|
|
var config : Config;
|
2025-03-25 08:54:22 +00:00
|
|
|
|
2025-03-25 11:39:58 +00:00
|
|
|
const nodemailer = require('nodemailer');
|
|
|
|
|
2025-03-28 12:40:48 +00:00
|
|
|
function executeCommand(): void {
|
2025-03-25 08:54:22 +00:00
|
|
|
|
2025-03-28 12:40:48 +00:00
|
|
|
exec('iching divine', (error, stdout, stderr) => {
|
2025-03-25 08:54:22 +00:00
|
|
|
|
2025-03-28 12:40:48 +00:00
|
|
|
console.log(`Begin`);
|
2025-03-25 08:54:22 +00:00
|
|
|
|
2025-03-28 12:40:48 +00:00
|
|
|
if (error) {
|
|
|
|
console.error(`Error: ${error.message}`);
|
|
|
|
return;
|
|
|
|
}
|
2025-03-25 08:54:22 +00:00
|
|
|
|
2025-03-28 12:40:48 +00:00
|
|
|
if (stderr) {
|
|
|
|
console.error(`Stderr: ${stderr}`);
|
|
|
|
return;
|
|
|
|
}
|
2025-03-25 14:04:48 +00:00
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
//Load config once
|
2025-03-28 12:40:48 +00:00
|
|
|
if (config == undefined) {
|
|
|
|
config = loadConfig();
|
2025-03-28 13:36:48 +00:00
|
|
|
}
|
2025-03-28 12:04:35 +00:00
|
|
|
|
2025-03-31 08:18:06 +00:00
|
|
|
console.log(`Send E-Mail`);
|
|
|
|
sendEmail(stdout);
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
// Calculate next execution time
|
2025-03-28 12:40:48 +00:00
|
|
|
const nextRunDate = calculateNextRunDate(config.daysInterval, config.timeOfDay);
|
2025-03-28 13:36:48 +00:00
|
|
|
console.log(`Next execution: ${nextRunDate}`);
|
2025-03-28 12:40:48 +00:00
|
|
|
|
2025-03-31 08:39:17 +00:00
|
|
|
// Start Scheduling
|
2025-03-28 12:40:48 +00:00
|
|
|
scheduleNextRun(nextRunDate);
|
|
|
|
});
|
|
|
|
}
|
2025-03-28 12:04:35 +00:00
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
// Run function once initially, called from Dockerfile
|
2025-03-28 13:11:57 +00:00
|
|
|
executeCommand();
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
// Load the Configuration
|
2025-03-28 12:04:35 +00:00
|
|
|
function loadConfig(): Config {
|
2025-03-28 12:21:30 +00:00
|
|
|
|
|
|
|
console.log(`Load Config`);
|
|
|
|
|
2025-03-28 12:04:35 +00:00
|
|
|
const data = fs.readFileSync('config.json', 'utf-8');
|
|
|
|
return JSON.parse(data);
|
|
|
|
}
|
|
|
|
|
2025-03-26 11:44:42 +00:00
|
|
|
// Send E-Mail
|
|
|
|
async function sendEmail(content: string) {
|
2025-03-31 09:06:14 +00:00
|
|
|
|
|
|
|
// Create Transporter
|
|
|
|
const transporter = nodemailer.createTransport({
|
|
|
|
//host: "mailhog.mailhog.svc.cluster.local", // MailHog ClusterIP
|
|
|
|
host: config.mailHost,
|
|
|
|
//port: 1025, // Standard-MailHog SMTP-Port
|
|
|
|
port: config.mailPort,
|
|
|
|
secure: false // MailHog needs no encryption
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2025-03-26 11:44:42 +00:00
|
|
|
try {
|
|
|
|
const info = await transporter.sendMail({
|
2025-03-26 14:55:41 +00:00
|
|
|
from: '"The Oracle" <the.oracle@holy.mountain>',
|
2025-03-31 08:14:08 +00:00
|
|
|
to: config.emailReceiver,
|
2025-03-28 08:32:23 +00:00
|
|
|
subject: "Your Horoscope Is Ready",
|
2025-03-26 11:44:42 +00:00
|
|
|
text: content,
|
2025-03-27 08:52:03 +00:00
|
|
|
html: html(content)
|
2025-03-26 11:44:42 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
console.log("E-Mail sent: ", info.messageId);
|
|
|
|
} catch (error) {
|
|
|
|
console.error("Error Sending E-Mail:", error);
|
2025-03-25 11:39:58 +00:00
|
|
|
}
|
2025-03-26 11:44:42 +00:00
|
|
|
}
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
//Calculate the time for the next execution of the main process, depending on configuration.
|
|
|
|
//Returns the time of the next process loop.
|
2025-03-28 12:04:35 +00:00
|
|
|
function calculateNextRunDate(daysInterval: number, timeOfDay: string): Date {
|
|
|
|
const currentDate = new Date();
|
|
|
|
|
2025-03-28 13:54:24 +00:00
|
|
|
// Splitte die Uhrzeit in Stunden und Minuten
|
2025-03-28 12:04:35 +00:00
|
|
|
const [hours, minutes] = timeOfDay.split(':').map(Number);
|
|
|
|
|
|
|
|
// Berechne das Datum für die nächste Ausführung
|
|
|
|
currentDate.setHours(hours, minutes, 0, 0); // Setze die Uhrzeit auf Y (z.B. 14:30)
|
|
|
|
|
|
|
|
// Wenn die Uhrzeit bereits vorbei ist, verschiebe das Datum auf den nächsten Tag
|
|
|
|
if (currentDate < new Date()) {
|
|
|
|
currentDate.setDate(currentDate.getDate() + 1); // Setze auf den nächsten Tag
|
|
|
|
}
|
|
|
|
|
|
|
|
// Berechne das Datum für den nächsten Ausführungszeitpunkt unter Berücksichtigung von X Tagen
|
|
|
|
currentDate.setDate(currentDate.getDate() + daysInterval);
|
|
|
|
|
|
|
|
return currentDate;
|
2025-03-28 13:54:24 +00:00
|
|
|
|
|
|
|
//TODO: JUST FOR DEBUGGING!!!
|
|
|
|
/*currentDate.setMinutes(currentDate.getMinutes() + 2);
|
|
|
|
return currentDate;*/
|
2025-03-28 12:04:35 +00:00
|
|
|
}
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
//Schedule the next process loop.
|
2025-03-28 12:04:35 +00:00
|
|
|
function scheduleNextRun(nextRunDate: Date) {
|
|
|
|
const now = new Date();
|
|
|
|
const timeUntilNextRun = nextRunDate.getTime() - now.getTime();
|
|
|
|
|
|
|
|
if (timeUntilNextRun > 0) {
|
|
|
|
setTimeout(() => {
|
|
|
|
console.log('Prozess wird ausgeführt!');
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
//run the main process
|
2025-03-28 12:40:48 +00:00
|
|
|
executeCommand();
|
2025-03-28 12:04:35 +00:00
|
|
|
|
|
|
|
}, timeUntilNextRun);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
// Generate 1) Parse Tree and 2) HTML
|
2025-03-31 11:59:41 +00:00
|
|
|
export function html(inputText: string): string {
|
2025-03-27 12:27:14 +00:00
|
|
|
const parseTree = parse(inputText);
|
|
|
|
const htmlOutput = render(parseTree);
|
|
|
|
|
|
|
|
return htmlOutput;
|
|
|
|
}
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
// Generate the Parse Tree
|
2025-03-27 12:27:14 +00:00
|
|
|
function parse(input: string): Node {
|
|
|
|
|
|
|
|
console.log("Parse input text");
|
2025-03-26 14:21:12 +00:00
|
|
|
|
2025-03-27 13:59:49 +00:00
|
|
|
const root: Node = { type: "Root"};
|
2025-03-27 12:27:14 +00:00
|
|
|
var currentNode: Node = root;
|
2025-03-26 14:21:12 +00:00
|
|
|
|
2025-03-27 12:27:14 +00:00
|
|
|
const lines = input.split("\n");
|
2025-03-26 14:21:12 +00:00
|
|
|
|
2025-03-27 12:27:14 +00:00
|
|
|
for (const line of lines) {
|
|
|
|
if (line.startsWith("Hexagram")) {
|
|
|
|
const hexagram: Node = { type: "Hexagram"};
|
|
|
|
currentNode.child = hexagram;
|
|
|
|
currentNode = hexagram;
|
2025-03-27 14:29:19 +00:00
|
|
|
currentNode.value = "<h1>" + line + "</h1>";
|
2025-03-27 13:59:49 +00:00
|
|
|
} else if (line.startsWith("Judgement")) {
|
2025-03-27 12:27:14 +00:00
|
|
|
const judgement: Node = { type: "Judgement"};
|
|
|
|
currentNode.child = judgement;
|
|
|
|
currentNode = judgement;
|
2025-03-28 09:22:40 +00:00
|
|
|
currentNode.value = "<h3>" + line + "</h3>";
|
2025-03-27 13:59:49 +00:00
|
|
|
} else if (line.startsWith("Images")) {
|
2025-03-27 12:27:14 +00:00
|
|
|
const images: Node = { type: "Images"};
|
|
|
|
currentNode.child = images;
|
|
|
|
currentNode = images;
|
2025-03-28 09:22:40 +00:00
|
|
|
currentNode.value = "<h3>" + line + "</h3>";
|
2025-03-27 13:59:49 +00:00
|
|
|
} else if (line.startsWith("~") && currentNode.type != "ChangingLines") {
|
2025-03-27 12:27:14 +00:00
|
|
|
const changingLines: Node = { type: "ChangingLines"};
|
|
|
|
currentNode.child = changingLines;
|
|
|
|
currentNode = changingLines;
|
2025-03-31 07:45:03 +00:00
|
|
|
currentNode.value = line; // + "<br>"; TODO: try without this <br>
|
2025-03-27 13:59:49 +00:00
|
|
|
} else {
|
2025-03-27 13:42:28 +00:00
|
|
|
currentNode.value = currentNode.value + line + "<br>";
|
2025-03-27 12:27:14 +00:00
|
|
|
}
|
|
|
|
}
|
2025-03-26 14:21:12 +00:00
|
|
|
|
2025-03-27 12:27:14 +00:00
|
|
|
return root;
|
2025-03-26 14:21:12 +00:00
|
|
|
}
|
|
|
|
|
2025-03-28 13:36:48 +00:00
|
|
|
// Generate HTML from Parse Tree
|
2025-03-27 12:27:14 +00:00
|
|
|
function render(node: Node): string {
|
|
|
|
|
2025-03-27 13:01:33 +00:00
|
|
|
if (node == undefined) {
|
2025-03-27 12:36:53 +00:00
|
|
|
console.log("...finished...")
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2025-03-27 13:59:49 +00:00
|
|
|
console.log("Render node" + node.type);
|
2025-03-27 12:27:14 +00:00
|
|
|
|
|
|
|
var outputHTML: string = "";
|
|
|
|
|
|
|
|
switch (node.type) {
|
|
|
|
case "Root":
|
|
|
|
return render(node.child!);
|
2025-03-28 10:23:31 +00:00
|
|
|
case "Hexagram":
|
2025-03-31 07:37:17 +00:00
|
|
|
node.value = node.value?.replace("<h1>", "<div style=\"border: 1px dotted gray; border-radius: 10px; padding-left: 10px; padding-right: 10px; padding-top: 10px; padding-bottom: 10px; width: auto; display: inline-block; box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.2);\"><h1>");
|
2025-03-28 10:23:31 +00:00
|
|
|
node.value = node.value?.replace("</h1>", "</h1><div style=\"border: 1px solid gray; border-radius: 25px; padding-left: 30px; padding-right: 30px; padding-top: 20px; width: auto; display: inline-block; text-align: center; box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.2);\"><h2>");
|
2025-03-28 08:48:54 +00:00
|
|
|
node.value = node.value?.replace("<br>", " - ");
|
2025-03-28 10:43:59 +00:00
|
|
|
outputHTML = "<br><p>" + node.value + "</h2></div></p>";
|
2025-03-27 14:29:19 +00:00
|
|
|
outputHTML = outputHTML + render(node.child!);
|
|
|
|
|
|
|
|
return outputHTML;
|
|
|
|
|
2025-03-31 07:32:41 +00:00
|
|
|
case "Images":
|
|
|
|
outputHTML = "<p>" + node.value + "</p></div>"; //EXTRA closing div
|
|
|
|
outputHTML = outputHTML + render(node.child!);
|
|
|
|
|
|
|
|
return outputHTML;
|
|
|
|
|
2025-03-27 13:59:49 +00:00
|
|
|
case "ChangingLines" :
|
2025-03-28 10:31:01 +00:00
|
|
|
const regex = new RegExp("~", "g");
|
|
|
|
node.value = node.value?.replace(regex, "");
|
2025-03-31 07:57:07 +00:00
|
|
|
//outputHTML = "<br><p><div style=\"border: 1px dashed gray; border-radius: 10px; padding-left: 10px; padding-right: 10px; padding-top: 10px; width: auto; display: inline-block; color: gray; text-align: center; box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.2);\">" + node.value + "</div></p><br>";
|
2025-03-31 08:14:08 +00:00
|
|
|
outputHTML = "<br><br><p><div style=\"padding-left: 20px; padding-right: 20px; padding-top: 20px; display: inline-block; color: gray; text-align: center;\">" + node.value + "</div></p><br>";
|
2025-03-27 13:59:49 +00:00
|
|
|
outputHTML = outputHTML + render(node.child!);
|
|
|
|
|
|
|
|
return outputHTML;
|
|
|
|
|
2025-03-27 12:27:14 +00:00
|
|
|
default:
|
|
|
|
outputHTML = "<p>" + node.value + "</p>";
|
2025-03-27 13:23:36 +00:00
|
|
|
outputHTML = outputHTML + render(node.child!);
|
2025-03-27 12:27:14 +00:00
|
|
|
|
2025-03-27 13:23:36 +00:00
|
|
|
return outputHTML;
|
2025-03-27 12:27:14 +00:00
|
|
|
}
|
2025-03-31 11:59:41 +00:00
|
|
|
|
|
|
|
|
2025-03-26 14:21:12 +00:00
|
|
|
}
|
2025-03-25 11:39:58 +00:00
|
|
|
|