munin/source/main.ts

318 lines
7.8 KiB
TypeScript
Raw Normal View History

2025-04-25 12:50:13 +02:00
/*
This file is part of »munin«.
Copyright 2025 'Fenris Wolf' <fenris@folksprak.org>
»munin« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
»munin« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with »munin«. If not, see <http://www.gnu.org/licenses/>.
*/
namespace _munin
2025-04-25 00:48:05 +02:00
{
2025-04-25 12:50:13 +02:00
/**
*/
async function run_iteration(
conf : _munin.conf.type_conf,
sources : Array<_munin.type_source>,
targets : Array<_munin.type_target>,
{
"dry_run": dry_run = false,
} : {
dry_run ?: boolean;
} = {
}
) : Promise<void>
{
const now : lib_plankton.pit.type_pit = lib_plankton.pit.now();
const events : Array<_munin.type_event> = (
(await Promise.all(sources.map(source => source.fetch())))
.reduce((x, y) => x.concat(y), [])
);
for (const target of targets) {
2025-04-30 07:23:23 +02:00
const window_from : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
now,
0
);
const window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour(
now,
conf.settings.interval
);
2025-04-25 12:50:13 +02:00
lib_plankton.log._info(
"munin.run.iteration",
{
"details": {
2025-04-30 07:23:23 +02:00
"target": target.show(),
"window_from": lib_plankton.pit.to_date_object(window_from).toISOString(),
"window_to": lib_plankton.pit.to_date_object(window_to).toISOString(),
2025-04-25 12:50:13 +02:00
}
}
);
2025-04-30 07:23:23 +02:00
for (const reminder_hours of target.reminders) {
2025-04-25 12:50:13 +02:00
for (const event of events) {
2025-04-30 07:23:23 +02:00
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_hours)
);
lib_plankton.log._info(
2025-04-25 12:50:13 +02:00
"munin.run.check_dueness",
{
"details": {
"event_begin": lib_plankton.pit.to_date_object(event_begin).toISOString(),
2025-04-30 07:23:23 +02:00
"reminder_hours": reminder_hours,
"reminder_time": lib_plankton.pit.to_date_object(reminder_time).toISOString(),
2025-04-25 12:50:13 +02:00
}
}
);
const remind : boolean = lib_plankton.pit.is_between(
2025-04-30 07:23:23 +02:00
reminder_time,
2025-04-25 12:50:13 +02:00
window_from,
window_to
);
if (! remind) {
// do nothing
}
else {
lib_plankton.log._info(
"munin.remind",
{
"details": {
"event": event,
"target": target.show(),
2025-04-25 12:50:13 +02:00
}
}
);
if (dry_run) {
// do nothing
}
else {
await target.send(conf.labels, event);
}
}
}
}
}
}
/**
*/
async function run(
2025-04-25 12:50:13 +02:00
conf : _munin.conf.type_conf,
{
2025-04-29 22:19:45 +02:00
"single_run": single_run = false,
2025-04-25 12:50:13 +02:00
"dry_run": dry_run = false,
} : {
2025-04-29 22:19:45 +02:00
single_run ?: boolean;
2025-04-25 12:50:13 +02:00
dry_run ?: boolean;
} = {
}
) : Promise<void>
2025-04-25 12:50:13 +02:00
{
const sources : Array<_munin.type_source> = conf.sources.map(
source_raw => _munin.sources.factory(source_raw)
);
const targets : Array<_munin.type_target> = conf.targets.map(
target_raw => _munin.targets.factory(target_raw)
);
lib_plankton.log._info(
"munin.run.start",
{
"details": {
}
}
);
2025-04-29 22:19:45 +02:00
if (single_run) {
await run_iteration(conf, sources, targets, {"dry_run": dry_run});
2025-04-29 22:19:45 +02:00
}
else {
while (true) {
await run_iteration(conf, sources, targets, {"dry_run": dry_run});
await lib_plankton.call.sleep(conf.settings.interval * 60 * 60);
}
}
2025-04-25 12:50:13 +02:00
}
2025-04-25 00:48:05 +02:00
/**
*/
export async function main(
args_raw : Array<string>
): Promise<void>
{
// args
const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler(
{
/*
2025-04-25 00:48:05 +02:00
"action": lib_plankton.args.class_argument.positional({
"index": 0,
"type": lib_plankton.args.enum_type.string,
"mode": lib_plankton.args.enum_mode.replace,
"default": "run",
"info": "what to do : help | run",
2025-04-25 00:48:05 +02:00
"name": "action",
}),
*/
2025-04-25 00:48:05 +02:00
"conf_path": lib_plankton.args.class_argument.volatile({
"indicators_long": ["conf-path"],
"indicators_short": ["c"],
"type": lib_plankton.args.enum_type.string,
"mode": lib_plankton.args.enum_mode.replace,
"default": "munin.json",
2025-04-25 00:48:05 +02:00
"info": "path to configuration file",
"name": "conf-path",
}),
2025-04-25 12:50:13 +02:00
"conf_expose": lib_plankton.args.class_argument.volatile({
"indicators_long": ["conf-expose"],
"indicators_short": ["e"],
"type": lib_plankton.args.enum_type.boolean,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"info": "whether to expose the full configuration",
"name": "conf-expose",
}),
2025-04-29 22:19:45 +02:00
"single_run": lib_plankton.args.class_argument.volatile({
"indicators_long": ["single-run"],
"indicators_short": ["s"],
"type": lib_plankton.args.enum_type.boolean,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"info": "whether to only execute on iteration at run",
"name": "single-run",
}),
2025-04-25 12:50:13 +02:00
"verbosity": lib_plankton.args.class_argument.volatile({
"indicators_long": ["verbosity"],
"indicators_short": ["v"],
2025-04-25 00:48:05 +02:00
"type": lib_plankton.args.enum_type.string,
"mode": lib_plankton.args.enum_mode.replace,
2025-04-25 12:50:13 +02:00
"default": "notice",
"info": "error | warning | notice | info | debug",
"name": "verbosity",
}),
"dry_run": lib_plankton.args.class_argument.volatile({
"indicators_long": ["dry-run"],
"indicators_short": ["q"],
"type": lib_plankton.args.enum_type.boolean,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"info": "whether to not skip the sending of reminders (logs will be written)",
"name": "dry-run",
2025-04-25 00:48:05 +02:00
}),
"help": lib_plankton.args.class_argument.volatile({
"indicators_long": ["help"],
"indicators_short": ["h"],
"type": lib_plankton.args.enum_type.boolean,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"info": "alias for action 'help'",
"name": "help",
}),
}
);
const args : Record<string, any> = arg_handler.read(
lib_plankton.args.enum_environment.cli,
args_raw.join(" ")
);
if (args.help) {
2025-04-25 00:48:05 +02:00
process.stdout.write(
arg_handler.generate_help(
{
2025-04-25 10:54:41 +02:00
"programname": "munin",
"description": "sends reminders about upcoming events",
"executable": "node build/munin",
2025-04-25 00:48:05 +02:00
}
)
);
}
else {
2025-04-25 12:50:13 +02:00
// init
const conf : _munin.conf.type_conf = await _munin.conf.load(args.conf_path);
2025-04-25 12:50:13 +02:00
lib_plankton.log.set_main_logger(
[
{
"kind": "filtered",
"data": {
"core": {
"kind": "std",
"data": {
"target": "stdout",
"format": {
"kind": "human_readable",
"data": {
}
}
}
},
"predicate": [
[
{
"item": {
"kind": "level",
"data": {
"threshold": args.verbosity,
}
},
},
2025-04-25 12:50:13 +02:00
]
],
}
},
]
);
// exec
if (args.conf_expose) {
process.stdout.write(
lib_plankton.json.encode(
conf,
{
"formatted": true,
}
)
+
"\n"
);
}
switch (/*args.action*/"run") {
2025-04-25 00:48:05 +02:00
default: {
throw (new Error("unhandled action: " + args.action));
break;
}
case "run": {
2025-04-25 12:50:13 +02:00
run(
conf,
{
2025-04-29 22:19:45 +02:00
"single_run": args.single_run,
2025-04-25 12:50:13 +02:00
"dry_run": args.dry_run,
2025-04-25 00:48:05 +02:00
}
2025-04-25 12:50:13 +02:00
);
2025-04-25 00:48:05 +02:00
break;
}
}
}
return Promise.resolve<void>(undefined);
}
}
2025-04-25 12:50:13 +02:00
_munin.main(process.argv.slice(2))
2025-04-25 00:48:05 +02:00
.then(() => {})
.catch((reason) => {process.stderr.write(String(reason) + "\n");})
;