This commit is contained in:
Christian Fraß 2023-08-03 08:34:33 +02:00
parent bcc0283149
commit 27d6b4eb16
35 changed files with 1426 additions and 1096 deletions

View file

@ -1487,6 +1487,9 @@ declare namespace lib_plankton.file {
* @author fenris * @author fenris
*/ */
function write_buffer(path: string, content: Buffer, options?: {}): Promise<void>; function write_buffer(path: string, content: Buffer, options?: {}): Promise<void>;
/**
*/
function delete_(path: string): Promise<void>;
} }
declare namespace lib_plankton.translate { declare namespace lib_plankton.translate {
/** /**
@ -1905,3 +1908,45 @@ declare namespace lib_plankton.http {
decode(x: string): type_response; decode(x: string): type_response;
} }
} }
declare namespace lib_plankton.sqlite {
/**
*/
type type_query_raw = {
template: string;
arguments: Record<string, any>;
};
/**
*/
type type_connection = {
handle: any;
};
/**
*/
function get_connection(database_path: string): Promise<type_connection>;
/**
*/
function drop_connection(connection: type_connection): Promise<void>;
/**
* for CREATE TABLE, DROP TABLE, etc.
*/
function query_set(connection: type_connection, query_raw: type_query_raw): Promise<any>;
/**
* for INSERT, UPDATE, DELETE
*/
function query_put(connection: type_connection, query_raw: type_query_raw): Promise<{
id: (null | number);
affected: (null | number);
}>;
/**
* for SELECT
*
* @todo rather use handle procedure for rows instead of returning an array
*/
function query_get(connection: type_connection, query_raw: type_query_raw): Promise<Array<Record<string, any>>>;
/**
* for SELECT
*
* @todo rather use handle procedure for rows instead of returning an array
*/
function query_probe(connection: type_connection, query_raw: type_query_raw, handler: ((row: Record<string, any>) => void)): void;
}

View file

@ -4274,7 +4274,7 @@ var lib_plankton;
return (new Promise(function (resolve, reject) { return (new Promise(function (resolve, reject) {
nm_fs.readFile(path, { nm_fs.readFile(path, {
"encoding": "utf8", "encoding": "utf8",
"flag": "r", "flag": "r"
}, function (error, content) { }, function (error, content) {
if (error == null) { if (error == null) {
resolve(content); resolve(content);
@ -4293,7 +4293,7 @@ var lib_plankton;
var nm_fs = require("fs"); var nm_fs = require("fs");
return (new Promise(function (resolve, reject) { return (new Promise(function (resolve, reject) {
nm_fs.readFile(path, { nm_fs.readFile(path, {
"flag": "r", "flag": "r"
}, function (error, content) { }, function (error, content) {
if (error == null) { if (error == null) {
resolve(content); resolve(content);
@ -4330,13 +4330,13 @@ var lib_plankton;
function write(path, content, options) { function write(path, content, options) {
if (options === void 0) { options = {}; } if (options === void 0) { options = {}; }
options = Object.assign({ options = Object.assign({
"encoding": "utf-8", "encoding": "utf-8"
}, options); }, options);
var nm_fs = require("fs"); var nm_fs = require("fs");
return (new Promise(function (resolve, reject) { return (new Promise(function (resolve, reject) {
nm_fs.writeFile(path, content, { nm_fs.writeFile(path, content, {
"encoding": options.encoding, "encoding": options.encoding,
"flag": "w", "flag": "w"
}, function (error) { }, function (error) {
if (error == null) { if (error == null) {
resolve(undefined); resolve(undefined);
@ -4357,7 +4357,7 @@ var lib_plankton;
var nm_fs = require("fs"); var nm_fs = require("fs");
return (new Promise(function (resolve, reject) { return (new Promise(function (resolve, reject) {
nm_fs.writeFile(path, content, { nm_fs.writeFile(path, content, {
"flag": "w", "flag": "w"
}, function (error) { }, function (error) {
if (error == null) { if (error == null) {
resolve(undefined); resolve(undefined);
@ -4369,6 +4369,17 @@ var lib_plankton;
})); }));
} }
file.write_buffer = write_buffer; file.write_buffer = write_buffer;
/**
*/
function delete_(path) {
var nm_fs = require("fs");
return (new Promise(function (resolve, reject) {
nm_fs.unlink(path, function () {
resolve(undefined);
});
}));
}
file.delete_ = delete_;
})(file = lib_plankton.file || (lib_plankton.file = {})); })(file = lib_plankton.file || (lib_plankton.file = {}));
})(lib_plankton || (lib_plankton = {})); })(lib_plankton || (lib_plankton = {}));
/* /*
@ -4851,8 +4862,8 @@ var lib_plankton;
"info": info, "info": info,
"hidden": hidden, "hidden": hidden,
"parameters": { "parameters": {
"index": index, "index": index
}, }
})); }));
}; };
/** /**
@ -4870,8 +4881,8 @@ var lib_plankton;
"hidden": hidden, "hidden": hidden,
"parameters": { "parameters": {
"indicators_short": indicators_short, "indicators_short": indicators_short,
"indicators_long": indicators_long, "indicators_long": indicators_long
}, }
})); }));
}; };
/** /**
@ -5117,17 +5128,17 @@ var lib_plankton;
"symbols": { "symbols": {
"delimiter": " ", "delimiter": " ",
"prefix": "--", "prefix": "--",
"assignment": "=", "assignment": "="
}, }
}, },
"url": { "url": {
"symbols": { "symbols": {
"delimiter": "&", "delimiter": "&",
"prefix": "", "prefix": "",
"assignment": "=", "assignment": "="
} }
} }
}, }
}; };
/** /**
* @author fenris * @author fenris
@ -5204,14 +5215,14 @@ var lib_plankton;
"pattern_from": pattern_from, "pattern_from": pattern_from,
"pattern_to": pattern_to, "pattern_to": pattern_to,
"input": input, "input": input,
"result": result, "result": result
}); });
input = result; input = result;
} }
} }
} }
lib_plankton.log.debug("lib_args:read:current_input", { lib_plankton.log.debug("lib_args:read:current_input", {
"input": input, "input": input
}); });
} }
// parsing // parsing
@ -5222,18 +5233,18 @@ var lib_plankton;
var index_expected_1 = 0; var index_expected_1 = 0;
parts.forEach(function (part) { parts.forEach(function (part) {
lib_plankton.log.debug("lib_args:read:analyzing", { lib_plankton.log.debug("lib_args:read:analyzing", {
"part": part, "part": part
}); });
var found = [ var found = [
function () { function () {
lib_plankton.log.debug("lib_args:read:probing_as_volatile", { lib_plankton.log.debug("lib_args:read:probing_as_volatile", {
"part": part, "part": part
}); });
for (var _i = 0, _a = Object.entries(_this.filter(args.enum_kind.volatile)); _i < _a.length; _i++) { for (var _i = 0, _a = Object.entries(_this.filter(args.enum_kind.volatile)); _i < _a.length; _i++) {
var _b = _a[_i], name = _b[0], argument = _b[1]; var _b = _a[_i], name = _b[0], argument = _b[1];
lib_plankton.log.debug("lib_args:read:probing_as_volatile:trying", { lib_plankton.log.debug("lib_args:read:probing_as_volatile:trying", {
"part": part, "part": part,
"argument": argument.toString(), "argument": argument.toString()
}); });
var pattern = ""; var pattern = "";
{ {
@ -5252,12 +5263,12 @@ var lib_plankton;
pattern += pattern_back; pattern += pattern_back;
} }
lib_plankton.log.debug("lib_args:read:probing_as_volatile:pattern", { lib_plankton.log.debug("lib_args:read:probing_as_volatile:pattern", {
"pattern": pattern, "pattern": pattern
}); });
var regexp = new RegExp(pattern); var regexp = new RegExp(pattern);
var matching = regexp.exec(part); var matching = regexp.exec(part);
lib_plankton.log.debug("lib_args:read:probing_as_volatile:matching", { lib_plankton.log.debug("lib_args:read:probing_as_volatile:matching", {
"matching": matching, "matching": matching
}); });
if (matching == null) { if (matching == null) {
// do nothing // do nothing
@ -5271,7 +5282,7 @@ var lib_plankton;
}, },
function () { function () {
lib_plankton.log.debug("lib_args:read:probing_as_positional", { lib_plankton.log.debug("lib_args:read:probing_as_positional", {
"part": part, "part": part
}); });
var positional = _this.filter(args.enum_kind.positional); var positional = _this.filter(args.enum_kind.positional);
for (var _i = 0, _a = Object.entries(positional); _i < _a.length; _i++) { for (var _i = 0, _a = Object.entries(positional); _i < _a.length; _i++) {
@ -5282,7 +5293,7 @@ var lib_plankton;
else { else {
lib_plankton.log.debug("lib_args:read:probing_as_positional:trying", { lib_plankton.log.debug("lib_args:read:probing_as_positional:trying", {
"part": part, "part": part,
"argument": argument.toString(), "argument": argument.toString()
}); });
var pattern = ""; var pattern = "";
{ {
@ -5291,12 +5302,12 @@ var lib_plankton;
pattern += pattern_back; pattern += pattern_back;
} }
lib_plankton.log.debug("lib_args:read:probing_as_positional:pattern", { lib_plankton.log.debug("lib_args:read:probing_as_positional:pattern", {
"pattern": pattern, "pattern": pattern
}); });
var regexp = new RegExp(pattern); var regexp = new RegExp(pattern);
var matching = regexp.exec(part); var matching = regexp.exec(part);
lib_plankton.log.debug("lib_args:read:probing_as_positional:matching", { lib_plankton.log.debug("lib_args:read:probing_as_positional:matching", {
"matching": matching, "matching": matching
}); });
if (matching == null) { if (matching == null) {
return false; return false;
@ -5313,7 +5324,7 @@ var lib_plankton;
].some(function (x) { return x(); }); ].some(function (x) { return x(); });
if (!found) { if (!found) {
lib_plankton.log.warning("lib_args:read:could_not_parse", { lib_plankton.log.warning("lib_args:read:could_not_parse", {
"part": part, "part": part
}); });
} }
}); });
@ -5831,7 +5842,7 @@ var lib_plankton;
((request.query === null) ((request.query === null)
? "" ? ""
: request.query)); : request.query));
// console.info({target,options}); console.info({ target });
switch (options.implementation) { switch (options.implementation) {
default: { default: {
return Promise.reject("invalid implementation: " + options.implementation); return Promise.reject("invalid implementation: " + options.implementation);
@ -6019,3 +6030,145 @@ var lib_plankton;
http.class_http_response = class_http_response; http.class_http_response = class_http_response;
})(http = lib_plankton.http || (lib_plankton.http = {})); })(http = lib_plankton.http || (lib_plankton.http = {}));
})(lib_plankton || (lib_plankton = {})); })(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:sqlite«.
Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>
»bacterio-plankton:sqlite« 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.
»bacterio-plankton:sqlite« 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 »bacterio-plankton:sqlite«. If not, see <http://www.gnu.org/licenses/>.
*/
var lib_plankton;
(function (lib_plankton) {
var sqlite;
(function (sqlite) {
/**
*/
function get_connection(database_path) {
return (new Promise((resolve, reject) => {
const nm_sqlite3 = require("sqlite3");
const handle = new nm_sqlite3.Database(database_path, (nm_sqlite3.OPEN_READWRITE
|
nm_sqlite3.OPEN_CREATE
|
nm_sqlite3.OPEN_FULLMUTEX), (error) => {
if (error) {
reject(error);
}
else {
resolve({
"handle": handle,
});
}
});
}));
}
sqlite.get_connection = get_connection;
/**
*/
function drop_connection(connection) {
return (new Promise((resolve, reject) => {
connection.handle.close(() => {
resolve(undefined);
});
}));
}
sqlite.drop_connection = drop_connection;
/**
*/
function query_transform(query_raw) {
return {
"template": query_raw.template,
"arguments": Object.fromEntries(Object.entries(query_raw.arguments)
.map(([key, value]) => ([(":" + key), value]))),
};
}
/**
* for CREATE TABLE, DROP TABLE, etc.
*/
async function query_set(connection, query_raw) {
const query_transformed = query_transform(query_raw);
return (new Promise((resolve, reject) => {
connection.handle.run(query_transformed.template, query_transformed.arguments, (error) => {
if (error) {
reject(error);
}
else {
resolve(undefined);
}
});
}));
}
sqlite.query_set = query_set;
/**
* for INSERT, UPDATE, DELETE
*/
async function query_put(connection, query_raw) {
const query_transformed = query_transform(query_raw);
return (new Promise((resolve, reject) => {
connection.handle.run(query_transformed.template, query_transformed.arguments,
// must be a classic function due the special use of "this"
function (error) {
if (error) {
reject(error);
}
else {
resolve({
"id": this.lastID,
"affected": this.changes,
});
}
});
}));
}
sqlite.query_put = query_put;
/**
* for SELECT
*
* @todo rather use handle procedure for rows instead of returning an array
*/
async function query_get(connection, query_raw) {
const query_transformed = query_transform(query_raw);
return (new Promise((resolve, reject) => {
connection.handle.all(query_transformed.template, query_transformed.arguments, (error, rows) => {
if (error) {
reject(error);
}
else {
resolve(rows);
}
});
}));
}
sqlite.query_get = query_get;
/**
* for SELECT
*
* @todo rather use handle procedure for rows instead of returning an array
*/
function query_probe(connection, query_raw, handler) {
const query_transformed = query_transform(query_raw);
connection.handle.each(query_transformed.template, query_transformed.arguments, function (error, row) {
if (error) {
// do nothing
// log?
}
else {
handler(row);
}
});
}
sqlite.query_probe = query_probe;
})(sqlite = lib_plankton.sqlite || (lib_plankton.sqlite = {}));
})(lib_plankton || (lib_plankton = {}));

288
source/app/cli.ts Normal file
View file

@ -0,0 +1,288 @@
/**
*/
async function main(
) : Promise<void>
{
await _heimdall.init();
// consts
const version : string = "0.9";
// args
const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler(
{
"order_path": new lib_plankton.args.class_argument(
{
"name": "order_path",
"type": lib_plankton.args.enum_type.string,
"kind": lib_plankton.args.enum_kind.positional,
"mode": lib_plankton.args.enum_mode.replace,
"default": "monitoring.hmdl.json",
"parameters": {
"index": 0,
},
"info": lib_plankton.translate.get("help.args.order_path"),
}
),
"show_help": new lib_plankton.args.class_argument(
{
"name": "help",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["help"],
"indicators_short": ["h"],
},
"info": lib_plankton.translate.get("help.args.show_help"),
}
),
"show_version": new lib_plankton.args.class_argument(
{
"name": "version",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["version"],
"indicators_short": ["r"],
},
"info": lib_plankton.translate.get("help.args.show_version"),
}
),
"show_schema": new lib_plankton.args.class_argument(
{
"name": "schema",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["schema"],
"indicators_short": ["s"],
},
"info": lib_plankton.translate.get("help.args.show_schema"),
}
),
"expose_full_order": new lib_plankton.args.class_argument(
{
"name": "expose_full_order",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["expose-full-order"],
"indicators_short": ["e"],
},
"info": lib_plankton.translate.get("help.args.expose_full_order"),
}
),
"erase_state": new lib_plankton.args.class_argument(
{
"name": "erase_state",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["erase-state"],
"indicators_short": ["x"],
},
"info": lib_plankton.translate.get("help.args.erase_state"),
}
),
"database_path": new lib_plankton.args.class_argument(
{
"name": "database_path",
"type": lib_plankton.args.enum_type.string,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": null,
"parameters": {
"indicators_long": ["database-path"],
"indicators_short": ["d"],
},
"info": lib_plankton.translate.get("help.args.database_path"),
}
),
"mutex_path": new lib_plankton.args.class_argument(
{
"name": "mutex_path",
"type": lib_plankton.args.enum_type.string,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": "/tmp/heimdall.lock",
"parameters": {
"indicators_long": ["mutex-path"],
"indicators_short": ["m"],
},
"info": lib_plankton.translate.get("help.args.mutex_path"),
}
),
"send_ok_notifications": new lib_plankton.args.class_argument(
{
"name": "send_ok_notifications",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["send-ok-notifications"],
"indicators_short": ["y"],
},
"info": lib_plankton.translate.get(
"help.args.send_ok_notifications",
{
"condition_name": lib_plankton.translate.get("conditions.ok"),
}
),
}
),
"language": new lib_plankton.args.class_argument(
{
"name": "language",
"type": lib_plankton.args.enum_type.string,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": null,
"parameters": {
"indicators_long": ["language"],
"indicators_short": ["l"],
},
"info": lib_plankton.translate.get("help.args.language"),
}
),
"time_to_live": new lib_plankton.args.class_argument(
{
"name": "time_to_live",
"type": lib_plankton.args.enum_type.float,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": (60 * 60 * 24 * 7),
"parameters": {
"indicators_long": ["time-to-live"],
"indicators_short": ["t"],
},
"info": lib_plankton.translate.get("help.args.time_to_live"),
}
),
"verbosity": new lib_plankton.args.class_argument(
{
"name": "verbosity",
"type": lib_plankton.args.enum_type.integer,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": 1,
"parameters": {
"indicators_long": ["verbosity"],
"indicators_short": ["v"],
},
"info": lib_plankton.translate.get("help.args.verbosity"),
}
),
}
);
const args : Record<string, any> = arg_handler.read(
lib_plankton.args.enum_environment.cli,
process.argv.slice(2).join(" ")
);
// setup logging
lib_plankton.log.conf_push(
[
new lib_plankton.log.class_channel_minlevel(
new lib_plankton.log.class_channel_stdout(),
[
lib_plankton.log.enum_level.debug,
lib_plankton.log.enum_level.info,
lib_plankton.log.enum_level.notice,
lib_plankton.log.enum_level.warning,
lib_plankton.log.enum_level.error,
][Math.min(4, args["verbosity"])]
),
]
);
// exec
if (args.show_help) {
process.stdout.write(
arg_handler.generate_help(
{
"programname": "heimdall",
"description": lib_plankton.translate.get("help.title"),
"executable": "heimdall",
}
)
);
}
else {
if (args["show_version"]) {
process.stdout.write(version + "\n");
}
else {
if (args["show_schema"]) {
process.stdout.write(
lib_plankton.json.encode(
_heimdall.order.schema_root(
),
true
)
+
"\n"
)
}
else {
const nm_path = require("path");
const nm_fs = require("fs");
if (! nm_fs.existsSync(args["order_path"])) {
lib_plankton.log.error(
lib_plankton.translate.get("misc.order_file_not_found"),
{
"path": args["order_path"],
}
);
}
else {
const order : _heimdall.type_order = await _heimdall.order.load(
nm_path.normalize(args["order_path"])
);
if (args["expose_full_order"]) {
process.stdout.write(lib_plankton.json.encode(order, true) + "\n");
}
else {
await _heimdall.master.wrap_mutex(
args["mutex_path"],
() => _heimdall.master.wrap_database(
args["database_path"],
args["order_path"],
async () => {
await _heimdall.master.clean(
{
"time_to_live": args["time_to_live"],
"erase_state": args["erase_state"],
}
);
await _heimdall.master.run(
order,
{
"send_ok_notifications": args["send_ok_notifications"],
}
);
}
)
)
.catch(
() => {process.exit(2);}
);
}
}
}
}
}
}
main();

View file

@ -1,6 +1,17 @@
namespace _heimdall.helpers.misc namespace _heimdall.helpers.misc
{ {
/**
*/
export function get_env_language(
) : (null | string)
{
const env_lang : string = process.env["LANG"];
const locale : string = env_lang.split(".")[0];
const language : string = locale.split("_")[0];
return language;
}
/** /**
*/ */
export function format_bytes( export function format_bytes(

49
source/init.ts Normal file
View file

@ -0,0 +1,49 @@
namespace _heimdall
{
/**
*/
export async function init(
) : Promise<void>
{
const workdir : string = __dirname;
// translation
{
const language_order : Array<string> = ["de", "en"];
await lib_plankton.translate.initialize_promise(
{
"verbosity": 1,
"order": language_order,
"packages": await Promise.all(
[
{"identifier": "de", "path": (workdir + "/localization/de.json")},
{"identifier": "en", "path": (workdir + "/localization/en.json")},
]
.map(
(entry) => (
lib_plankton.file.read(entry.path)
.then(content => Promise.resolve(JSON.parse(content)))
.then(tree => Promise.resolve({"meta": {"identifier": entry.identifier}, "tree": tree}))
)
)
),
}
);
const env_language : (null | string) = _heimdall.helpers.misc.get_env_language();
if (
! (
(env_language !== null)
&&
language_order.includes(env_language)
)
) {
// do nothing
}
else {
lib_plankton.translate.promote(env_language);
}
}
}
}

View file

@ -37,5 +37,5 @@
"misc.check_procedure_failed": "Prüfungs-Prozedur fehlgeschlagen", "misc.check_procedure_failed": "Prüfungs-Prozedur fehlgeschlagen",
"misc.still_running": "läuft bereits/noch", "misc.still_running": "läuft bereits/noch",
"misc.cleanup_info": "{{count}} alte Ergebnis-Datensätze gelöscht", "misc.cleanup_info": "{{count}} alte Ergebnis-Datensätze gelöscht",
"misc.order_file_not_found": "Auftrags-Datei nicht gefunden: {{path}}" "misc.order_file_not_found": "Auftrags-Datei nicht gefunden"
} }

View file

@ -37,5 +37,5 @@
"misc.check_procedure_failed": "check procedure failed", "misc.check_procedure_failed": "check procedure failed",
"misc.still_running": "already/still running", "misc.still_running": "already/still running",
"misc.cleanup_info": "removed {{count}} old result entries", "misc.cleanup_info": "removed {{count}} old result entries",
"misc.order_file_not_found": "order file not found: {{path}}" "misc.order_file_not_found": "order file not found"
} }

View file

@ -1,12 +0,0 @@
namespace _heimdall.check_kinds
{
/**
*/
export type type_check_kind = {
parameters_schema : (() => _heimdall.helpers.json_schema.type_schema);
normalize_order_node : ((node : any) => any);
run : (parameters) => Promise<_heimdall.type_result>;
};
}

View file

@ -0,0 +1,59 @@
namespace _heimdall.check_kinds
{
/**
*/
export type type_check_kind = {
parameters_schema : (
()
=>
_heimdall.helpers.json_schema.type_schema
);
normalize_order_node : (
(node : any)
=>
any
);
run : (
(parameters)
=>
Promise<_heimdall.type_result>
);
};
/**
*/
var _implementations : Record<string, type_check_kind> = {};
/**
*/
export function register_implementation(
name : string,
check_kind : type_check_kind
) : void
{
_implementations[name] = check_kind;
}
/**
*/
export function get_implementation(
name : string
) : type_check_kind
{
return _implementations[name];
}
/**
*/
export function get_implementations(
) : Record<string, type_check_kind>
{
return _implementations;
}
}

View file

@ -366,14 +366,13 @@ namespace _heimdall.check_kinds.file_state
/** /**
*/ */
export function check_kind_implementation( register_implementation(
) : type_check_kind "file_state",
{ {
return {
"parameters_schema": parameters_schema, "parameters_schema": parameters_schema,
"normalize_order_node": normalize_order_node, "normalize_order_node": normalize_order_node,
"run": run, "run": run,
}; }
} );
} }

View file

@ -242,14 +242,13 @@ namespace _heimdall.check_kinds.generic_remote
/** /**
*/ */
export function check_kind_implementation( register_implementation(
) : type_check_kind "generic_remote",
{ {
return {
"parameters_schema": parameters_schema, "parameters_schema": parameters_schema,
"normalize_order_node": normalize_order_node, "normalize_order_node": normalize_order_node,
"run": run, "run": run,
}; }
} );
} }

View file

@ -380,14 +380,13 @@ namespace _heimdall.check_kinds.http_request
/** /**
*/ */
export function check_kind_implementation( register_implementation(
) : type_check_kind "http_request",
{ {
return {
"parameters_schema": parameters_schema, "parameters_schema": parameters_schema,
"normalize_order_node": normalize_order_node, "normalize_order_node": normalize_order_node,
"run": run, "run": run,
}; }
} );
} }

View file

@ -118,14 +118,13 @@ namespace _heimdall.check_kinds.script
/** /**
*/ */
export function check_kind_implementation( register_implementation(
) : type_check_kind "script",
{ {
return {
"parameters_schema": parameters_schema, "parameters_schema": parameters_schema,
"normalize_order_node": normalize_order_node, "normalize_order_node": normalize_order_node,
"run": run, "run": run,
}; }
} );
} }

View file

@ -237,14 +237,13 @@ namespace _heimdall.check_kinds.tls_certificate
/** /**
*/ */
export function check_kind_implementation( register_implementation(
) : type_check_kind "tls_certificate",
{ {
return {
"parameters_schema": parameters_schema, "parameters_schema": parameters_schema,
"normalize_order_node": normalize_order_node, "normalize_order_node": normalize_order_node,
"run": run, "run": run,
}; }
} );
} }

View file

@ -1,176 +0,0 @@
namespace _heimdall.helpers.sqlite
{
/**
*/
export type type_query_raw = {
template : string;
arguments : Record<string, any>;
};
/**
*/
type type_query_transformed = {
template : string;
arguments : Record<string, any>;
};
/**
*/
function query_transform(
query_raw : type_query_raw
) : type_query_transformed
{
return {
"template": query_raw.template,
"arguments": lib_plankton.call.convey(
query_raw.arguments,
[
x => Object.entries(x),
x => (
x.map(
([key, value]) => ([
(":" + key),
value
])
)
),
x => Object.fromEntries(x),
]
),
};
}
/**
*/
function execute(
database_path : string,
action : ((handle) => Promise<void>),
) : Promise<void>
{
return (
new Promise<void>(
async (resolve, reject) => {
const nm_sqlite3 = require("sqlite3");
const handle = new nm_sqlite3.Database(database_path);
try {
await action(handle);
handle.close();
resolve(undefined);
}
catch (error) {
handle.close();
reject(error);
}
}
)
);
}
/**
* for CREATE TABLE, DROP TABLE, etc.
*/
export async function query_set(
database_path : string,
query_raw : type_query_raw
) : Promise<any>
{
const query_transformed : type_query_transformed = query_transform(query_raw);
await execute(
database_path,
(handle) => new Promise<void>(
(resolve, reject) => {
handle.run(
query_transformed.template,
query_transformed.arguments,
(error) => {
if (error) {
reject(error);
}
else {
resolve(undefined);
}
}
);
}
)
);
return undefined;
}
/**
* for INSERT, UPDATE, DELETE
*/
export async function query_put(
database_path : string,
query_raw : type_query_raw
) : Promise<{id : (null | int); affected : (null | int);}>
{
let result : {id : (null | int); affected : (null | int);};
const query_transformed : type_query_transformed = query_transform(query_raw);
await execute(
database_path,
(handle) => new Promise<void>(
(resolve, reject) => {
handle.run(
query_transformed.template,
query_transformed.arguments,
function (error) {
if (error) {
reject(error);
}
else {
result = {
"id": this.lastID,
"affected": this.changes,
};
resolve(undefined);
}
}
);
}
)
);
return result;
}
/**
* for SELECT
*/
export async function query_get(
database_path : string,
query_raw : type_query_raw
) : Promise<Array<Array<any>>>
{
const query_transformed : type_query_transformed = query_transform(query_raw);
let rows : Array<Array<any>> = [];
await execute(
database_path,
(handle) => new Promise<void>(
(resolve, reject) => {
handle.all(
query_transformed.template,
query_transformed.arguments,
(error, row) => {
if (error) {
reject(error);
}
else {
rows.push(row);
resolve(undefined);
}
}
);
}
)
);
return rows;
}
}

View file

@ -1,569 +0,0 @@
async function main(
) : Promise<void>
{
// consts
const version : string = "0.9";
const workdir : string = __dirname;
// init translations
// TODO: use env language
await lib_plankton.translate.initialize_promise(
{
"verbosity": 1,
"order": ["de", "en"],
"packages": await Promise.all(
[
{"identifier": "de", "path": (workdir + "/localization/de.json")},
{"identifier": "en", "path": (workdir + "/localization/en.json")},
]
.map(
(entry) => (
lib_plankton.file.read(entry.path)
.then(content => Promise.resolve(JSON.parse(content)))
.then(tree => Promise.resolve({"meta": {"identifier": entry.identifier}, "tree": tree}))
)
)
),
}
);
// args
const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler(
{
"order_path": new lib_plankton.args.class_argument(
{
"name": "order_path",
"type": lib_plankton.args.enum_type.string,
"kind": lib_plankton.args.enum_kind.positional,
"mode": lib_plankton.args.enum_mode.replace,
"default": "monitoring.hmdl.json",
"parameters": {
"index": 0,
},
"info": lib_plankton.translate.get("help.args.order_path"),
}
),
"show_help": new lib_plankton.args.class_argument(
{
"name": "help",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["help"],
"indicators_short": ["h"],
},
"info": lib_plankton.translate.get("help.args.show_help"),
}
),
"show_version": new lib_plankton.args.class_argument(
{
"name": "version",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["version"],
"indicators_short": ["r"],
},
"info": lib_plankton.translate.get("help.args.show_version"),
}
),
"show_schema": new lib_plankton.args.class_argument(
{
"name": "schema",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["schema"],
"indicators_short": ["s"],
},
"info": lib_plankton.translate.get("help.args.show_schema"),
}
),
"expose_full_order": new lib_plankton.args.class_argument(
{
"name": "expose_full_order",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["expose-full-order"],
"indicators_short": ["e"],
},
"info": lib_plankton.translate.get("help.args.expose_full_order"),
}
),
"erase_state": new lib_plankton.args.class_argument(
{
"name": "erase_state",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["erase-state"],
"indicators_short": ["x"],
},
"info": lib_plankton.translate.get("help.args.erase_state"),
}
),
"database_path": new lib_plankton.args.class_argument(
{
"name": "database_path",
"type": lib_plankton.args.enum_type.string,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": null,
"parameters": {
"indicators_long": ["database-path"],
"indicators_short": ["d"],
},
"info": lib_plankton.translate.get("help.args.database_path"),
}
),
"mutex_path": new lib_plankton.args.class_argument(
{
"name": "mutex_path",
"type": lib_plankton.args.enum_type.string,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": "/tmp/heimdall.lock",
"parameters": {
"indicators_long": ["mutex-path"],
"indicators_short": ["m"],
},
"info": lib_plankton.translate.get("help.args.mutex_path"),
}
),
"send_ok_notifications": new lib_plankton.args.class_argument(
{
"name": "send_ok_notifications",
"type": lib_plankton.args.enum_type.boolean,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"parameters": {
"indicators_long": ["send-ok-notifications"],
"indicators_short": ["y"],
},
"info": lib_plankton.translate.get(
"help.args.send_ok_notifications",
{
"condition_name": lib_plankton.translate.get("conditions.ok"),
}
),
}
),
"language": new lib_plankton.args.class_argument(
{
"name": "language",
"type": lib_plankton.args.enum_type.string,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": null,
"parameters": {
"indicators_long": ["language"],
"indicators_short": ["l"],
},
"info": lib_plankton.translate.get("help.args.language"),
}
),
"time_to_live": new lib_plankton.args.class_argument(
{
"name": "time_to_live",
"type": lib_plankton.args.enum_type.float,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": (60 * 60 * 24 * 7),
"parameters": {
"indicators_long": ["time-to-live"],
"indicators_short": ["t"],
},
"info": lib_plankton.translate.get("help.args.time_to_live"),
}
),
"verbosity": new lib_plankton.args.class_argument(
{
"name": "verbosity",
"type": lib_plankton.args.enum_type.integer,
"kind": lib_plankton.args.enum_kind.volatile,
"mode": lib_plankton.args.enum_mode.replace,
"default": 1,
"parameters": {
"indicators_long": ["verbosity"],
"indicators_short": ["v"],
},
"info": lib_plankton.translate.get("help.args.verbosity"),
}
),
}
);
const args : Record<string, any> = arg_handler.read(
lib_plankton.args.enum_environment.cli,
process.argv.slice(2).join(" ")
);
// setup logging
lib_plankton.log.conf_push(
[
new lib_plankton.log.class_channel_minlevel(
new lib_plankton.log.class_channel_stdout(),
[
lib_plankton.log.enum_level.debug,
lib_plankton.log.enum_level.info,
lib_plankton.log.enum_level.notice,
lib_plankton.log.enum_level.warning,
lib_plankton.log.enum_level.error,
][Math.min(4, args["verbosity"])]
),
]
);
// exec
if (args.show_help) {
process.stdout.write(
arg_handler.generate_help(
{
"programname": "heimdall",
"description": lib_plankton.translate.get("help.title"),
"executable": "heimdall",
}
)
);
}
else {
if (args["show_version"]) {
process.stdout.write(version + "\n");
}
else {
const notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind> = {
"console": _heimdall.notification_kinds.console.notification_kind_implementation(),
"email": _heimdall.notification_kinds.email.notification_kind_implementation(),
"libnotify": _heimdall.notification_kinds.libnotify.notification_kind_implementation(),
};
const check_kind_implementations : Record<string, _heimdall.check_kinds.type_check_kind> = {
"script": _heimdall.check_kinds.script.check_kind_implementation(),
"http_request": _heimdall.check_kinds.http_request.check_kind_implementation(),
"file_state": _heimdall.check_kinds.file_state.check_kind_implementation(),
"tls_certificate": _heimdall.check_kinds.tls_certificate.check_kind_implementation(),
"generic_remote": _heimdall.check_kinds.generic_remote.check_kind_implementation(),
};
if (args["show_schema"]) {
process.stdout.write(
lib_plankton.json.encode(
_heimdall.order.schema_root(
check_kind_implementations,
notification_kind_implementations
),
true
)
+
"\n"
)
}
else {
const nm_path = require("path");
const nm_fs = require("fs");
if (! nm_fs.existsSync(args["order_path"])) {
process.stderr.write(
lib_plankton.translate.get(
"misc.order_file_not_found",
{
"path": args["order_path"],
}
)
+
"\n"
);
}
else {
// get order data
const order = await _heimdall.order.load(
check_kind_implementations,
notification_kind_implementations,
nm_path.normalize(args["order_path"])
);
if (args["expose_full_order"]) {
process.stdout.write(lib_plankton.json.encode(order, true) + "\n");
}
else {
const database_path : string = (
(args["database_path"] !== null)
? args["database_path"]
: nm_path.join(
// TODO get path from fs or path module?
"/tmp",
lib_plankton.string.coin(
"monitoring-state-{{id}}.sqlite",
{
"id": lib_plankton.call.convey(
args["order_path"],
[
nm_path.normalize,
// encode(ascii),
x => lib_plankton.sha256.get(x),
x => x.slice(0, 8),
]
),
}
)
)
);
lib_plankton.log.info(
lib_plankton.translate.get("misc.state_file_path"),
{
"database_path": database_path,
}
);
// mutex check
if (nm_fs.existsSync(args["mutex_path"])) {
lib_plankton.log.error(
lib_plankton.translate.get("misc.still_running"),
{
"mutex_path": args["mutex_path"],
}
);
process.exit(2);
}
else {
await _heimdall.state_repository.setup(database_path);
const clean_count : int = await _heimdall.state_repository.clean(
database_path,
args["time_to_live"],
args["erase_state"]
);
// create mutex file
await lib_plankton.file.write(args["mutex_path"], "");
for await (const check of order.checks) {
if (! check.active) {
// do nothing
}
else {
let old_item_state : (null | _heimdall.type_item_state);
const last_notification_timestamp : (null | int) = await _heimdall.state_repository.get_last_notification_timestamp(
database_path,
check.name
);
const rows : Array<
{
timestamp : int;
condition : _heimdall.enum_condition;
notification_sent : boolean;
}
> = await _heimdall.state_repository.probe(
database_path,
check.name,
(check.threshold + 1),
);
if (rows.length <= 0) {
old_item_state = null;
}
else {
let count : int = 1;
rows.slice(1).some(
(row) => {
if (row.condition === rows[0].condition) {
count += 1;
return true;
}
else {
return false;
}
}
);
if (count > check.threshold) {
count = null;
}
else {
// do nothing
}
old_item_state = {
"timestamp": rows[0].timestamp,
"condition": rows[0].condition,
"count": count,
"last_notification_timestamp": last_notification_timestamp,
}
const timestamp : int = _heimdall.get_current_timestamp();
const due : boolean = (
(old_item_state === null)
||
(old_item_state.condition !== _heimdall.enum_condition.ok)
||
((timestamp - old_item_state.timestamp) >= check.schedule.regular_interval)
||
(
(! (old_item_state.count === null))
&&
((timestamp - old_item_state.timestamp) >= check.schedule.attentive_interval)
)
);
if (! due) {
// do nothing
}
else {
process.stderr.write(
lib_plankton.string.coin(
"-- {{check_name}}\n",
{
"check_name": check.name,
}
)
);
// execute check and set new state
let result;
try {
result = await check_kind_implementations[check.kind].run(check.parameters);
}
catch (error) {
result = {
"condition": _heimdall.enum_condition.unknown,
"info": {
"cause": lib_plankton.translate.get("misc.check_procedure_failed"),
"error": error.toString(),
},
}
}
const count : (null | int) = (
(
(old_item_state === null)
||
(old_item_state.condition !== result.condition)
)
? 1
: (
(
(! (old_item_state.count === null))
&&
((old_item_state.count + 1) <= check.threshold)
)
? (old_item_state.count + 1)
: null
)
)
const shall_send_notification : boolean = (
(
(
(! (count === null))
&&
(count == check.threshold)
)
||
(
(count === null)
&&
check.annoy
)
||
(
(count === null)
&&
(
(! (old_item_state === null))
&&
(! (old_item_state.last_notification_timestamp === null))
&&
(! (check.schedule.reminding_interval === null))
&&
(
(timestamp - old_item_state.last_notification_timestamp)
>=
check.schedule.reminding_interval
)
)
)
)
&&
(
(result.condition !== _heimdall.enum_condition.ok)
||
args["send_ok_notifications"]
)
)
const new_item_state : _heimdall.type_item_state = {
"timestamp": timestamp,
"condition": result.condition,
"count": count,
"last_notification_timestamp": (
shall_send_notification
? timestamp
: (
(old_item_state === null)
? null
: old_item_state.last_notification_timestamp
)
),
}
await _heimdall.state_repository.feed(
database_path,
check.name,
timestamp,
result.condition,
shall_send_notification,
result.info
);
// send notifications
if (! shall_send_notification) {
// do nothing
}
else {
check.notifications.forEach(
notification => {
notification_kind_implementations[notification.kind].notify(
notification.parameters,
check.name,
check,
new_item_state,
Object.assign(
(
(check.custom === null)
? {}
: {"custom": check.custom}
),
result.info
)
)
}
);
}
}
}
}
}
// drop mutex file
await (
new Promise<void>(
(resolve, reject) => {
nm_fs.unlink(
args["mutex_path"],
() => {
resolve(undefined);
}
);
}
)
);
}
}
}
}
}
}
}
main();

365
source/logic/master.ts Normal file
View file

@ -0,0 +1,365 @@
namespace _heimdall.master
{
/**
* @todo automated tests
*/
export function determine_due(
check : _heimdall.type_check,
timestamp : int,
old_item_state : (null | _heimdall.type_item_state),
) : boolean
{
return (
(old_item_state === null)
||
(old_item_state.condition !== _heimdall.enum_condition.ok)
||
((timestamp - old_item_state.timestamp) >= check.schedule.regular_interval)
||
(
(! (old_item_state.count === null))
&&
((timestamp - old_item_state.timestamp) >= check.schedule.attentive_interval)
)
);
}
/**
* @todo automated tests
*/
function determine_shall_send_notification(
check : _heimdall.type_check,
send_ok_notifications : boolean,
count : (null | int),
timestamp : int,
old_item_state : (null | _heimdall.type_item_state),
result : _heimdall.type_result
) : boolean
{
return (
(
(
(! (count === null))
&&
(count == check.threshold)
)
||
(
(count === null)
&&
check.annoy
)
||
(
(count === null)
&&
(
(! (old_item_state === null))
&&
(! (old_item_state.last_notification_timestamp === null))
&&
(! (check.schedule.reminding_interval === null))
&&
(
(timestamp - old_item_state.last_notification_timestamp)
>=
check.schedule.reminding_interval
)
)
)
)
&&
(
(result.condition !== _heimdall.enum_condition.ok)
||
send_ok_notifications
)
);
}
/**
*/
export async function clean(
options : {
time_to_live ?: int;
erase_state ?: boolean;
} = {}
) : Promise<void>
{
options = Object.assign(
{
"time_to_live": (7 * 24 * 60 * 60),
"erase_state": false,
},
options
);
const count : int = await _heimdall.state_repository.clean(
options.time_to_live,
options.erase_state
);
lib_plankton.log.info(
lib_plankton.translate.get(
"cleanup_info",
{
"count": count.toFixed(0),
}
),
{
}
);
}
/**
*/
export async function wrap_database(
database_path_raw : (null | string),
order_path : string,
procedure : (() => Promise<void>)
) : Promise<void>
{
const nm_path = require("path");
const database_path : string = (
(database_path_raw !== null)
? database_path_raw
: nm_path.join(
// TODO get path from fs or path module?
"/tmp",
lib_plankton.string.coin(
"monitoring-state-{{id}}.sqlite",
{
"id": lib_plankton.call.convey(
order_path,
[
nm_path.normalize,
// encode(ascii),
x => lib_plankton.sha256.get(x),
x => x.slice(0, 8),
]
),
}
)
)
);
lib_plankton.log.info(
lib_plankton.translate.get("misc.state_file_path"),
{
"database_path": database_path,
}
);
await _heimdall.state_repository.init(database_path);
await procedure();
await _heimdall.state_repository.kill();
}
/**
* @todo outsource?
*/
export async function wrap_mutex(
mutex_path : string,
procedure : (() => Promise<void>)
) : Promise<void>
{
const nm_fs = require("fs");
if (nm_fs.existsSync(mutex_path)) {
lib_plankton.log.error(
lib_plankton.translate.get("misc.still_running"),
{
"mutex_path": mutex_path,
}
);
return Promise.reject();
}
else {
await lib_plankton.file.write(mutex_path, "");
await procedure();
await lib_plankton.file.delete_(mutex_path);
}
}
/**
* central processing procedure
*/
export async function run(
order : _heimdall.type_order,
options : {
send_ok_notifications ?: boolean;
} = {}
) : Promise<void>
{
options = Object.assign(
{
"send_ok_notifications": false
},
options
);
const notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind> = _heimdall.notification_kinds.get_implementations();
const check_kind_implementations : Record<string, _heimdall.check_kinds.type_check_kind> = _heimdall.check_kinds.get_implementations();
for await (const check of order.checks) {
if (! check.active) {
// do nothing
}
else {
let old_item_state : (null | _heimdall.type_item_state);
const last_notification_timestamp : (null | int) = await _heimdall.state_repository.get_last_notification_timestamp(
check.name
);
const rows : Array<
{
timestamp : int;
condition : _heimdall.enum_condition;
notification_sent : boolean;
}
> = await _heimdall.state_repository.probe(
check.name,
(check.threshold + 1),
);
if (rows.length <= 0) {
old_item_state = null;
}
else {
let count : int = 1;
rows.slice(1).some(
(row) => {
if (row.condition === rows[0].condition) {
count += 1;
return true;
}
else {
return false;
}
}
);
if (count > check.threshold) {
count = null;
}
else {
// do nothing
}
old_item_state = {
"timestamp": rows[0].timestamp,
"condition": rows[0].condition,
"count": count,
"last_notification_timestamp": last_notification_timestamp,
}
const timestamp : int = _heimdall.get_current_timestamp();
const due : boolean = determine_due(
check,
timestamp,
old_item_state
);
if (! due) {
// do nothing
}
else {
process.stderr.write(
lib_plankton.string.coin(
"-- {{check_name}}\n",
{
"check_name": check.name,
}
)
);
// execute check and set new state
let result : _heimdall.type_result;
try {
result = await check_kind_implementations[check.kind].run(check.parameters);
}
catch (error) {
result = {
"condition": _heimdall.enum_condition.unknown,
"info": {
"cause": lib_plankton.translate.get("misc.check_procedure_failed"),
"error": error.toString(),
},
};
}
const count : (null | int) = (
(
(old_item_state === null)
||
(old_item_state.condition !== result.condition)
)
? 1
: (
(
(! (old_item_state.count === null))
&&
((old_item_state.count + 1) <= check.threshold)
)
? (old_item_state.count + 1)
: null
)
);
const shall_send_notification : boolean = determine_shall_send_notification(
check,
options.send_ok_notifications,
count,
timestamp,
old_item_state,
result
);
const new_item_state : _heimdall.type_item_state = {
"timestamp": timestamp,
"condition": result.condition,
"count": count,
"last_notification_timestamp": (
shall_send_notification
? timestamp
: (
(old_item_state === null)
? null
: old_item_state.last_notification_timestamp
)
),
}
await _heimdall.state_repository.feed(
check.name,
timestamp,
result.condition,
shall_send_notification,
result.info
);
// send notifications
if (! shall_send_notification) {
// do nothing
}
else {
check.notifications.forEach(
notification => {
notification_kind_implementations[notification.kind].notify(
notification.parameters,
check.name,
check,
new_item_state,
Object.assign(
(
(check.custom === null)
? {}
: {"custom": check.custom}
),
result.info
)
)
}
);
}
}
}
}
}
}
}

View file

@ -1,18 +0,0 @@
namespace _heimdall.notification_kinds
{
/**
*/
export type type_notification_kind = {
parameters_schema : (() => _heimdall.helpers.json_schema.type_schema);
normalize_order_node : ((node : any) => any);
notify : (
parameters : any,
name : string,
data : type_check,
state : type_item_state,
info : any
) => Promise<void>;
};
}

View file

@ -0,0 +1,65 @@
namespace _heimdall.notification_kinds
{
/**
*/
export type type_notification_kind = {
parameters_schema : (
()
=>
_heimdall.helpers.json_schema.type_schema
);
normalize_order_node : (
(node : any)
=>
any
);
notify : (
(
parameters : any,
name : string,
data : type_check,
state : type_item_state,
info : any
)
=>
Promise<void>
);
};
/**
*/
var _implementations : Record<string, type_notification_kind> = {};
/**
*/
export function register_implementation(
name : string,
notification_kind : type_notification_kind
) : void
{
_implementations[name] = notification_kind;
}
/**
*/
export function get_implementation(
name : string
) : type_notification_kind
{
return _implementations[name];
}
/**
*/
export function get_implementations(
) : Record<string, type_notification_kind>
{
return _implementations;
}
}

View file

@ -57,14 +57,13 @@ namespace _heimdall.notification_kinds.console
/** /**
*/ */
export function notification_kind_implementation( register_implementation(
) : type_notification_kind "console",
{ {
return {
"parameters_schema": parameters_schema, "parameters_schema": parameters_schema,
"normalize_order_node": normalize_order_node, "normalize_order_node": normalize_order_node,
"notify": notify, "notify": notify,
}; }
} );
} }

View file

@ -128,14 +128,13 @@ namespace _heimdall.notification_kinds.email
/** /**
*/ */
export function notification_kind_implementation( register_implementation(
) : type_notification_kind "email",
{ {
return {
"parameters_schema": parameters_schema, "parameters_schema": parameters_schema,
"normalize_order_node": normalize_order_node, "normalize_order_node": normalize_order_node,
"notify": notify, "notify": notify,
}; }
} );
} }

View file

@ -114,14 +114,13 @@ namespace _heimdall.notification_kinds.libnotify
/** /**
*/ */
export function notification_kind_implementation( register_implementation(
) : type_notification_kind "libnotify",
{ {
return {
"parameters_schema": parameters_schema, "parameters_schema": parameters_schema,
"normalize_order_node": normalize_order_node, "normalize_order_node": normalize_order_node,
"notify": notify, "notify": notify,
}; }
} );
} }

View file

@ -107,9 +107,9 @@ namespace _heimdall.order
/** /**
*/ */
function schema_notifications( function schema_notifications(
notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind>
) : _heimdall.helpers.json_schema.type_schema ) : _heimdall.helpers.json_schema.type_schema
{ {
const notification_kind_implementations = _heimdall.notification_kinds.get_implementations();
return { return {
"type": "array", "type": "array",
"items": { "items": {
@ -149,10 +149,9 @@ namespace _heimdall.order
/** /**
*/ */
export function schema_root( export function schema_root(
check_kind_implementations : Record<string, _heimdall.check_kinds.type_check_kind>,
notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind>,
) : _heimdall.helpers.json_schema.type_schema ) : _heimdall.helpers.json_schema.type_schema
{ {
const check_kind_implementations = _heimdall.check_kinds.get_implementations();
return { return {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
@ -166,7 +165,7 @@ namespace _heimdall.order
"threshold": schema_threshold(), "threshold": schema_threshold(),
"annoy": schema_annoy(), "annoy": schema_annoy(),
"schedule": schema_schedule(), "schedule": schema_schedule(),
"notifications": schema_notifications(notification_kind_implementations), "notifications": schema_notifications(),
}, },
"required": [ "required": [
], ],
@ -198,7 +197,7 @@ namespace _heimdall.order
"threshold": schema_threshold(), "threshold": schema_threshold(),
"annoy": schema_annoy(), "annoy": schema_annoy(),
"schedule": schema_schedule(), "schedule": schema_schedule(),
"notifications": schema_notifications(notification_kind_implementations), "notifications": schema_notifications(),
}, },
"required": [ "required": [
"name", "name",
@ -301,10 +300,10 @@ namespace _heimdall.order
/** /**
*/ */
function normalize_notification( function normalize_notification(
notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind>,
node : any node : any
) : type_notification ) : type_notification
{ {
const notification_kind_implementations = _heimdall.notification_kinds.get_implementations();
if (! (node["kind"] in notification_kind_implementations)) { if (! (node["kind"] in notification_kind_implementations)) {
throw new Error("invalid notification kind: " + node["kind"]); throw new Error("invalid notification kind: " + node["kind"]);
} }
@ -320,7 +319,6 @@ namespace _heimdall.order
/** /**
*/ */
function normalize_defaults( function normalize_defaults(
notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind>,
node : any node : any
) : type_check_common ) : type_check_common
{ {
@ -346,7 +344,7 @@ namespace _heimdall.order
"schedule": node_["schedule"], "schedule": node_["schedule"],
"notifications": ( "notifications": (
node_["notifications"] node_["notifications"]
.map(x => normalize_notification(notification_kind_implementations, x)) .map(x => normalize_notification(x))
), ),
}; };
} }
@ -355,8 +353,6 @@ namespace _heimdall.order
/** /**
*/ */
function normalize_check( function normalize_check(
check_kind_implementations : Record<string, _heimdall.check_kinds.type_check_kind>,
notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind>,
defaults : type_check_common, defaults : type_check_common,
node : { node : {
name : string; name : string;
@ -364,6 +360,8 @@ namespace _heimdall.order
} }
) : type_check ) : type_check
{ {
const check_kind_implementations = _heimdall.check_kinds.get_implementations();
const notification_kind_implementations = _heimdall.notification_kinds.get_implementations();
if (! ("name" in node)) { if (! ("name" in node)) {
throw new Error("missing mandatory field in 'check' node: 'name'"); throw new Error("missing mandatory field in 'check' node: 'name'");
} }
@ -410,7 +408,7 @@ namespace _heimdall.order
check.notifications = ( check.notifications = (
node_["notifications"] node_["notifications"]
.map( .map(
x => normalize_notification(notification_kind_implementations, x), x => normalize_notification(x),
) )
); );
} }
@ -427,8 +425,6 @@ namespace _heimdall.order
/** /**
*/ */
function normalize_root( function normalize_root(
check_kind_implementations : Record<string, _heimdall.check_kinds.type_check_kind>,
notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind>,
node : any, node : any,
options : { options : {
use_implicit_default_values ?: boolean; use_implicit_default_values ?: boolean;
@ -440,7 +436,8 @@ namespace _heimdall.order
"use_implicit_default_values": true, "use_implicit_default_values": true,
}, },
options options
) );
let counts : Record<string, int> = {}; let counts : Record<string, int> = {};
const checks_raw : Array<any> = ( const checks_raw : Array<any> = (
("checks" in node) ("checks" in node)
@ -480,7 +477,6 @@ namespace _heimdall.order
const defaults : type_check_common = ( const defaults : type_check_common = (
options.use_implicit_default_values options.use_implicit_default_values
? normalize_defaults( ? normalize_defaults(
notification_kind_implementations,
defaults_raw defaults_raw
) )
: defaults_raw : defaults_raw
@ -497,8 +493,6 @@ namespace _heimdall.order
checks_raw checks_raw
.map( .map(
node_ => normalize_check( node_ => normalize_check(
check_kind_implementations,
notification_kind_implementations,
defaults, defaults,
node_ node_
) )
@ -512,8 +506,6 @@ namespace _heimdall.order
/** /**
*/ */
export async function load( export async function load(
check_kind_implementations : Record<string, _heimdall.check_kinds.type_check_kind>,
notification_kind_implementations : Record<string, _heimdall.notification_kinds.type_notification_kind>,
path : string, path : string,
options : { options : {
root ?: boolean; root ?: boolean;
@ -529,7 +521,8 @@ namespace _heimdall.order
"already_included": [], "already_included": [],
}, },
options options
) );
if (options.already_included.includes(path)) { if (options.already_included.includes(path)) {
throw new Error("circular dependency detected") throw new Error("circular dependency detected")
} }
@ -546,8 +539,6 @@ namespace _heimdall.order
for (let index = 0; index < includes.length; index += 1) { for (let index = 0; index < includes.length; index += 1) {
const path_ : string = includes[index]; const path_ : string = includes[index];
const sub_order : type_order = await load( const sub_order : type_order = await load(
check_kind_implementations,
notification_kind_implementations,
( (
nm_path.isAbsolute(path_) nm_path.isAbsolute(path_)
? path_ ? path_
@ -582,8 +573,6 @@ namespace _heimdall.order
order_raw.includes = []; order_raw.includes = [];
} }
return normalize_root( return normalize_root(
check_kind_implementations,
notification_kind_implementations,
order_raw, order_raw,
{ {
"use_implicit_default_values": options["root"], "use_implicit_default_values": options["root"],

View file

@ -1,6 +1,11 @@
namespace _heimdall.state_repository namespace _heimdall.state_repository
{ {
/**
*/
var _connection : (null | lib_plankton.sqlite.type_connection) = null;
/** /**
*/ */
function condition_decode( function condition_decode(
@ -33,12 +38,32 @@ namespace _heimdall.state_repository
/** /**
*/ */
export async function setup( export async function init(
database_path : string database_path : string
) : Promise<void> ) : Promise<void>
{ {
const result = await _heimdall.helpers.sqlite.query_set( _connection = await lib_plankton.sqlite.get_connection(database_path);
database_path, await setup();
}
/**
*/
export async function kill(
) : Promise<void>
{
await lib_plankton.sqlite.drop_connection(_connection);
_connection = null;
}
/**
*/
export async function setup(
) : Promise<void>
{
const result = await lib_plankton.sqlite.query_set(
_connection,
{ {
"template": "CREATE TABLE IF NOT EXISTS results(check_name TEXT NOT NULL, timestamp INTEGER NOT NULL, condition TEXT NOT NULL, notification_sent BOOLEAN NOT NULL, info TEXT NOT NULL);", "template": "CREATE TABLE IF NOT EXISTS results(check_name TEXT NOT NULL, timestamp INTEGER NOT NULL, condition TEXT NOT NULL, notification_sent BOOLEAN NOT NULL, info TEXT NOT NULL);",
"arguments": { "arguments": {
@ -51,13 +76,12 @@ namespace _heimdall.state_repository
/** /**
*/ */
export async function clean( export async function clean(
database_path : string,
time_to_live : int, time_to_live : int,
erase_state : boolean erase_state : boolean
) : Promise<int> ) : Promise<int>
{ {
const result = await _heimdall.helpers.sqlite.query_put( const result = await lib_plankton.sqlite.query_put(
database_path, _connection,
{ {
"template": "DELETE FROM results WHERE ((timestamp < :timestamp_min) OR :erase_state);", "template": "DELETE FROM results WHERE ((timestamp < :timestamp_min) OR :erase_state);",
"arguments": { "arguments": {
@ -73,7 +97,6 @@ namespace _heimdall.state_repository
/** /**
*/ */
export async function probe( export async function probe(
database_path : string,
check_name : string, check_name : string,
threshold : int threshold : int
) : Promise< ) : Promise<
@ -86,8 +109,8 @@ namespace _heimdall.state_repository
> >
> >
{ {
const rows : Array<Array<any>> = await _heimdall.helpers.sqlite.query_get( const rows : Array<Record<string, any>> = await lib_plankton.sqlite.query_get(
database_path, _connection,
{ {
"template": "SELECT timestamp, condition, notification_sent FROM results WHERE (check_name = :check_name) ORDER BY timestamp DESC LIMIT :limit;", "template": "SELECT timestamp, condition, notification_sent FROM results WHERE (check_name = :check_name) ORDER BY timestamp DESC LIMIT :limit;",
"arguments": { "arguments": {
@ -100,9 +123,9 @@ namespace _heimdall.state_repository
rows rows
.map( .map(
row => ({ row => ({
"timestamp": row[0], "timestamp": row["timestamp"],
"condition": condition_decode(row[1]), "condition": condition_decode(row["condition"]),
"notification_sent": row[2], "notification_sent": row["notification_sent"],
}) })
) )
); );
@ -112,27 +135,25 @@ namespace _heimdall.state_repository
/** /**
*/ */
export async function get_last_notification_timestamp( export async function get_last_notification_timestamp(
database_path : string,
check_name : string check_name : string
) : Promise<(null | int)> ) : Promise<(null | int)>
{ {
const rows : Array<Array<any>> = await _heimdall.helpers.sqlite.query_get( const rows : Array<Record<string, any>> = await lib_plankton.sqlite.query_get(
database_path, _connection,
{ {
"template": "SELECT MAX(timestamp) FROM results WHERE (check_name = :check_name) AND (notification_sent = TRUE);", "template": "SELECT MAX(timestamp) AS max_timestamp FROM results WHERE (check_name = :check_name) AND (notification_sent = TRUE);",
"arguments": { "arguments": {
"check_name": check_name, "check_name": check_name,
}, },
} }
); );
return rows[0][0]; return rows[0]["max_timestamp"];
} }
/** /**
*/ */
export async function feed( export async function feed(
database_path : string,
check_name : string, check_name : string,
timestamp : int, timestamp : int,
condition : _heimdall.enum_condition, condition : _heimdall.enum_condition,
@ -140,8 +161,8 @@ namespace _heimdall.state_repository
info : any info : any
) : Promise<void> ) : Promise<void>
{ {
await _heimdall.helpers.sqlite.query_put( await lib_plankton.sqlite.query_put(
database_path, _connection,
{ {
"template": "INSERT INTO results(check_name, timestamp, condition, notification_sent, info) VALUES (:check_name, :timestamp, :condition, :notification_sent, :info);", "template": "INSERT INTO results(check_name, timestamp, condition, notification_sent, info) VALUES (:check_name, :timestamp, :condition, :notification_sent, :info);",
"arguments": { "arguments": {

102
source/test/test.mocha.ts Normal file
View file

@ -0,0 +1,102 @@
const nm_assert = require("assert");
declare var describe;
declare var it;
_heimdall.init();
describe(
"heimdall",
() => {
function datetimestring_to_timestamp(datetimestring) {
return Math.floor((new Date(datetimestring)).getTime() / 1000);
};
describe(
"master.determine_due",
() => {
const cases = [
{
"name": "regular interval hit",
"input": {
"check": {
"active": true,
"threshold": 1,
"annoy": false,
"schedule": {
"regular_interval": 3600,
"attentive_interval": 120,
"reminding_interval": 86400,
},
"notifications": [],
"name": "test",
"title": "Test",
"kind": "BOGUS",
"parameters": {},
"custom": null,
},
"timestamp": "2023-01-15T12:30:00",
"old_item_state": {
"timestamp": "2023-01-15T11:00:00",
"condition": _heimdall.enum_condition.ok,
"count": 0,
"last_notification_timestamp": "2023-01-15T10:00:00"
}
},
"output": true,
},
{
"name": "regular interval not hit",
"input": {
"check": {
"active": true,
"threshold": 1,
"annoy": false,
"schedule": {
"regular_interval": 3600,
"attentive_interval": 120,
"reminding_interval": 86400,
},
"notifications": [],
"name": "test",
"title": "Test",
"kind": "BOGUS",
"parameters": {},
"custom": null,
},
"timestamp": "2023-01-15T11:30:00",
"old_item_state": {
"timestamp": "2023-01-15T11:00:00",
"condition": _heimdall.enum_condition.ok,
"count": 0,
"last_notification_timestamp": "2023-01-15T10:00:00"
}
},
"output": false,
},
];
cases.forEach(
case_ => {
it(
case_.name,
() => {
// execution
const result : boolean = _heimdall.master.determine_due(
case_.input["check"],
datetimestring_to_timestamp(case_.input["timestamp"]),
{
"timestamp": datetimestring_to_timestamp(case_.input["old_item_state"]["timestamp"]),
"condition": case_.input["old_item_state"]["condition"],
"count": case_.input["old_item_state"]["count"],
"last_notification_timestamp": datetimestring_to_timestamp(case_.input["old_item_state"]["last_notification_timestamp"]),
}
);
// assertions
nm_assert.equal(result, case_.output);
}
);
}
);
}
);
}
);

View file

@ -1,105 +0,0 @@
definitions = [
{
"name": "lib.string_coin",
"procedure": lambda input_: string_coin(input_["template"], input_["arguments"]),
"cases": [
{
"input": {
"template": "{{sachen}} sind {{farbe}}",
"arguments": {
"farbe": "rot",
},
},
"output": "{{sachen}} sind rot"
},
{
"input": {
"template": "{{sachen}} sind {{farbe}}",
"arguments": {
},
},
"output": "{{sachen}} sind {{farbe}}"
},
{
"input": {
"template": "{{sachen}} sind {{farbe}}",
"arguments": {
"sachen": "rosen",
"farbe": "rot",
},
},
"output": "rosen sind rot"
},
{
"input": {
"template": "{{sachen}} sind {{farbe}}",
"arguments": {
"sachen": "rosen",
"farbe": "rot",
"ort": "frankreich",
},
},
"output": "rosen sind rot"
},
],
},
{
"name": "lib.format_bytes",
"procedure": lambda input_: format_bytes(input_),
"cases": [
{
"input": 999,
"output": "999 B",
},
{
"input": 1000,
"output": "1.0 KB",
},
{
"input": 1000000,
"output": "1.0 MB",
},
{
"input": 1000000000,
"output": "1.0 GB",
},
{
"input": 1000000000000,
"output": "1.0 TB",
},
{
"input": 1000000000000000,
"output": "1.0 PB",
},
{
"input": 1000000000000000000,
"output": "1000.0 PB",
},
],
},
]
for definition in definitions:
fails = 0
for index in range(len(definition["cases"])):
case = definition["cases"][index]
output_actual = definition["procedure"](case["input"])
output_expected = case["output"]
passed = (output_actual == output_expected)
fails += (0 if passed else 1)
info = {
"input": case["input"],
"output_expected": output_expected,
"output_actual": output_actual,
}
_sys.stderr.write(
"[%s] %s.%u%s\n"
% (
("+" if passed else "x"),
definition["name"],
index,
("" if passed else (": " + _json.dumps(info))),
)
)
_sys.exit(1 if (fails > 0) else 0)

View file

@ -1,4 +1,3 @@
- neu schreiben in TypeScript (und plankton dafür nutzen?)
- Benachrichtigungen versenden, wenn ein Zustand sich wieder normalisiert hat (aber vorher über dem Schwellwert oft nicht OK war) - Benachrichtigungen versenden, wenn ein Zustand sich wieder normalisiert hat (aber vorher über dem Schwellwert oft nicht OK war)
- Selbst-Test - Selbst-Test
- Benachrichtigungs-Kanäle: - Benachrichtigungs-Kanäle:

View file

@ -2,13 +2,24 @@
## vars ## vars
path_prj_from=tools/heimdall.prj.json path_prj_core_from=tools/heimdall-core.prj.json
path_prj_to=heimdall.prj.json path_prj_core_to=heimdall-core.prj.json
path_prj_app_from=tools/heimdall-app.prj.json
path_prj_app_to=heimdall-app.prj.json
path_prj_test_from=tools/heimdall-test.prj.json
path_prj_test_to=heimdall-test.prj.json
## exec ## exec
cp ${path_prj_from} ${path_prj_to} cp ${path_prj_core_from} ${path_prj_core_to}
koralle --execute ${path_prj_to} cp ${path_prj_app_from} ${path_prj_app_to}
cp ${path_prj_test_from} ${path_prj_test_to}
koralle --execute ${path_prj_app_to}
chmod +r build/heimdall chmod +r build/heimdall
rm ${path_prj_to} koralle --execute ${path_prj_test_to}
rm ${path_prj_test_to}
rm ${path_prj_app_to}
rm ${path_prj_core_to}

View file

@ -0,0 +1,57 @@
{
"name": "heimdall-app",
"dependencies": [
"heimdall-core.prj.json"
],
"roottask": {
"name": "all",
"type": "group",
"sub": [
{
"name": "postprocess",
"sub": [
{
"name": "link",
"sub": [
{
"name": "compile",
"type": "typescript",
"parameters": {
"inputs": [
"lib/plankton/plankton.d.ts",
"temp/heimdall-core.d.ts",
"source/app/cli.ts"
],
"target": "es2020",
"strict": true,
"output": "temp/heimdall-app.raw.js"
}
}
],
"type": "concat",
"parameters": {
"inputs": [
"source/misc/head.js",
"lib/plankton/plankton.js",
"temp/heimdall-core.js",
"temp/heimdall-app.raw.js"
],
"output": "temp/heimdall-app.js"
}
}
],
"type": "script",
"parameters": {
"path": "tools/postprocess",
"interpreter": null,
"inputs": [
"temp/heimdall-app.js"
],
"outputs": [
"build/heimdall"
]
}
}
]
}
}

View file

@ -0,0 +1,59 @@
{
"name": "heimdall-core",
"dependencies": [
],
"roottask": {
"name": "all",
"type": "group",
"sub": [
{
"name": "compile",
"type": "typescript",
"parameters": {
"inputs": [
"lib/plankton/plankton.d.ts",
"source/base.ts",
"source/helpers/json_schema.ts",
"source/helpers/misc.ts",
"source/logic/state_repository.ts",
"source/logic/notification_kinds/_base.ts",
"source/logic/notification_kinds/console.ts",
"source/logic/notification_kinds/email.ts",
"source/logic/notification_kinds/libnotify.ts",
"source/logic/check_kinds/_base.ts",
"source/logic/check_kinds/script.ts",
"source/logic/check_kinds/http_request.ts",
"source/logic/check_kinds/file_state.ts",
"source/logic/check_kinds/tls_certificate.ts",
"source/logic/check_kinds/generic_remote.ts",
"source/logic/order.ts",
"source/logic/master.ts",
"source/init.ts"
],
"target": "es2020",
"strict": true,
"output": "temp/heimdall-core.js",
"declaration": "temp/heimdall-core.d.ts"
}
},
{
"name": "node_modules",
"type": "copy",
"parameters": {
"folder": true,
"input": "lib/node/node_modules/",
"output": "build/node_modules/"
}
},
{
"name": "localization",
"type": "copy",
"parameters": {
"folder": true,
"input": "source/localization/",
"output": "build/localization/"
}
}
]
}
}

View file

@ -0,0 +1,34 @@
{
"name": "heimdall-test",
"dependencies": [
"heimdall-core.prj.json"
],
"roottask": {
"name": "link",
"sub": [
{
"name": "compile",
"type": "typescript",
"parameters": {
"inputs": [
"lib/plankton/plankton.d.ts",
"temp/heimdall-core.d.ts",
"source/test/test.mocha.ts"
],
"target": "es2020",
"strict": true,
"output": "temp/heimdall-test.mocha.raw.js"
}
}
],
"type": "concat",
"parameters": {
"inputs": [
"lib/plankton/plankton.js",
"temp/heimdall-core.js",
"temp/heimdall-test.mocha.raw.js"
],
"output": "build/heimdall-test.mocha.js"
}
}
}

View file

@ -1,90 +0,0 @@
{
"name": "heimdall",
"version": "0.8",
"dependencies": [
],
"roottask": {
"name": "logic",
"type": "group",
"sub": [
{
"name": "postprocess",
"sub": [
{
"name": "link",
"sub": [
{
"name": "compile",
"type": "typescript",
"parameters": {
"inputs": [
"lib/plankton/plankton.d.ts",
"source/logic/base.ts",
"source/logic/helpers/json_schema.ts",
"source/logic/helpers/sqlite.ts",
"source/logic/helpers/misc.ts",
"source/logic/notification_kinds/_abstract.ts",
"source/logic/notification_kinds/console.ts",
"source/logic/notification_kinds/email.ts",
"source/logic/notification_kinds/libnotify.ts",
"source/logic/check_kinds/_abstract.ts",
"source/logic/check_kinds/script.ts",
"source/logic/check_kinds/http_request.ts",
"source/logic/check_kinds/file_state.ts",
"source/logic/check_kinds/tls_certificate.ts",
"source/logic/check_kinds/generic_remote.ts",
"source/logic/state_repository.ts",
"source/logic/order.ts",
"source/logic/main.ts"
],
"target": "es2020",
"strict": true,
"output": "temp/heimdall-unlinked"
}
}
],
"type": "concat",
"parameters": {
"inputs": [
"source/misc/head.js",
"lib/plankton/plankton.js",
"temp/heimdall-unlinked"
],
"output": "temp/heimdall-raw"
}
}
],
"type": "script",
"parameters": {
"path": "tools/postprocess",
"interpreter": null,
"inputs": [
"temp/heimdall-raw"
],
"outputs": [
"build/heimdall"
]
}
},
{
"active": true,
"name": "node_modules",
"type": "copy",
"parameters": {
"folder": true,
"input": "lib/node/node_modules/",
"output": "build/node_modules/"
}
},
{
"name": "localization",
"type": "copy",
"parameters": {
"folder": true,
"input": "source/localization/",
"output": "build/localization/"
}
}
]
}
}

View file

@ -19,6 +19,7 @@ modules="${modules} file"
modules="${modules} translate" modules="${modules} translate"
modules="${modules} args" modules="${modules} args"
modules="${modules} http" modules="${modules} http"
modules="${modules} sqlite"
## exec ## exec