/* This file is part of »munin«. Copyright 2025 'Fenris Wolf' »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 . */ namespace _munin { /** */ 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 { 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) { lib_plankton.log._info( "munin.run.iteration", { "details": { "target": target, } } ); for (const hours of target.reminders) { const window_from : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour( now, hours + 0 ); const window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour( now, hours + conf.settings.interval ); for (const event of events) { const event_begin : lib_plankton.pit.type_pit = lib_plankton.pit.from_datetime(event.begin); lib_plankton.log._debug( "munin.run.check_dueness", { "details": { // "now": lib_plankton.pit.to_date_object(now).toISOString(), "event_begin": lib_plankton.pit.to_date_object(event_begin).toISOString(), "window_from": lib_plankton.pit.to_date_object(window_from).toISOString(), "window_to": lib_plankton.pit.to_date_object(window_to).toISOString(), } } ); const remind : boolean = lib_plankton.pit.is_between( event_begin, window_from, window_to ); if (! remind) { // do nothing } else { lib_plankton.log._info( "munin.remind", { "details": { "event": event, "target": target.show(), } } ); if (dry_run) { // do nothing } else { await target.send(conf.labels, event); } } } } } } /** */ async function run( conf : _munin.conf.type_conf, { "single_run": single_run = false, "dry_run": dry_run = false, } : { single_run ?: boolean; dry_run ?: boolean; } = { } ) : Promise { 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": { } } ); if (single_run) { await run_iteration(conf, sources, targets, {"dry_run": dry_run}); } else { while (true) { await run_iteration(conf, sources, targets, {"dry_run": dry_run}); await lib_plankton.call.sleep(conf.settings.interval * 60 * 60); } } } /** */ export async function main( args_raw : Array ): Promise { // args const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler( { /* "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", "name": "action", }), */ "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", "info": "path to configuration file", "name": "conf-path", }), "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", }), "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", }), "verbosity": lib_plankton.args.class_argument.volatile({ "indicators_long": ["verbosity"], "indicators_short": ["v"], "type": lib_plankton.args.enum_type.string, "mode": lib_plankton.args.enum_mode.replace, "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", }), "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 = arg_handler.read( lib_plankton.args.enum_environment.cli, args_raw.join(" ") ); if (args.help) { process.stdout.write( arg_handler.generate_help( { "programname": "munin", "description": "sends reminders about upcoming events", "executable": "node build/munin", } ) ); } else { // init const conf : _munin.conf.type_conf = await _munin.conf.load(args.conf_path); 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, } }, }, ] ], } }, ] ); // exec if (args.conf_expose) { process.stdout.write( lib_plankton.json.encode( conf, { "formatted": true, } ) + "\n" ); } switch (/*args.action*/"run") { default: { throw (new Error("unhandled action: " + args.action)); break; } case "run": { run( conf, { "single_run": args.single_run, "dry_run": args.dry_run, } ); break; } } } return Promise.resolve(undefined); } } _munin.main(process.argv.slice(2)) .then(() => {}) .catch((reason) => {process.stderr.write(String(reason) + "\n");}) ;