diff --git a/source/conf.ts b/source/conf.ts
index cd440d7..f492559 100644
--- a/source/conf.ts
+++ b/source/conf.ts
@@ -24,6 +24,24 @@ along with »munin«. If not, see .
namespace _munin.conf
{
+ /**
+ */
+ type type_reminder_raw = {
+ frequency : (
+ "hourly"
+ |
+ "daily"
+ |
+ "weekly"
+ |
+ "monthly"
+ );
+ offset : int;
+ from : int;
+ to : int;
+ };
+
+
/**
*/
type type_conf_v1 = {
@@ -236,7 +254,71 @@ namespace _munin.conf
/**
*/
- export type type_conf = type_conf_v4;
+ type type_conf_v5 = {
+ sources : Array<
+ (
+ {
+ kind : "ical_feed";
+ data : {
+ url : string;
+ filtration : {
+ category_whitelist : (null | Array);
+ category_blacklist : (null | Array);
+ title_whitelist : (null | Array);
+ title_blacklist : (null | Array);
+ }
+ }
+ }
+ )
+ >;
+ targets : Array<
+ (
+ {
+ kind : "email";
+ data : {
+ smtp_host : string;
+ smtp_port : int;
+ smtp_username : string;
+ smtp_password : string;
+ sender : string;
+ receivers : Array;
+ hide_tags : boolean;
+ /**
+ * in hours
+ */
+ reminders : Array;
+ }
+ }
+ |
+ {
+ kind : "telegram_bot";
+ data : {
+ bot_token : string;
+ chat_id : int;
+ hide_tags : boolean;
+ /**
+ * in hours
+ */
+ reminders : Array;
+ }
+ }
+ )
+ >;
+ settings : {
+ interval : float;
+ };
+ labels : {
+ head : string;
+ title : string;
+ time : string;
+ location : string;
+ };
+ };
+
+
+ /**
+ */
+ export type type_conf = type_conf_v5;
/**
@@ -396,6 +478,65 @@ namespace _munin.conf
}
+ /**
+ */
+ function convert_from_v4(
+ conf_v4 : type_conf_v4
+ ) : type_conf_v5
+ {
+ const map_reminder = hours => ({
+ "frequency": "hourly",
+ "offset": 0,
+ "from": hours,
+ "to": (hours + 1),
+ } as type_reminder_raw);
+ return {
+ "sources": conf_v4.sources,
+ "targets": conf_v4.targets.map(
+ target => {
+ switch (target.kind) {
+ case "email": {
+ return {
+ "kind": "email",
+ "data": {
+ "smtp_host": target.data.smtp_host,
+ "smtp_port": target.data.smtp_port,
+ "smtp_username": target.data.smtp_username,
+ "smtp_password": target.data.smtp_password,
+ "sender": target.data.sender,
+ "receivers": target.data.receivers,
+ "hide_tags": target.data.hide_tags,
+ "reminders": target.data.reminders.map(map_reminder),
+ },
+ };
+ break;
+ }
+ case "telegram_bot": {
+ return {
+ "kind": "telegram_bot",
+ "data": {
+ "bot_token": target.data.bot_token,
+ "chat_id": target.data.chat_id,
+ "hide_tags": target.data.hide_tags,
+ "reminders": target.data.reminders.map(map_reminder),
+ },
+ };
+ break;
+ }
+ default: {
+ // return target;
+ throw (new Error("unhandled target kind: " + String(target)));
+ break;
+ }
+ }
+ }
+ ),
+ "settings": conf_v4.settings,
+ "labels": conf_v4.labels,
+ };
+ }
+
+
/**
*/
function schema_source_kalender_digital(
@@ -546,6 +687,136 @@ namespace _munin.conf
}
+ /**
+ */
+ function schema_sources(
+ version : string
+ ) : lib_plankton.conf.type_schema
+ {
+ switch (version) {
+ case "1": {
+ return {
+ "nullable": false,
+ "type": "array",
+ "items": {
+ "nullable": false,
+ "anyOf": [
+ schema_source_kalender_digital(version),
+ ],
+ }
+ };
+ break;
+ }
+ default:
+ case "2": {
+ return {
+ "nullable": false,
+ "type": "array",
+ "items": {
+ "nullable": false,
+ "anyOf": [
+ schema_source_ical_feed(version),
+ ],
+ }
+ };
+ break;
+ }
+ }
+ }
+
+
+ /**
+ */
+ function schema_reminder(
+ version : string
+ ) : lib_plankton.conf.type_schema
+ {
+ switch (version)
+ {
+ case "1":
+ case "2":
+ case "3":
+ case "4":
+ {
+ return {
+ "type": "integer",
+ };
+ }
+ case "5":
+ default:
+ {
+ return {
+ "nullable": false,
+ "type": "object",
+ "properties": {
+ "frequency": {
+ "nullable": false,
+ "type": "string",
+ "enum": [
+ "hourly",
+ "daily",
+ "weekly",
+ "monthly",
+ ]
+ },
+ "offset": {
+ "nullable": false,
+ "type": "integer",
+ "default": 0
+ },
+ "from": {
+ "nullable": false,
+ "type": "integer"
+ },
+ "to": {
+ "nullable": false,
+ "type": "integer"
+ },
+ },
+ "additionalProperties": false,
+ "required": [
+ "frequency",
+ "from",
+ "to",
+ ]
+ };
+ break;
+ }
+ }
+ }
+
+
+ /**
+ */
+ function default_reminder(
+ version : string
+ ) : any
+ {
+ switch (version)
+ {
+ case "1":
+ case "2":
+ case "3":
+ case "4":
+ {
+ return [24];
+ }
+ case "5":
+ default:
+ {
+ return [
+ {
+ "frequency": "hourly",
+ "from": 24,
+ "to": 25
+ }
+ ];
+ break;
+ }
+ }
+ }
+
+
/**
*/
function schema_target_email(
@@ -602,11 +873,8 @@ namespace _munin.conf
"reminders": {
"nullable": false,
"type": "array",
- "items": {
- "nullable": false,
- "type": "integer"
- },
- "default": [24.0],
+ "items": schema_reminder(version),
+ "default": default_reminder(version),
},
},
"additionalProperties": false,
@@ -628,44 +896,6 @@ namespace _munin.conf
}
- /**
- */
- function schema_sources(
- version : string
- ) : lib_plankton.conf.type_schema
- {
- switch (version) {
- case "1": {
- return {
- "nullable": false,
- "type": "array",
- "items": {
- "nullable": false,
- "anyOf": [
- schema_source_kalender_digital(version),
- ],
- }
- };
- break;
- }
- default:
- case "2": {
- return {
- "nullable": false,
- "type": "array",
- "items": {
- "nullable": false,
- "anyOf": [
- schema_source_ical_feed(version),
- ],
- }
- };
- break;
- }
- }
- }
-
-
/**
*/
function schema_target_telegram_bot(
@@ -701,11 +931,8 @@ namespace _munin.conf
"reminders": {
"nullable": false,
"type": "array",
- "items": {
- "nullable": false,
- "type": "integer"
- },
- "default": [24.0],
+ "items": schema_reminder(version),
+ "default": default_reminder(version),
},
},
"additionalProperties": false,
@@ -737,13 +964,18 @@ namespace _munin.conf
"nullable": false,
"anyOf": (() => {
switch (version) {
- default: {
+ case "1":
+ case "2":
+ {
return [
schema_target_telegram_bot(version),
];
break;
}
- case "3": {
+ case "4":
+ case "5":
+ default:
+ {
return [
schema_target_email(version),
schema_target_telegram_bot(version),
@@ -824,7 +1056,7 @@ namespace _munin.conf
/**
*/
export function schema(
- version : string = "4"
+ version : string = "5"
) : lib_plankton.conf.type_schema
{
switch (version) {
@@ -852,7 +1084,9 @@ namespace _munin.conf
}
case "2":
case "3":
- case "4": {
+ case "4":
+ case "5":
+ {
return {
"nullable": false,
"type": "object",
@@ -887,7 +1121,8 @@ namespace _munin.conf
"1": {"target": "2", "function": convert_from_v1},
"2": {"target": "3", "function": convert_from_v2},
"3": {"target": "4", "function": convert_from_v3},
- "4": null,
+ "4": {"target": "5", "function": convert_from_v4},
+ "5": null,
}
);
@@ -925,7 +1160,7 @@ namespace _munin.conf
}
}
*/
- return (conf_raw.content as type_conf_v4);
+ return (conf_raw.content as type_conf_v5);
}
}
diff --git a/source/logic.ts b/source/logic.ts
index 693811f..a9efba2 100644
--- a/source/logic.ts
+++ b/source/logic.ts
@@ -21,45 +21,6 @@ along with »munin«. If not, see .
namespace _munin.logic
{
- /**
- * @todo Tests schreiben
- */
- function shall_remind(
- event : _munin.type_event,
- reminder : type_reminder,
- {
- "pit": pit = lib_plankton.pit.now(),
- "interval": interval = 1,
- } : {
- pit ?: lib_plankton.pit.type_pit;
- interval ?: int;
- } = {
- }
- ) : boolean
- {
- const window_from : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
- pit,
- 0
- );
- const window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
- pit,
- interval
- );
- const event_begin : lib_plankton.pit.type_pit = lib_plankton.pit.from_datetime(
- event.begin
- );
- const reminder_time : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
- event_begin,
- (-reminder)
- );
- return lib_plankton.pit.is_between(
- reminder_time,
- window_from,
- window_to
- );
- }
-
-
/**
*/
function frequency_anchor(
@@ -90,7 +51,7 @@ namespace _munin.logic
/**
*/
export function reminder_due(
- reminder : type_reminder_new,
+ reminder : type_reminder,
{
"pit": pit = lib_plankton.pit.now(),
"interval": interval = 1,
@@ -105,35 +66,46 @@ namespace _munin.logic
reminder.frequency,
{"pit": pit}
);
- // 0 ≤ ((p - a(p)) - o) < i
- const x : float = (
- (
- (
- lib_plankton.pit.to_unix_timestamp(pit)
- -
- lib_plankton.pit.to_unix_timestamp(anchor)
- )
- /
- (60 * 60)
- )
- -
- reminder.offset
+ const window_from : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
+ anchor,
+ (reminder.offset + 0)
);
- return ((0 <= x) && (x < interval));
+ const window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
+ anchor,
+ (reminder.offset + interval)
+ );
+ const result : boolean = lib_plankton.pit.is_between(
+ pit,
+ window_from,
+ window_to
+ );
+ lib_plankton.log._info(
+ "munin.logic.reminder_due",
+ {
+ "details": {
+ "reminder": reminder,
+ "datetime": lib_plankton.pit.to_datetime(pit),
+ "interval": interval,
+ "anchor": lib_plankton.pit.to_datetime(anchor),
+ "window_from": lib_plankton.pit.to_datetime(window_from),
+ "window_to": lib_plankton.pit.to_datetime(window_to),
+ "result": result,
+ }
+ }
+ );
+ return result;
}
/**
*/
export function reminder_event_in_window(
- reminder : type_reminder_new,
+ reminder : type_reminder,
event : _munin.type_event,
{
"pit": pit = lib_plankton.pit.now(),
- "interval": interval = 1,
} : {
pit ?: lib_plankton.pit.type_pit;
- interval ?: int;
} = {
}
) : boolean
@@ -153,41 +125,26 @@ namespace _munin.logic
const event_begin : lib_plankton.pit.type_pit = lib_plankton.pit.from_datetime(
event.begin
);
- return lib_plankton.pit.is_between(
+ const result : boolean = lib_plankton.pit.is_between(
event_begin,
window_from,
window_to
);
- }
-
-
- /**
- */
- function shall_remind_new(
- reminder : type_reminder_new,
- event : _munin.type_event,
- {
- "pit": pit = lib_plankton.pit.now(),
- "interval": interval = 1,
- } : {
- pit ?: lib_plankton.pit.type_pit;
- interval ?: int;
- } = {
- }
- ) : boolean
- {
- return (
- reminder_due(
- reminder,
- {"pit": pit, "interval": interval}
- )
- &&
- reminder_event_in_window(
- reminder,
- event,
- {"pit": pit, "interval": interval}
- )
+ lib_plankton.log._info(
+ "munin.logic.reminder_event_in_window",
+ {
+ "details": {
+ "reminder": reminder,
+ "event": event,
+ "datetime": lib_plankton.pit.to_datetime(pit),
+ "anchor": lib_plankton.pit.to_datetime(anchor),
+ "window_from": lib_plankton.pit.to_datetime(window_from),
+ "window_to": lib_plankton.pit.to_datetime(window_to),
+ "result": result,
+ }
+ }
);
+ return result;
}
@@ -211,17 +168,30 @@ namespace _munin.logic
.reduce((x, y) => x.concat(y), [])
);
for (const target of targets) {
- for (const reminder_hours of target.reminders) {
- for (const event of events) {
- const remind : boolean = shall_remind(
- event,
- reminder_hours,
- {
- "pit": now,
- "interval": conf.settings.interval,
- }
+ for (const reminder of target.reminders) {
+ const due : boolean = reminder_due(
+ reminder,
+ {
+ "pit": now,
+ "interval": conf.settings.interval,
+ }
+ );
+ if (! due)
+ {
+ // do nothing
+ }
+ else
+ {
+ const events_matching : Array<_munin.type_event> = events.filter(
+ event => reminder_event_in_window(
+ reminder,
+ event,
+ {
+ "pit": now,
+ }
+ )
);
- if (! remind) {
+ if (events_matching.length <= 0) {
// do nothing
}
else {
@@ -229,7 +199,7 @@ namespace _munin.logic
"munin.remind.do",
{
"details": {
- "event": event,
+ "events": events,
"target": target.show(),
}
}
@@ -238,18 +208,24 @@ namespace _munin.logic
// do nothing
}
else {
- try {
- await target.send(conf.labels, event);
- }
- catch (error) {
- lib_plankton.log.error(
- "munin.remind.error",
- {
- "details": {
- "message": String(error),
+ /**
+ * @todo bundle?
+ */
+ for (const event of events_matching)
+ {
+ try {
+ await target.send(conf.labels, event);
+ }
+ catch (error) {
+ lib_plankton.log.error(
+ "munin.remind.error",
+ {
+ "details": {
+ "message": String(error),
+ }
}
- }
- );
+ );
+ }
}
}
}
diff --git a/source/main.ts b/source/main.ts
index 9fb52fa..af737a4 100644
--- a/source/main.ts
+++ b/source/main.ts
@@ -158,8 +158,9 @@ namespace _munin
"data": {
"target": "stdout",
"format": {
- "kind": "human_readable",
+ "kind": "jsonl",
"data": {
+ "structured": true
}
}
}
diff --git a/source/targets/email.ts b/source/targets/email.ts
index b9d33fa..358ebd6 100644
--- a/source/targets/email.ts
+++ b/source/targets/email.ts
@@ -31,10 +31,7 @@ namespace _munin.targets.email
sender : string;
receivers : Array;
hide_tags : boolean;
- /**
- * in hours
- */
- reminders : Array;
+ reminders : Array<_munin.type_reminder>;
};
diff --git a/source/targets/telegram_bot.ts b/source/targets/telegram_bot.ts
index df24da4..44f0dd7 100644
--- a/source/targets/telegram_bot.ts
+++ b/source/targets/telegram_bot.ts
@@ -27,7 +27,7 @@ namespace _munin.targets.telegram_bot
bot_token : string;
chat_id : int;
hide_tags : boolean;
- reminders : Array;
+ reminders : Array<_munin.type_reminder>;
};
diff --git a/source/test.ts b/source/test.ts
index 91b0842..91bed40 100644
--- a/source/test.ts
+++ b/source/test.ts
@@ -359,7 +359,6 @@ namespace _munin.test
},
{
"pit": datetime_to_pit(testcase.input.datetime),
- "interval": testcase.input.interval,
}
);
diff --git a/source/types.ts b/source/types.ts
index e29db21..9c56ef0 100644
--- a/source/types.ts
+++ b/source/types.ts
@@ -67,15 +67,8 @@ namespace _munin
/**
* @todo rename
- * @todo extend
*/
- export type type_reminder = int;
-
-
- /**
- * @todo rename
- */
- export type type_reminder_new = {
+ export type type_reminder = {
frequency : enum_frequency;
offset : int;
from : int;