From fc3d99e3a14d5e0a1e3a9095dc42555e2538a449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Mon, 19 Jun 2023 13:05:17 +0200 Subject: [PATCH] [int] --- lib/plankton/plankton.d.ts | 864 +++---- lib/plankton/plankton.js | 2232 +++++++++-------- .../channels/_interface.py | 0 .../{logic => logic.old}/channels/console.py | 0 source/{logic => logic.old}/channels/email.py | 0 .../channels/libnotify.py | 0 .../check_kinds}/_interface.py | 0 .../check_kinds}/file_state.py | 0 .../check_kinds}/generic_remote.py | 0 .../check_kinds}/http_request.py | 0 .../check_kinds}/script.py | 0 .../check_kinds}/tls_certificate.py | 0 source/{logic => logic.old}/condition.py | 0 source/{logic => logic.old}/lib.py | 0 source/{logic => logic.old}/localization.py | 0 source/{logic => logic.old}/main.py | 0 source/{logic => logic.old}/order.py | 0 source/{logic => logic.old}/packages.py | 0 .../_type.ts => check_kinds/_abstract.ts} | 4 +- source/logic/helpers/json_schema.ts | 2 + source/logic/helpers/sqlite.ts | 25 + source/logic/main.ts | 97 +- .../_abstract.ts} | 4 +- source/logic/order.ts | 187 +- source/logic/state_repository.ts | 37 + tools/heimdall.prj.json | 6 +- tools/update-plankton | 2 + 27 files changed, 1865 insertions(+), 1595 deletions(-) rename source/{logic => logic.old}/channels/_interface.py (100%) rename source/{logic => logic.old}/channels/console.py (100%) rename source/{logic => logic.old}/channels/email.py (100%) rename source/{logic => logic.old}/channels/libnotify.py (100%) rename source/{logic/checks => logic.old/check_kinds}/_interface.py (100%) rename source/{logic/checks => logic.old/check_kinds}/file_state.py (100%) rename source/{logic/checks => logic.old/check_kinds}/generic_remote.py (100%) rename source/{logic/checks => logic.old/check_kinds}/http_request.py (100%) rename source/{logic/checks => logic.old/check_kinds}/script.py (100%) rename source/{logic/checks => logic.old/check_kinds}/tls_certificate.py (100%) rename source/{logic => logic.old}/condition.py (100%) rename source/{logic => logic.old}/lib.py (100%) rename source/{logic => logic.old}/localization.py (100%) rename source/{logic => logic.old}/main.py (100%) rename source/{logic => logic.old}/order.py (100%) rename source/{logic => logic.old}/packages.py (100%) rename source/logic/{checks/_type.ts => check_kinds/_abstract.ts} (77%) create mode 100644 source/logic/helpers/sqlite.ts rename source/logic/{channels/_type.ts => notification_kinds/_abstract.ts} (83%) create mode 100644 source/logic/state_repository.ts diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index 9d39880..538ec24 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -383,6 +383,443 @@ declare namespace lib_plankton.base { */ function object_merge(core: Record, mantle: Record): Record; } +declare namespace lib_plankton.call { + /** + * @desc hacked class for postfix function application + * @author fenris + */ + class class_valuewrapper { + /** + * @author fenris + */ + protected value: type_value; + /** + * @desc [constructor] + * @author fenris + */ + constructor(value: type_value); + /** + * @desc [accessor] applies a function and returns a new valuewrapper + * @author fenris + */ + pass(function_: (value: type_value) => type_value_): class_valuewrapper; + /** + * @desc [accessor] gives the wrapped value + * @author fenris + */ + extract(): type_value; + } + /** + * @desc shortcut for constructing a valuewrapper-object + * @author fenris + */ + function vw(value: type_value): class_valuewrapper; + /** + * @author fenris + */ + function use(input: type_input, function_: (input: type_input) => type_output): type_output; + /** + * @desc just the identity; useful for some callbacks etc. + * @author fenris + */ + function id(x: type_value): type_value; + /** + * @desc composes two functions (i.e. returns a function that return the result of the successive execution of both input-functions) + * @param {function} function_f + * @param {function} function_g + * @author fenris + */ + function compose(function_f: (type_x: any) => type_y, function_g: (type_y: any) => type_z): (value: type_x) => type_z; + /** + * @desc transforms a function with sequential input into a function with leveled input; example: add(2,3) = curryfy(add)(2)(3) + * @param {function} f + * @param {int} n (don't set manually) + * @return {function} the currified version of the in put function + * @author fenris + */ + function curryfy(f: Function, n?: int): Function; +} +declare namespace lib_plankton.call { + /** + * @author fenris + */ + type type_executor = ((resolve: (result?: type_result) => any, reject?: (reason?: type_reason) => void) => void); + /** + * @author fenris + */ + function executor_resolve(result: type_result): type_executor; + /** + * @author fenris + */ + function executor_reject(reason: type_reason): type_executor; + /** + * @author fenris + */ + function executor_transform(executor: type_executor, transform_result: (result_from: type_result_from) => type_result_to, transform_reason: (error_from: type_error_from) => type_error_to): type_executor; + /** + * @author fenris + */ + function executor_transform_default(executor: type_executor, transform_result: (result_from: type_result_from) => type_result_to, wrap_string?: string): type_executor; + /** + * @author fenris + */ + function executor_compose_sequential(first: type_executor, second: (result: type_result_first) => type_executor): type_executor; + /** + * @author fenris + */ + function executor_chain(state: type_state, executors: Array<(state: type_state) => type_executor>): type_executor; + /** + * @author fenris + */ + function executor_first(executors: Array>): type_executor>; + /** + * @author fenris + */ + function executor_condense(executors: Array>): type_executor, Error>; + /** + * @author fenris + * @deprecated use condense + */ + function executor_filter(executors: Array>, predicate: (element: type_element) => boolean): type_executor, Error>; + /** + * @author fenris + * @deprecated use condense + */ + function executor_map(executors: Array>, transformator: (element1: type_element1) => type_element2): type_executor, Error>; + /** + * @author fenris + * @deprecated use condense + */ + function executor_reduce(executors: Array>, initial: type_result, accumulator: (result: type_result, element: type_element) => type_result): type_executor; +} +declare namespace lib_plankton.call { + /** + * @author fenris + */ + type type_promise = Promise; + /** + * @author fenris + */ + function promise_reject(reason: type_reason): type_promise; + /** + * @author fenris + */ + function promise_resolve(result: type_result): type_promise; + /** + * @author fenris + */ + function promise_make(executor: (resolve: (result?: type_result) => void, reject: (reason?: type_reason) => void) => void): type_promise; + /** + * @author fenris + */ + function promise_then_close(promise: type_promise, resolver: (result: type_result) => void, rejector: (reason: type_reason) => void): void; + /** + * @author fenris + */ + function promise_then_append(promise: type_promise, resolver: (result: type_result) => type_promise, rejector?: (reason: type_reason) => type_promise): type_promise; + /** + * @author fenris + */ + function promise_all(promises: Array>): type_promise, type_reason>; + /** + * @author fenris + */ + function promise_chain(promises: Array<(input: type_result) => type_promise>, start?: type_result): type_promise; + /** + * @author fenris + */ + function promise_condense(promises: Array<() => type_promise>): type_promise, type_reason>; + /** + * @author fenris + */ + function promise_group(promises: { + [name: string]: () => type_promise; + }, serial?: boolean): type_promise<{ + [name: string]: any; + }, type_reason>; + /** + * @author fenris + */ + function promise_wrap(promise: type_promise, transformator_result: (reason: type_result_inner) => type_result_outer, transformator_reason?: (reason: type_reason) => type_reason): type_promise; + /** + * @author fenris + */ + function promise_show(label: string): (result: type_result) => type_promise; + /** + * @author fenris + */ + function promise_log(result: type_result): (result: type_result) => type_promise; + /** + * @author fenris + */ + function promise_attach(state: { + [name: string]: any; + }, promise: type_promise, name: string): type_promise<{ + [name: string]: any; + }, type_reason>; + /** + * @author fenris + */ + function promise_delay(promise: type_promise, delay: int): type_promise; + /** + * @author fenris + */ + function promise_to_executor(promise: type_promise): type_executor; +} +declare namespace lib_plankton.call { + /** + * @author fenris + */ + type type_initializer_state = int; + const initializer_state_initial: type_initializer_state; + const initializer_state_waiting: type_initializer_state; + const initializer_state_successful: type_initializer_state; + const initializer_state_failed: type_initializer_state; + /** + * @author fenris + */ + type type_initializer = { + fetcher: () => type_promise; + state?: type_initializer_state; + queue: Array<{ + resolve: (result?: type_result) => void; + reject: (reason?: type_reason) => void; + }>; + result?: type_result; + reason?: type_reason; + }; + /** + * @author fenris + */ + function initializer_make(fetcher: () => type_promise): type_initializer; + /** + * @author fenris + */ + function initializer_reset(subject: type_initializer): void; + /** + * @author fenris + */ + function initializer_state(subject: type_initializer): type_initializer_state; + /** + * @author fenris + */ + function initializer_get(subject: type_initializer): type_promise; +} +declare namespace lib_plankton.call { + /** + * @author fenris + */ + type type_deferral = { + representation: (input: type_input) => Promise; + }; + /** + * @author fenris + * @desc activates the deferral and handles its output according to a given procedure + * @param {(value : type_value)=>void} procedure a function which receives the output of the deferral as argument + */ + function deferral_use(deferral: type_deferral, input: type_input, procedure: (output: type_output) => void): void; + /** + * @author fenris + * @desc creates a deferral-subject (similar to "new Promise", where "convey" reflects "resolve"/"reject") + */ + function deferral_make(handler: (input: type_input, convey: (output: type_output) => void) => void): type_deferral; + /** + * @author fenris + * @desc wraps a simple function into a deferral (similar to "Promise.resolve"/"Promise.reject") + */ + function deferral_wrap(function_: (input: type_input) => type_output): type_deferral; + /** + * @author fenris + */ + function deferral_id(): type_deferral; + /** + * @author fenris + */ + function deferral_const(value: type_value): type_deferral; + /** + * @author fenris + */ + function deferral_delay(output: type_output, delay: int): type_deferral; + /** + * @author fenris + * @desc connects two deferrals to form a new one; the output of the first is taken as input for the second + * (similar to "Promise.then" when passing a function which returns a new promise) + * @param {type_deferral} first a simple deferral + * @param {(value1 : type_value1)=>type_deferral} second a function depending from a value returning a deferral + */ + function deferral_compose_serial(first: type_deferral, second: type_deferral): type_deferral; + /** + * @author fenris + */ + function deferral_compose_parallel({ "left": deferral_left, "right": deferral_right, }: { + left: type_deferral; + right: type_deferral; + }): type_deferral; + /** + * @author fenris + * @desc repeatedly applied serial composition + */ + function deferral_chain(members: Array>): type_deferral; + /** + * @author fenris + */ +} +declare namespace lib_plankton.call { + /** + * @author fenris + */ + class class_deferral { + /** + * @author fenris + */ + private subject; + /** + * @author fenris + */ + private constructor(); + /** + * @author fenris + */ + private static _cram; + /** + * @author fenris + */ + private static _tear; + /** + * @author fenris + */ + static make(handler: (input: type_input, convey: (value: type_output) => void) => void): class_deferral; + /** + * @author fenris + */ + use(input: type_input, procedure: (value: type_output) => void): void; + /** + * @author fenris + */ + compose_serial(second: class_deferral): class_deferral; + /** + * @author fenris + */ + static chain(members: Array>): class_deferral; + /** + * @author fenris + */ + static wrap(function_: (input: type_input) => type_output): class_deferral; + /** + * @author fenris + */ + static const_(value: type_value): class_deferral; + /** + * @author fenris + */ + static delay(output: type_output, delay: int): class_deferral; + } +} +declare namespace lib_plankton.call { + /** + * @author fenris + */ + function convey(value: any, functions: Array): any; + /** + * @author fenris + */ + function timeout(function_: () => void, delay: int): int; + /** + * @desc a definition for a value being "defined" + * @author neuc + */ + function is_def(obj: type_value, null_is_valid?: boolean): boolean; + /** + * @desc returns the value if set and, when a type is specified, if the type is correct, if not return default_value + * @author neuc + */ + function def_val(value: any, default_value: any, type?: string, null_is_valid?: boolean): any; + /** + * @desc just the empty function; useful for some callbacks etc. + * @author fenris + */ + function nothing(): void; + /** + * @desc outputs + * @author fenris + */ + /** + * @desc converts the "arguments"-map into an array + * @param {Object} args + * @author fenris + */ + function args2list(args: any): Array; + /** + * @desc provides the call for an attribute of a class as a regular function + * @param {string} name the name of the attribute + * @return {*} + * @author fenris + */ + function attribute(name: string): (object: type_object) => type_attribute; + /** + * @desc provides a method of a class as a regular function + * @param {string} name the name of the method + * @return {function} + * @author fenris + */ + function method(name: string): (object: type_object) => type_output; + /** + * @author fenris + */ + type type_unival = { + kind: string; + data?: any; + }; + /** + * @author fenris + */ + function distinguish(unival: type_unival, handlers: { + [kind: string]: (data?: any) => any; + }, fallback?: (unival?: type_unival) => any): any; + /** + * Promise version of "setTimeout" + * + * @author fenris + */ + function defer(seconds: int, action: (() => type_result)): Promise; + /** + * for rate_limit_check + * + * @author fenris + */ + type type_mana_snapshot = { + timestamp: float; + value: float; + }; + /** + * rate limiting algorithm, based on the idea of mana (magic power) in video games: + * - an actor has a fixed mana capacity, i.e. the maximum amount of available power + * - an actor has a fixed rate of mana regeneration, i.e. how fast the power is filled up (linear growth) + * - an action has a defined mana heft, i.e. how much power is required and deducted in order to execute it + * - mana states are represented by snapshots, i.e. the amount of power at a certain point in time + * + * @author fenris + */ + function rate_limit_check(setup: { + capacity: float; + regeneration_rate: float; + get_snapshot: (() => Promise<(null | type_mana_snapshot)>); + set_snapshot: ((snapshot: type_mana_snapshot) => Promise); + update_snapshot: ((timestamp: float, value_increment: float) => Promise); + }, heft: float): Promise<{ + granted: boolean; + seconds: (null | float); + }>; +} +declare namespace lib_plankton.sha256 { + /** + * @author fenris + */ + function get(value: string, secret?: string): string; +} declare namespace lib_plankton.log { /** */ @@ -1037,433 +1474,6 @@ declare namespace lib_plankton.object { */ function copy(object: Object): Object; } -declare namespace lib_plankton.call { - /** - * @desc hacked class for postfix function application - * @author fenris - */ - class class_valuewrapper { - /** - * @author fenris - */ - protected value: type_value; - /** - * @desc [constructor] - * @author fenris - */ - constructor(value: type_value); - /** - * @desc [accessor] applies a function and returns a new valuewrapper - * @author fenris - */ - pass(function_: (value: type_value) => type_value_): class_valuewrapper; - /** - * @desc [accessor] gives the wrapped value - * @author fenris - */ - extract(): type_value; - } - /** - * @desc shortcut for constructing a valuewrapper-object - * @author fenris - */ - function vw(value: type_value): class_valuewrapper; - /** - * @author fenris - */ - function use(input: type_input, function_: (input: type_input) => type_output): type_output; - /** - * @desc just the identity; useful for some callbacks etc. - * @author fenris - */ - function id(x: type_value): type_value; - /** - * @desc composes two functions (i.e. returns a function that return the result of the successive execution of both input-functions) - * @param {function} function_f - * @param {function} function_g - * @author fenris - */ - function compose(function_f: (type_x: any) => type_y, function_g: (type_y: any) => type_z): (value: type_x) => type_z; - /** - * @desc transforms a function with sequential input into a function with leveled input; example: add(2,3) = curryfy(add)(2)(3) - * @param {function} f - * @param {int} n (don't set manually) - * @return {function} the currified version of the in put function - * @author fenris - */ - function curryfy(f: Function, n?: int): Function; -} -declare namespace lib_plankton.call { - /** - * @author fenris - */ - type type_executor = ((resolve: (result?: type_result) => any, reject?: (reason?: type_reason) => void) => void); - /** - * @author fenris - */ - function executor_resolve(result: type_result): type_executor; - /** - * @author fenris - */ - function executor_reject(reason: type_reason): type_executor; - /** - * @author fenris - */ - function executor_transform(executor: type_executor, transform_result: (result_from: type_result_from) => type_result_to, transform_reason: (error_from: type_error_from) => type_error_to): type_executor; - /** - * @author fenris - */ - function executor_transform_default(executor: type_executor, transform_result: (result_from: type_result_from) => type_result_to, wrap_string?: string): type_executor; - /** - * @author fenris - */ - function executor_compose_sequential(first: type_executor, second: (result: type_result_first) => type_executor): type_executor; - /** - * @author fenris - */ - function executor_chain(state: type_state, executors: Array<(state: type_state) => type_executor>): type_executor; - /** - * @author fenris - */ - function executor_first(executors: Array>): type_executor>; - /** - * @author fenris - */ - function executor_condense(executors: Array>): type_executor, Error>; - /** - * @author fenris - * @deprecated use condense - */ - function executor_filter(executors: Array>, predicate: (element: type_element) => boolean): type_executor, Error>; - /** - * @author fenris - * @deprecated use condense - */ - function executor_map(executors: Array>, transformator: (element1: type_element1) => type_element2): type_executor, Error>; - /** - * @author fenris - * @deprecated use condense - */ - function executor_reduce(executors: Array>, initial: type_result, accumulator: (result: type_result, element: type_element) => type_result): type_executor; -} -declare namespace lib_plankton.call { - /** - * @author fenris - */ - type type_promise = Promise; - /** - * @author fenris - */ - function promise_reject(reason: type_reason): type_promise; - /** - * @author fenris - */ - function promise_resolve(result: type_result): type_promise; - /** - * @author fenris - */ - function promise_make(executor: (resolve: (result?: type_result) => void, reject: (reason?: type_reason) => void) => void): type_promise; - /** - * @author fenris - */ - function promise_then_close(promise: type_promise, resolver: (result: type_result) => void, rejector: (reason: type_reason) => void): void; - /** - * @author fenris - */ - function promise_then_append(promise: type_promise, resolver: (result: type_result) => type_promise, rejector?: (reason: type_reason) => type_promise): type_promise; - /** - * @author fenris - */ - function promise_all(promises: Array>): type_promise, type_reason>; - /** - * @author fenris - */ - function promise_chain(promises: Array<(input: type_result) => type_promise>, start?: type_result): type_promise; - /** - * @author fenris - */ - function promise_condense(promises: Array<() => type_promise>): type_promise, type_reason>; - /** - * @author fenris - */ - function promise_group(promises: { - [name: string]: () => type_promise; - }, serial?: boolean): type_promise<{ - [name: string]: any; - }, type_reason>; - /** - * @author fenris - */ - function promise_wrap(promise: type_promise, transformator_result: (reason: type_result_inner) => type_result_outer, transformator_reason?: (reason: type_reason) => type_reason): type_promise; - /** - * @author fenris - */ - function promise_show(label: string): (result: type_result) => type_promise; - /** - * @author fenris - */ - function promise_log(result: type_result): (result: type_result) => type_promise; - /** - * @author fenris - */ - function promise_attach(state: { - [name: string]: any; - }, promise: type_promise, name: string): type_promise<{ - [name: string]: any; - }, type_reason>; - /** - * @author fenris - */ - function promise_delay(promise: type_promise, delay: int): type_promise; - /** - * @author fenris - */ - function promise_to_executor(promise: type_promise): type_executor; -} -declare namespace lib_plankton.call { - /** - * @author fenris - */ - type type_initializer_state = int; - const initializer_state_initial: type_initializer_state; - const initializer_state_waiting: type_initializer_state; - const initializer_state_successful: type_initializer_state; - const initializer_state_failed: type_initializer_state; - /** - * @author fenris - */ - type type_initializer = { - fetcher: () => type_promise; - state?: type_initializer_state; - queue: Array<{ - resolve: (result?: type_result) => void; - reject: (reason?: type_reason) => void; - }>; - result?: type_result; - reason?: type_reason; - }; - /** - * @author fenris - */ - function initializer_make(fetcher: () => type_promise): type_initializer; - /** - * @author fenris - */ - function initializer_reset(subject: type_initializer): void; - /** - * @author fenris - */ - function initializer_state(subject: type_initializer): type_initializer_state; - /** - * @author fenris - */ - function initializer_get(subject: type_initializer): type_promise; -} -declare namespace lib_plankton.call { - /** - * @author fenris - */ - type type_deferral = { - representation: (input: type_input) => Promise; - }; - /** - * @author fenris - * @desc activates the deferral and handles its output according to a given procedure - * @param {(value : type_value)=>void} procedure a function which receives the output of the deferral as argument - */ - function deferral_use(deferral: type_deferral, input: type_input, procedure: (output: type_output) => void): void; - /** - * @author fenris - * @desc creates a deferral-subject (similar to "new Promise", where "convey" reflects "resolve"/"reject") - */ - function deferral_make(handler: (input: type_input, convey: (output: type_output) => void) => void): type_deferral; - /** - * @author fenris - * @desc wraps a simple function into a deferral (similar to "Promise.resolve"/"Promise.reject") - */ - function deferral_wrap(function_: (input: type_input) => type_output): type_deferral; - /** - * @author fenris - */ - function deferral_id(): type_deferral; - /** - * @author fenris - */ - function deferral_const(value: type_value): type_deferral; - /** - * @author fenris - */ - function deferral_delay(output: type_output, delay: int): type_deferral; - /** - * @author fenris - * @desc connects two deferrals to form a new one; the output of the first is taken as input for the second - * (similar to "Promise.then" when passing a function which returns a new promise) - * @param {type_deferral} first a simple deferral - * @param {(value1 : type_value1)=>type_deferral} second a function depending from a value returning a deferral - */ - function deferral_compose_serial(first: type_deferral, second: type_deferral): type_deferral; - /** - * @author fenris - */ - function deferral_compose_parallel({ "left": deferral_left, "right": deferral_right, }: { - left: type_deferral; - right: type_deferral; - }): type_deferral; - /** - * @author fenris - * @desc repeatedly applied serial composition - */ - function deferral_chain(members: Array>): type_deferral; - /** - * @author fenris - */ -} -declare namespace lib_plankton.call { - /** - * @author fenris - */ - class class_deferral { - /** - * @author fenris - */ - private subject; - /** - * @author fenris - */ - private constructor(); - /** - * @author fenris - */ - private static _cram; - /** - * @author fenris - */ - private static _tear; - /** - * @author fenris - */ - static make(handler: (input: type_input, convey: (value: type_output) => void) => void): class_deferral; - /** - * @author fenris - */ - use(input: type_input, procedure: (value: type_output) => void): void; - /** - * @author fenris - */ - compose_serial(second: class_deferral): class_deferral; - /** - * @author fenris - */ - static chain(members: Array>): class_deferral; - /** - * @author fenris - */ - static wrap(function_: (input: type_input) => type_output): class_deferral; - /** - * @author fenris - */ - static const_(value: type_value): class_deferral; - /** - * @author fenris - */ - static delay(output: type_output, delay: int): class_deferral; - } -} -declare namespace lib_plankton.call { - /** - * @author fenris - */ - function timeout(function_: () => void, delay: int): int; - /** - * @desc a definition for a value being "defined" - * @author neuc - */ - function is_def(obj: type_value, null_is_valid?: boolean): boolean; - /** - * @desc returns the value if set and, when a type is specified, if the type is correct, if not return default_value - * @author neuc - */ - function def_val(value: any, default_value: any, type?: string, null_is_valid?: boolean): any; - /** - * @desc just the empty function; useful for some callbacks etc. - * @author fenris - */ - function nothing(): void; - /** - * @desc outputs - * @author fenris - */ - /** - * @desc converts the "arguments"-map into an array - * @param {Object} args - * @author fenris - */ - function args2list(args: any): Array; - /** - * @desc provides the call for an attribute of a class as a regular function - * @param {string} name the name of the attribute - * @return {*} - * @author fenris - */ - function attribute(name: string): (object: type_object) => type_attribute; - /** - * @desc provides a method of a class as a regular function - * @param {string} name the name of the method - * @return {function} - * @author fenris - */ - function method(name: string): (object: type_object) => type_output; - /** - * @author fenris - */ - type type_unival = { - kind: string; - data?: any; - }; - /** - * @author fenris - */ - function distinguish(unival: type_unival, handlers: { - [kind: string]: (data?: any) => any; - }, fallback?: (unival?: type_unival) => any): any; - /** - * Promise version of "setTimeout" - * - * @author fenris - */ - function defer(seconds: int, action: (() => type_result)): Promise; - /** - * for rate_limit_check - * - * @author fenris - */ - type type_mana_snapshot = { - timestamp: float; - value: float; - }; - /** - * rate limiting algorithm, based on the idea of mana (magic power) in video games: - * - an actor has a fixed mana capacity, i.e. the maximum amount of available power - * - an actor has a fixed rate of mana regeneration, i.e. how fast the power is filled up (linear growth) - * - an action has a defined mana heft, i.e. how much power is required and deducted in order to execute it - * - mana states are represented by snapshots, i.e. the amount of power at a certain point in time - * - * @author fenris - */ - function rate_limit_check(setup: { - capacity: float; - regeneration_rate: float; - get_snapshot: (() => Promise<(null | type_mana_snapshot)>); - set_snapshot: ((snapshot: type_mana_snapshot) => Promise); - update_snapshot: ((timestamp: float, value_increment: float) => Promise); - }, heft: float): Promise<{ - granted: boolean; - seconds: (null | float); - }>; -} declare namespace lib_plankton.translate { /** * @author fenris diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 1120f34..4926f55 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -689,6 +689,1145 @@ var lib_plankton; base.object_merge = object_merge; })(base = lib_plankton.base || (lib_plankton.base = {})); })(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:call«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:call« 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:call« 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:call«. If not, see . + */ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +/* +This file is part of »bacterio-plankton:call«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:call« 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:call« 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:call«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var call; + (function (call) { + /** + * @desc hacked class for postfix function application + * @author fenris + */ + class class_valuewrapper { + /** + * @desc [constructor] + * @author fenris + */ + constructor(value) { + this.value = value; + } + /** + * @desc [accessor] applies a function and returns a new valuewrapper + * @author fenris + */ + pass(function_) { + return (new class_valuewrapper(function_(this.value))); + } + /** + * @desc [accessor] gives the wrapped value + * @author fenris + */ + extract() { + return this.value; + } + } + call.class_valuewrapper = class_valuewrapper; + /** + * @desc shortcut for constructing a valuewrapper-object + * @author fenris + */ + function vw(value) { + return (new class_valuewrapper(value)); + } + call.vw = vw; + /** + * @author fenris + */ + function use(input, function_) { + return function_(input); + } + call.use = use; + /** + * @desc just the identity; useful for some callbacks etc. + * @author fenris + */ + function id(x) { + return x; + } + call.id = id; + /** + * @desc composes two functions (i.e. returns a function that return the result of the successive execution of both input-functions) + * @param {function} function_f + * @param {function} function_g + * @author fenris + */ + function compose(function_f, function_g) { + return (function (x) { + // return function_g(function_f(x)); + return function_g(function_f.apply(function_f, call.args2list(arguments))); + }); + } + call.compose = compose; + /** + * @desc transforms a function with sequential input into a function with leveled input; example: add(2,3) = curryfy(add)(2)(3) + * @param {function} f + * @param {int} n (don't set manually) + * @return {function} the currified version of the in put function + * @author fenris + */ + function curryfy(f, n = f.length) { + switch (n) { + case 0: { + throw (new Error("[curryfy] impossible")); + // break; + } + case 1: { + return f; + // break; + } + default: { + return (function (x) { + return (curryfy(function () { return f.apply(f, [x].concat(call.args2list(arguments))); }, n - 1)); + }); + // break; + } + } + } + call.curryfy = curryfy; + })(call = lib_plankton.call || (lib_plankton.call = {})); +})(lib_plankton || (lib_plankton = {})); +var lib_plankton; +(function (lib_plankton) { + var call; + (function (call) { + /** + * @author fenris + */ + function executor_resolve(result) { + return ((resolve, reject) => resolve(result)); + } + call.executor_resolve = executor_resolve; + /** + * @author fenris + */ + function executor_reject(reason) { + return ((resolve, reject) => reject(reason)); + } + call.executor_reject = executor_reject; + /** + * @author fenris + */ + function executor_transform(executor, transform_result, transform_reason) { + return ((resolve, reject) => { + executor(result => resolve(transform_result(result)), reason => reject(transform_reason(reason))); + }); + } + call.executor_transform = executor_transform; + /** + * @author fenris + */ + function executor_transform_default(executor, transform_result, wrap_string = null) { + let transform_reason = (error => ((wrap_string == null) ? error : new class_error(wrap_string, [error]))); + return (executor_transform(executor, transform_result, transform_reason)); + } + call.executor_transform_default = executor_transform_default; + /** + * @author fenris + */ + function executor_compose_sequential(first, second) { + return ((resolve, reject) => { + first(result => { + second(result)(resolve, reject); + }, reason => { + reject(reason); + }); + }); + } + call.executor_compose_sequential = executor_compose_sequential; + /** + * @author fenris + */ + function executor_chain(state, executors) { + return ((resolve, reject) => { + if (executors.length == 0) { + return resolve(state); + } + else { + return executors[0](state)(result => { + executor_chain(result, executors.slice(1))(resolve, reject); + }, reject); + } + }); + /* + */ + /* + if (executors.length == 0) { + return executor_resolve(state); + } + else if (executors.length == 1) { + return executors[0](state); + } + else { + return ( + executor_chain( + state, + [ + state => (resolve, reject) => executors[0](state)(result => executors[1](result)(resolve, reject), reject) + ].concat(executors.slice(2)) + ) + ); + } + */ + /* + return ( + executors.reduce( + (chain, current) => executor_compose_sequential(chain, current, deferred), + executor_resolve(state) + ) + ); + */ + } + call.executor_chain = executor_chain; + /** + * @author fenris + */ + function executor_first(executors) { + /* + return ( + (resolve, reject) => { + if (executors.length == 0) { + reject(new Error("all failed")); + } + else { + executors[0]( + result => { + resolve(result); + }, + reason => { + executor_first(executors.slice(1))(resolve, reject); + } + ) + } + } + ); + */ + return ((resolve, reject) => { + executor_chain([], executors.map(executor => reasons => (resolve_, reject_) => { + executor(result => reject_(result), reason => resolve_(reasons.concat([reason]))); + }))(errors => reject(errors), result => resolve(result)); + }); + } + call.executor_first = executor_first; + /** + * @author fenris + */ + function executor_condense(executors) { + return (executor_chain([], executors.map(executor => result => (resolve, reject) => { + executor(element => resolve(result.concat([element])), reject); + }))); + } + call.executor_condense = executor_condense; + /** + * @author fenris + * @deprecated use condense + */ + function executor_filter(executors, predicate) { + return (executor_chain([], executors.map(executor => result => (resolve, reject) => { + executor(element => resolve(predicate(element) ? result.concat([element]) : result), reject); + }))); + } + call.executor_filter = executor_filter; + /** + * @author fenris + * @deprecated use condense + */ + function executor_map(executors, transformator) { + return (executor_chain([], executors.map(executor => result => (resolve, reject) => { + executor(element1 => resolve(result.concat([transformator(element1)])), reject); + }))); + } + call.executor_map = executor_map; + /** + * @author fenris + * @deprecated use condense + */ + function executor_reduce(executors, initial, accumulator) { + return (executor_chain(initial, executors.map(executor => result => (resolve, reject) => { + executor(element => resolve(accumulator(result, element)), reject); + }))); + } + call.executor_reduce = executor_reduce; + })(call = lib_plankton.call || (lib_plankton.call = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:call«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:call« 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:call« 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:call«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var call; + (function (call) { + /** + * @author fenris + */ + function promise_reject(reason) { + return Promise.reject(reason); + } + call.promise_reject = promise_reject; + /** + * @author fenris + */ + function promise_resolve(result) { + return Promise.resolve(result); + } + call.promise_resolve = promise_resolve; + /** + * @author fenris + */ + function promise_make(executor) { + return (new Promise(executor)); + } + call.promise_make = promise_make; + /** + * @author fenris + */ + function promise_then_close(promise, resolver, rejector) { + promise.then(resolver, rejector); + } + call.promise_then_close = promise_then_close; + /** + * @author fenris + */ + function promise_then_append(promise, resolver, rejector = null) { + if (rejector == null) { + rejector = (reason) => promise_reject(reason); + } + return (promise.then(resolver, rejector)); + } + call.promise_then_append = promise_then_append; + /** + * @author fenris + */ + function promise_all(promises) { + return Promise.all(promises); + } + call.promise_all = promise_all; + /** + * @author fenris + */ + function promise_chain(promises, start = undefined) { + return (promises.reduce((chain, promise) => promise_then_append(chain, promise), promise_resolve(start))); + } + call.promise_chain = promise_chain; + /** + * @author fenris + */ + function promise_condense(promises) { + return (promise_chain(promises.map(promise => result => promise_then_append(promise(), element => promise_resolve(result.concat([element])))), [])); + } + call.promise_condense = promise_condense; + /** + * @author fenris + */ + function promise_group(promises, serial = false) { + const decorate = function (promise, name) { + return (() => promise_then_append(promise(), value => promise_resolve({ "key": name, "value": value }))); + }; + const convert = function (array) { + let object = {}; + array.forEach(({ "key": key, "value": value }) => { object[key] = value; }); + return object; + }; + if (serial) { + return (promise_then_append(promise_condense(Object.keys(promises) + .map(name => decorate(promises[name], name))), list => promise_resolve(convert(list)))); + } + else { + return (promise_then_append(promise_all(Object.keys(promises) + .map(name => decorate(promises[name], name)) + .map(promise => promise())), list => promise_resolve(convert(list)))); + } + } + call.promise_group = promise_group; + /** + * @author fenris + */ + function promise_wrap(promise, transformator_result, transformator_reason = lib_plankton.call.id) { + return (promise_make((resolve, reject) => { + promise_then_close(promise, result => resolve(transformator_result(result)), reason => reject(transformator_reason(reason))); + })); + } + call.promise_wrap = promise_wrap; + /** + * @author fenris + */ + function promise_show(label) { + return (result => promise_make((resolve, reject) => { + // lib_plankton.log.info(label + ": " + instance_show(result)); + process.stdout.write(label + ": " + instance_show(result)); + resolve(result); + })); + } + call.promise_show = promise_show; + /** + * @author fenris + */ + function promise_log(result) { + return promise_show("log"); + } + call.promise_log = promise_log; + /** + * @author fenris + */ + function promise_attach(state, promise, name) { + return (promise_wrap(promise, result => { + state[name] = result; + return state; + })); + } + call.promise_attach = promise_attach; + /** + * @author fenris + */ + function promise_delay(promise, delay) { + return promise_make((resolve, reject) => { + call.timeout(() => { + promise_then_close(promise, resolve, reject); + return null; + }, delay); + }); + } + call.promise_delay = promise_delay; + /** + * @author fenris + */ + function promise_to_executor(promise) { + return ((resolve, reject) => promise.then(resolve, reject)); + } + call.promise_to_executor = promise_to_executor; + })(call = lib_plankton.call || (lib_plankton.call = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:call«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:call« 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:call« 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:call«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var call; + (function (call) { + call.initializer_state_initial = 0; + call.initializer_state_waiting = 1; + call.initializer_state_successful = 2; + call.initializer_state_failed = 3; + /** + * @author fenris + */ + function initializer_make(fetcher) { + let subject = { + "fetcher": fetcher, + "state": call.initializer_state_initial, + "queue": [], + "result": undefined, + "reason": undefined, + }; + return subject; + } + call.initializer_make = initializer_make; + /** + * @author fenris + */ + function initializer_actuate(subject) { + switch (subject.state) { + case call.initializer_state_successful: { + subject.queue.forEach(entry => entry.resolve(subject.result)); + break; + } + case call.initializer_state_failed: { + subject.queue.forEach(entry => entry.reject(subject.reason)); + break; + } + default: { + let message = `unhandled state ${subject.state}`; + throw (new Error(message)); + break; + } + } + } + /** + * @author fenris + */ + function initializer_reset(subject) { + subject.state = call.initializer_state_initial; + subject.queue = []; + } + call.initializer_reset = initializer_reset; + /** + * @author fenris + */ + function initializer_state(subject) { + return subject.state; + } + call.initializer_state = initializer_state; + /** + * @author fenris + */ + function initializer_get(subject) { + switch (subject.state) { + case call.initializer_state_initial: { + subject.state = call.initializer_state_waiting; + return (call.promise_make((resolve, reject) => { + subject.queue.push({ "resolve": resolve, "reject": reject }); + subject.fetcher().then(result => { + subject.state = call.initializer_state_successful; + subject.result = result; + initializer_actuate(subject); + }, reason => { + subject.state = call.initializer_state_failed; + subject.reason = reason; + initializer_actuate(subject); + }); + })); + break; + } + case call.initializer_state_waiting: { + return (call.promise_make((resolve, reject) => { + subject.queue.push({ "resolve": resolve, "reject": reject }); + })); + break; + } + case call.initializer_state_successful: { + return (call.promise_resolve(subject.result)); + break; + } + case call.initializer_state_failed: { + return (call.promise_reject(subject.reason)); + break; + } + default: { + let message = `unhandled state ${subject.state}`; + throw (new Error(message)); + break; + } + } + } + call.initializer_get = initializer_get; + /** + * @author fenris + */ + function initializer_get_sync(subject) { + switch (subject.state) { + case call.initializer_state_successful: { + return subject.result; + break; + } + case call.initializer_state_failed: { + throw subject.reason; + break; + } + default: { + let message = `unhandled state ${subject.state}`; + throw (new Error(message)); + break; + } + } + } + /** + * @author fenris + */ + function initializer_set_sync(subject, result) { + switch (subject.state) { + case call.initializer_state_successful: { + subject.result = result; + break; + } + case call.initializer_state_failed: { + subject.state = call.initializer_state_successful; + subject.result = result; + break; + } + default: { + let message = `unhandled state ${subject.state}`; + throw (new Error(message)); + break; + } + } + } + })(call = lib_plankton.call || (lib_plankton.call = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:call«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:call« 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:call« 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:call«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var call; + (function (call) { + /* + The core idea of this library is to provide means for asynchronous program flow. The old-school way to do is, + is to use callbacks. While this approach is simple and easy to understand, it has some disadvantages. As an + attempt to relief and improve this, the promise-system was introduced. In principle it solves most of the + problems found in the callback-approach; however it has some downsides as well: + + - Convolution of multiple principles + Promises unite the ideas of asynchronous program flow and error handling. + + - Instant execution + Creating a promise results in the instant execution of the given executor prodecure. While this might be + convenient in some cases, it can be quite disturbing and counter-intuitive in others. + + - Broken typing + The Promise system doesn't distinguish between an appending "then" (i.e. passing a function, which returns a + new promise) and a closing "then" (i.e. passing a function, which has no return value). On top of that it + allows returning simple values in an appending "then", which results in an implicit call of the executors + "resolve"-function. The price for these "pragmatic" features is that the whole system can't be typed well. + And even though JavaScript is not a strictly typed language, it was a quite questionable decision to design + the promise system in a way, which breaks typing from the start. + + The deferral-system forseeks to solve these issues while retaining the advantages of the promise-system. + */ + /** + * @author fenris + * @desc activates the deferral and handles its output according to a given procedure + * @param {(value : type_value)=>void} procedure a function which receives the output of the deferral as argument + */ + function deferral_use(deferral, input, procedure) { + deferral.representation(input).then(value => { + procedure(value); + }, reason => { + throw reason; + }); + } + call.deferral_use = deferral_use; + /** + * @author fenris + * @desc creates a deferral-subject (similar to "new Promise", where "convey" reflects "resolve"/"reject") + */ + function deferral_make(handler) { + return ({ + "representation": ((input) => (new Promise((resolve, reject) => { + handler(input, resolve); + }))) + }); + } + call.deferral_make = deferral_make; + /** + * @author fenris + * @desc wraps a simple function into a deferral (similar to "Promise.resolve"/"Promise.reject") + */ + function deferral_wrap(function_) { + return (deferral_make((input, convey) => convey(function_(input)))); + } + call.deferral_wrap = deferral_wrap; + /** + * @author fenris + */ + function deferral_id() { + return (deferral_make((input, convey) => convey(input))); + } + call.deferral_id = deferral_id; + /** + * @author fenris + */ + function deferral_const(value) { + return (deferral_make((input, convey) => convey(value))); + } + call.deferral_const = deferral_const; + /** + * @author fenris + */ + function deferral_delay(output, delay) { + return (deferral_make((input, convey) => { + setTimeout(() => convey(output), delay); + })); + } + call.deferral_delay = deferral_delay; + /** + * @author fenris + * @desc connects two deferrals to form a new one; the output of the first is taken as input for the second + * (similar to "Promise.then" when passing a function which returns a new promise) + * @param {type_deferral} first a simple deferral + * @param {(value1 : type_value1)=>type_deferral} second a function depending from a value returning a deferral + */ + function deferral_compose_serial(first, second) { + return { + "representation": ((input) => first.representation(input).then((between) => second.representation(between))) + }; + } + call.deferral_compose_serial = deferral_compose_serial; + /** + * @author fenris + */ + function deferral_compose_parallel({ "left": deferral_left, "right": deferral_right, }) { + return (deferral_make((input, convey) => { + let object = { + "left": lib_maybe.make_nothing(), + "right": lib_maybe.make_nothing(), + }; + let finish = function () { + if (lib_maybe.is_just(object.left) + && + lib_maybe.is_just(object.right)) { + let result = { + "left": lib_maybe.cull(object.left), + "right": lib_maybe.cull(object.right), + }; + convey(result); + } + else { + // do nothing + } + }; + deferral_use(deferral_left, input, output_left => { + object.left = lib_maybe.make_just(output_left); + finish(); + }); + deferral_use(deferral_right, input, output_right => { + object.right = lib_maybe.make_just(output_right); + finish(); + }); + })); + } + call.deferral_compose_parallel = deferral_compose_parallel; + /** + * @author fenris + * @desc repeatedly applied serial composition + */ + function deferral_chain(members) { + return (members.reduce( + // (result, current) => deferral_compose_serial(result, current), + deferral_compose_serial, deferral_id())); + } + call.deferral_chain = deferral_chain; + /** + * @author fenris + */ + /* + export function deferral_bunch( + members : {[name : string] : type_deferral} + ) : type_deferral { + + } + */ + })(call = lib_plankton.call || (lib_plankton.call = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:call«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:call« 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:call« 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:call«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var call; + (function (call) { + /** + * @author fenris + */ + class class_deferral { + /** + * @author fenris + */ + constructor(subject) { + this.subject = subject; + } + /** + * @author fenris + */ + static _cram(subject) { + return (new class_deferral(subject)); + } + /** + * @author fenris + */ + static _tear(instance) { + return instance.subject; + } + /** + * @author fenris + */ + static make(handler) { + return (class_deferral._cram(call.deferral_make(handler))); + } + /** + * @author fenris + */ + use(input, procedure) { + return (call.deferral_use(class_deferral._tear(this), input, procedure)); + } + /** + * @author fenris + */ + compose_serial(second) { + return (class_deferral._cram(call.deferral_compose_serial(class_deferral._tear(this), class_deferral._tear(second)))); + } + /** + * @author fenris + */ + static chain(members) { + return (class_deferral._cram(call.deferral_chain(members.map(member => class_deferral._tear(member))))); + } + /** + * @author fenris + */ + static wrap(function_) { + return (class_deferral._cram(call.deferral_wrap(function_))); + } + /** + * @author fenris + */ + static const_(value) { + return (class_deferral._cram(call.deferral_const(value))); + } + /** + * @author fenris + */ + static delay(output, delay) { + return (class_deferral._cram(call.deferral_delay(output, delay))); + } + } + call.class_deferral = class_deferral; + })(call = lib_plankton.call || (lib_plankton.call = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:call«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:call« 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:call« 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:call«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var call; + (function (call) { + /** + * @author fenris + */ + function convey(value, functions) { + let result = value; + functions.forEach(function_ => { + result = function_(result); + }); + return result; + } + call.convey = convey; + /** + * @author fenris + */ + function timeout(function_, delay) { + return ( + /*window.*/ setTimeout(function_, delay)); + } + call.timeout = timeout; + /** + * @desc a definition for a value being "defined" + * @author neuc + */ + function is_def(obj, null_is_valid = false) { + return (!((typeof (obj) === "undefined") + || + (!null_is_valid && (obj === null)))); + } + call.is_def = is_def; + /** + * @desc returns the value if set and, when a type is specified, if the type is correct, if not return default_value + * @author neuc + */ + function def_val(value, default_value, type = null, null_is_valid = false) { + if (is_def(value, null_is_valid) + && + (is_def(type) + ? ((typeof value === type) + || + ((value === null) + && + null_is_valid)) + : true)) { + return value; + } + else { + return default_value; + } + } + call.def_val = def_val; + ; + /** + * @desc just the empty function; useful for some callbacks etc. + * @author fenris + */ + function nothing() { + } + call.nothing = nothing; + /** + * @desc outputs + * @author fenris + */ + /* + export function output(...args : Array) : void { + lib_plankton.log.info.apply(lib_log, args); + } + */ + /** + * @desc converts the "arguments"-map into an array + * @param {Object} args + * @author fenris + */ + function args2list(args) { + return Object.keys(args).map(key => args[key]); + } + call.args2list = args2list; + /** + * @desc provides the call for an attribute of a class as a regular function + * @param {string} name the name of the attribute + * @return {*} + * @author fenris + */ + function attribute(name) { + return ((object) => object[name]); + } + call.attribute = attribute; + /** + * @desc provides a method of a class as a regular function + * @param {string} name the name of the method + * @return {function} + * @author fenris + */ + function method(name) { + return (function (object) { return object[name].apply(object, args2list(arguments).slice(1)); }); + } + call.method = method; + /** + * @author fenris + */ + function distinguish(unival, handlers, fallback = null) { + if (unival.kind in handlers) { + let handler = handlers[unival.kind]; + return handler(unival.data); + } + else { + let message = ("unhandled kind '" + unival.kind + "'"); + if (fallback !== null) { + console.warn(message); + return fallback(unival); + } + else { + throw (new Error(message)); + } + } + } + call.distinguish = distinguish; + /** + * Promise version of "setTimeout" + * + * @author fenris + */ + function defer(seconds, action) { + return (new Promise((resolve, reject) => { + setTimeout(() => resolve(action()), seconds); + })); + } + call.defer = defer; + /** + * rate limiting algorithm, based on the idea of mana (magic power) in video games: + * - an actor has a fixed mana capacity, i.e. the maximum amount of available power + * - an actor has a fixed rate of mana regeneration, i.e. how fast the power is filled up (linear growth) + * - an action has a defined mana heft, i.e. how much power is required and deducted in order to execute it + * - mana states are represented by snapshots, i.e. the amount of power at a certain point in time + * + * @author fenris + */ + function rate_limit_check(setup, heft) { + return __awaiter(this, void 0, void 0, function* () { + if (heft > setup.capacity) { + return Promise.resolve({ + "granted": false, + "seconds": null, + }); + } + else { + // get current value + const current_timestamp = (Date.now() / 1000); + const old_snapshot_raw = (yield setup.get_snapshot()); + const old_snapshot = (old_snapshot_raw !== null && old_snapshot_raw !== void 0 ? old_snapshot_raw : { "timestamp": current_timestamp, "value": setup.capacity }); + const seconds_passed = (current_timestamp - old_snapshot.timestamp); + const current_value = Math.min(setup.capacity, (old_snapshot.value + + + (setup.regeneration_rate + * + seconds_passed))); + // analyze + if (current_value < heft) { + // too less + const seconds_needed = ((setup.regeneration_rate <= 0) + ? null + : ((heft - old_snapshot.value) / setup.regeneration_rate)); + return Promise.resolve({ + "granted": false, + "seconds": ((seconds_needed === null) ? null : (seconds_needed - seconds_passed)), + }); + } + else { + // enough -> update snapshot + const new_value = (current_value - heft); + // set_snapshot + if (old_snapshot_raw === null) { + yield setup.set_snapshot({ "timestamp": current_timestamp, "value": new_value }); + } + else { + yield setup.update_snapshot(current_timestamp, (new_value - old_snapshot.value)); + } + return Promise.resolve({ + "granted": true, + "seconds": 0, + }); + } + } + }); + } + call.rate_limit_check = rate_limit_check; + })(call = lib_plankton.call || (lib_plankton.call = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:sha256«. + +Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:sha256« 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:sha256« 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:sha256«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var sha256; + (function (sha256) { + /** + * @author fenris + */ + function get(value, secret = "") { + const nm_crypto = require("crypto"); + const sha256Hasher = nm_crypto.createHmac("sha256", secret); + const hash = sha256Hasher.update(value).digest("hex"); + return hash; + } + sha256.get = get; + })(sha256 = lib_plankton.sha256 || (lib_plankton.sha256 = {})); +})(lib_plankton || (lib_plankton = {})); var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || @@ -3196,1099 +4335,6 @@ var lib_plankton; })(object = lib_plankton.object || (lib_plankton.object = {})); })(lib_plankton || (lib_plankton = {})); /* -This file is part of »bacterio-plankton:call«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:call« 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:call« 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:call«. If not, see . - */ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -/* -This file is part of »bacterio-plankton:call«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:call« 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:call« 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:call«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var call; - (function (call) { - /** - * @desc hacked class for postfix function application - * @author fenris - */ - class class_valuewrapper { - /** - * @desc [constructor] - * @author fenris - */ - constructor(value) { - this.value = value; - } - /** - * @desc [accessor] applies a function and returns a new valuewrapper - * @author fenris - */ - pass(function_) { - return (new class_valuewrapper(function_(this.value))); - } - /** - * @desc [accessor] gives the wrapped value - * @author fenris - */ - extract() { - return this.value; - } - } - call.class_valuewrapper = class_valuewrapper; - /** - * @desc shortcut for constructing a valuewrapper-object - * @author fenris - */ - function vw(value) { - return (new class_valuewrapper(value)); - } - call.vw = vw; - /** - * @author fenris - */ - function use(input, function_) { - return function_(input); - } - call.use = use; - /** - * @desc just the identity; useful for some callbacks etc. - * @author fenris - */ - function id(x) { - return x; - } - call.id = id; - /** - * @desc composes two functions (i.e. returns a function that return the result of the successive execution of both input-functions) - * @param {function} function_f - * @param {function} function_g - * @author fenris - */ - function compose(function_f, function_g) { - return (function (x) { - // return function_g(function_f(x)); - return function_g(function_f.apply(function_f, call.args2list(arguments))); - }); - } - call.compose = compose; - /** - * @desc transforms a function with sequential input into a function with leveled input; example: add(2,3) = curryfy(add)(2)(3) - * @param {function} f - * @param {int} n (don't set manually) - * @return {function} the currified version of the in put function - * @author fenris - */ - function curryfy(f, n = f.length) { - switch (n) { - case 0: { - throw (new Error("[curryfy] impossible")); - // break; - } - case 1: { - return f; - // break; - } - default: { - return (function (x) { - return (curryfy(function () { return f.apply(f, [x].concat(call.args2list(arguments))); }, n - 1)); - }); - // break; - } - } - } - call.curryfy = curryfy; - })(call = lib_plankton.call || (lib_plankton.call = {})); -})(lib_plankton || (lib_plankton = {})); -var lib_plankton; -(function (lib_plankton) { - var call; - (function (call) { - /** - * @author fenris - */ - function executor_resolve(result) { - return ((resolve, reject) => resolve(result)); - } - call.executor_resolve = executor_resolve; - /** - * @author fenris - */ - function executor_reject(reason) { - return ((resolve, reject) => reject(reason)); - } - call.executor_reject = executor_reject; - /** - * @author fenris - */ - function executor_transform(executor, transform_result, transform_reason) { - return ((resolve, reject) => { - executor(result => resolve(transform_result(result)), reason => reject(transform_reason(reason))); - }); - } - call.executor_transform = executor_transform; - /** - * @author fenris - */ - function executor_transform_default(executor, transform_result, wrap_string = null) { - let transform_reason = (error => ((wrap_string == null) ? error : new class_error(wrap_string, [error]))); - return (executor_transform(executor, transform_result, transform_reason)); - } - call.executor_transform_default = executor_transform_default; - /** - * @author fenris - */ - function executor_compose_sequential(first, second) { - return ((resolve, reject) => { - first(result => { - second(result)(resolve, reject); - }, reason => { - reject(reason); - }); - }); - } - call.executor_compose_sequential = executor_compose_sequential; - /** - * @author fenris - */ - function executor_chain(state, executors) { - return ((resolve, reject) => { - if (executors.length == 0) { - return resolve(state); - } - else { - return executors[0](state)(result => { - executor_chain(result, executors.slice(1))(resolve, reject); - }, reject); - } - }); - /* - */ - /* - if (executors.length == 0) { - return executor_resolve(state); - } - else if (executors.length == 1) { - return executors[0](state); - } - else { - return ( - executor_chain( - state, - [ - state => (resolve, reject) => executors[0](state)(result => executors[1](result)(resolve, reject), reject) - ].concat(executors.slice(2)) - ) - ); - } - */ - /* - return ( - executors.reduce( - (chain, current) => executor_compose_sequential(chain, current, deferred), - executor_resolve(state) - ) - ); - */ - } - call.executor_chain = executor_chain; - /** - * @author fenris - */ - function executor_first(executors) { - /* - return ( - (resolve, reject) => { - if (executors.length == 0) { - reject(new Error("all failed")); - } - else { - executors[0]( - result => { - resolve(result); - }, - reason => { - executor_first(executors.slice(1))(resolve, reject); - } - ) - } - } - ); - */ - return ((resolve, reject) => { - executor_chain([], executors.map(executor => reasons => (resolve_, reject_) => { - executor(result => reject_(result), reason => resolve_(reasons.concat([reason]))); - }))(errors => reject(errors), result => resolve(result)); - }); - } - call.executor_first = executor_first; - /** - * @author fenris - */ - function executor_condense(executors) { - return (executor_chain([], executors.map(executor => result => (resolve, reject) => { - executor(element => resolve(result.concat([element])), reject); - }))); - } - call.executor_condense = executor_condense; - /** - * @author fenris - * @deprecated use condense - */ - function executor_filter(executors, predicate) { - return (executor_chain([], executors.map(executor => result => (resolve, reject) => { - executor(element => resolve(predicate(element) ? result.concat([element]) : result), reject); - }))); - } - call.executor_filter = executor_filter; - /** - * @author fenris - * @deprecated use condense - */ - function executor_map(executors, transformator) { - return (executor_chain([], executors.map(executor => result => (resolve, reject) => { - executor(element1 => resolve(result.concat([transformator(element1)])), reject); - }))); - } - call.executor_map = executor_map; - /** - * @author fenris - * @deprecated use condense - */ - function executor_reduce(executors, initial, accumulator) { - return (executor_chain(initial, executors.map(executor => result => (resolve, reject) => { - executor(element => resolve(accumulator(result, element)), reject); - }))); - } - call.executor_reduce = executor_reduce; - })(call = lib_plankton.call || (lib_plankton.call = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:call«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:call« 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:call« 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:call«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var call; - (function (call) { - /** - * @author fenris - */ - function promise_reject(reason) { - return Promise.reject(reason); - } - call.promise_reject = promise_reject; - /** - * @author fenris - */ - function promise_resolve(result) { - return Promise.resolve(result); - } - call.promise_resolve = promise_resolve; - /** - * @author fenris - */ - function promise_make(executor) { - return (new Promise(executor)); - } - call.promise_make = promise_make; - /** - * @author fenris - */ - function promise_then_close(promise, resolver, rejector) { - promise.then(resolver, rejector); - } - call.promise_then_close = promise_then_close; - /** - * @author fenris - */ - function promise_then_append(promise, resolver, rejector = null) { - if (rejector == null) { - rejector = (reason) => promise_reject(reason); - } - return (promise.then(resolver, rejector)); - } - call.promise_then_append = promise_then_append; - /** - * @author fenris - */ - function promise_all(promises) { - return Promise.all(promises); - } - call.promise_all = promise_all; - /** - * @author fenris - */ - function promise_chain(promises, start = undefined) { - return (promises.reduce((chain, promise) => promise_then_append(chain, promise), promise_resolve(start))); - } - call.promise_chain = promise_chain; - /** - * @author fenris - */ - function promise_condense(promises) { - return (promise_chain(promises.map(promise => result => promise_then_append(promise(), element => promise_resolve(result.concat([element])))), [])); - } - call.promise_condense = promise_condense; - /** - * @author fenris - */ - function promise_group(promises, serial = false) { - const decorate = function (promise, name) { - return (() => promise_then_append(promise(), value => promise_resolve({ "key": name, "value": value }))); - }; - const convert = function (array) { - let object = {}; - array.forEach(({ "key": key, "value": value }) => { object[key] = value; }); - return object; - }; - if (serial) { - return (promise_then_append(promise_condense(Object.keys(promises) - .map(name => decorate(promises[name], name))), list => promise_resolve(convert(list)))); - } - else { - return (promise_then_append(promise_all(Object.keys(promises) - .map(name => decorate(promises[name], name)) - .map(promise => promise())), list => promise_resolve(convert(list)))); - } - } - call.promise_group = promise_group; - /** - * @author fenris - */ - function promise_wrap(promise, transformator_result, transformator_reason = lib_plankton.call.id) { - return (promise_make((resolve, reject) => { - promise_then_close(promise, result => resolve(transformator_result(result)), reason => reject(transformator_reason(reason))); - })); - } - call.promise_wrap = promise_wrap; - /** - * @author fenris - */ - function promise_show(label) { - return (result => promise_make((resolve, reject) => { - // lib_plankton.log.info(label + ": " + instance_show(result)); - process.stdout.write(label + ": " + instance_show(result)); - resolve(result); - })); - } - call.promise_show = promise_show; - /** - * @author fenris - */ - function promise_log(result) { - return promise_show("log"); - } - call.promise_log = promise_log; - /** - * @author fenris - */ - function promise_attach(state, promise, name) { - return (promise_wrap(promise, result => { - state[name] = result; - return state; - })); - } - call.promise_attach = promise_attach; - /** - * @author fenris - */ - function promise_delay(promise, delay) { - return promise_make((resolve, reject) => { - call.timeout(() => { - promise_then_close(promise, resolve, reject); - return null; - }, delay); - }); - } - call.promise_delay = promise_delay; - /** - * @author fenris - */ - function promise_to_executor(promise) { - return ((resolve, reject) => promise.then(resolve, reject)); - } - call.promise_to_executor = promise_to_executor; - })(call = lib_plankton.call || (lib_plankton.call = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:call«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:call« 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:call« 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:call«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var call; - (function (call) { - call.initializer_state_initial = 0; - call.initializer_state_waiting = 1; - call.initializer_state_successful = 2; - call.initializer_state_failed = 3; - /** - * @author fenris - */ - function initializer_make(fetcher) { - let subject = { - "fetcher": fetcher, - "state": call.initializer_state_initial, - "queue": [], - "result": undefined, - "reason": undefined, - }; - return subject; - } - call.initializer_make = initializer_make; - /** - * @author fenris - */ - function initializer_actuate(subject) { - switch (subject.state) { - case call.initializer_state_successful: { - subject.queue.forEach(entry => entry.resolve(subject.result)); - break; - } - case call.initializer_state_failed: { - subject.queue.forEach(entry => entry.reject(subject.reason)); - break; - } - default: { - let message = `unhandled state ${subject.state}`; - throw (new Error(message)); - break; - } - } - } - /** - * @author fenris - */ - function initializer_reset(subject) { - subject.state = call.initializer_state_initial; - subject.queue = []; - } - call.initializer_reset = initializer_reset; - /** - * @author fenris - */ - function initializer_state(subject) { - return subject.state; - } - call.initializer_state = initializer_state; - /** - * @author fenris - */ - function initializer_get(subject) { - switch (subject.state) { - case call.initializer_state_initial: { - subject.state = call.initializer_state_waiting; - return (call.promise_make((resolve, reject) => { - subject.queue.push({ "resolve": resolve, "reject": reject }); - subject.fetcher().then(result => { - subject.state = call.initializer_state_successful; - subject.result = result; - initializer_actuate(subject); - }, reason => { - subject.state = call.initializer_state_failed; - subject.reason = reason; - initializer_actuate(subject); - }); - })); - break; - } - case call.initializer_state_waiting: { - return (call.promise_make((resolve, reject) => { - subject.queue.push({ "resolve": resolve, "reject": reject }); - })); - break; - } - case call.initializer_state_successful: { - return (call.promise_resolve(subject.result)); - break; - } - case call.initializer_state_failed: { - return (call.promise_reject(subject.reason)); - break; - } - default: { - let message = `unhandled state ${subject.state}`; - throw (new Error(message)); - break; - } - } - } - call.initializer_get = initializer_get; - /** - * @author fenris - */ - function initializer_get_sync(subject) { - switch (subject.state) { - case call.initializer_state_successful: { - return subject.result; - break; - } - case call.initializer_state_failed: { - throw subject.reason; - break; - } - default: { - let message = `unhandled state ${subject.state}`; - throw (new Error(message)); - break; - } - } - } - /** - * @author fenris - */ - function initializer_set_sync(subject, result) { - switch (subject.state) { - case call.initializer_state_successful: { - subject.result = result; - break; - } - case call.initializer_state_failed: { - subject.state = call.initializer_state_successful; - subject.result = result; - break; - } - default: { - let message = `unhandled state ${subject.state}`; - throw (new Error(message)); - break; - } - } - } - })(call = lib_plankton.call || (lib_plankton.call = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:call«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:call« 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:call« 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:call«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var call; - (function (call) { - /* - The core idea of this library is to provide means for asynchronous program flow. The old-school way to do is, - is to use callbacks. While this approach is simple and easy to understand, it has some disadvantages. As an - attempt to relief and improve this, the promise-system was introduced. In principle it solves most of the - problems found in the callback-approach; however it has some downsides as well: - - - Convolution of multiple principles - Promises unite the ideas of asynchronous program flow and error handling. - - - Instant execution - Creating a promise results in the instant execution of the given executor prodecure. While this might be - convenient in some cases, it can be quite disturbing and counter-intuitive in others. - - - Broken typing - The Promise system doesn't distinguish between an appending "then" (i.e. passing a function, which returns a - new promise) and a closing "then" (i.e. passing a function, which has no return value). On top of that it - allows returning simple values in an appending "then", which results in an implicit call of the executors - "resolve"-function. The price for these "pragmatic" features is that the whole system can't be typed well. - And even though JavaScript is not a strictly typed language, it was a quite questionable decision to design - the promise system in a way, which breaks typing from the start. - - The deferral-system forseeks to solve these issues while retaining the advantages of the promise-system. - */ - /** - * @author fenris - * @desc activates the deferral and handles its output according to a given procedure - * @param {(value : type_value)=>void} procedure a function which receives the output of the deferral as argument - */ - function deferral_use(deferral, input, procedure) { - deferral.representation(input).then(value => { - procedure(value); - }, reason => { - throw reason; - }); - } - call.deferral_use = deferral_use; - /** - * @author fenris - * @desc creates a deferral-subject (similar to "new Promise", where "convey" reflects "resolve"/"reject") - */ - function deferral_make(handler) { - return ({ - "representation": ((input) => (new Promise((resolve, reject) => { - handler(input, resolve); - }))) - }); - } - call.deferral_make = deferral_make; - /** - * @author fenris - * @desc wraps a simple function into a deferral (similar to "Promise.resolve"/"Promise.reject") - */ - function deferral_wrap(function_) { - return (deferral_make((input, convey) => convey(function_(input)))); - } - call.deferral_wrap = deferral_wrap; - /** - * @author fenris - */ - function deferral_id() { - return (deferral_make((input, convey) => convey(input))); - } - call.deferral_id = deferral_id; - /** - * @author fenris - */ - function deferral_const(value) { - return (deferral_make((input, convey) => convey(value))); - } - call.deferral_const = deferral_const; - /** - * @author fenris - */ - function deferral_delay(output, delay) { - return (deferral_make((input, convey) => { - setTimeout(() => convey(output), delay); - })); - } - call.deferral_delay = deferral_delay; - /** - * @author fenris - * @desc connects two deferrals to form a new one; the output of the first is taken as input for the second - * (similar to "Promise.then" when passing a function which returns a new promise) - * @param {type_deferral} first a simple deferral - * @param {(value1 : type_value1)=>type_deferral} second a function depending from a value returning a deferral - */ - function deferral_compose_serial(first, second) { - return { - "representation": ((input) => first.representation(input).then((between) => second.representation(between))) - }; - } - call.deferral_compose_serial = deferral_compose_serial; - /** - * @author fenris - */ - function deferral_compose_parallel({ "left": deferral_left, "right": deferral_right, }) { - return (deferral_make((input, convey) => { - let object = { - "left": lib_maybe.make_nothing(), - "right": lib_maybe.make_nothing(), - }; - let finish = function () { - if (lib_maybe.is_just(object.left) - && - lib_maybe.is_just(object.right)) { - let result = { - "left": lib_maybe.cull(object.left), - "right": lib_maybe.cull(object.right), - }; - convey(result); - } - else { - // do nothing - } - }; - deferral_use(deferral_left, input, output_left => { - object.left = lib_maybe.make_just(output_left); - finish(); - }); - deferral_use(deferral_right, input, output_right => { - object.right = lib_maybe.make_just(output_right); - finish(); - }); - })); - } - call.deferral_compose_parallel = deferral_compose_parallel; - /** - * @author fenris - * @desc repeatedly applied serial composition - */ - function deferral_chain(members) { - return (members.reduce( - // (result, current) => deferral_compose_serial(result, current), - deferral_compose_serial, deferral_id())); - } - call.deferral_chain = deferral_chain; - /** - * @author fenris - */ - /* - export function deferral_bunch( - members : {[name : string] : type_deferral} - ) : type_deferral { - - } - */ - })(call = lib_plankton.call || (lib_plankton.call = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:call«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:call« 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:call« 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:call«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var call; - (function (call) { - /** - * @author fenris - */ - class class_deferral { - /** - * @author fenris - */ - constructor(subject) { - this.subject = subject; - } - /** - * @author fenris - */ - static _cram(subject) { - return (new class_deferral(subject)); - } - /** - * @author fenris - */ - static _tear(instance) { - return instance.subject; - } - /** - * @author fenris - */ - static make(handler) { - return (class_deferral._cram(call.deferral_make(handler))); - } - /** - * @author fenris - */ - use(input, procedure) { - return (call.deferral_use(class_deferral._tear(this), input, procedure)); - } - /** - * @author fenris - */ - compose_serial(second) { - return (class_deferral._cram(call.deferral_compose_serial(class_deferral._tear(this), class_deferral._tear(second)))); - } - /** - * @author fenris - */ - static chain(members) { - return (class_deferral._cram(call.deferral_chain(members.map(member => class_deferral._tear(member))))); - } - /** - * @author fenris - */ - static wrap(function_) { - return (class_deferral._cram(call.deferral_wrap(function_))); - } - /** - * @author fenris - */ - static const_(value) { - return (class_deferral._cram(call.deferral_const(value))); - } - /** - * @author fenris - */ - static delay(output, delay) { - return (class_deferral._cram(call.deferral_delay(output, delay))); - } - } - call.class_deferral = class_deferral; - })(call = lib_plankton.call || (lib_plankton.call = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:call«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:call« 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:call« 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:call«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var call; - (function (call) { - /** - * @author fenris - */ - function timeout(function_, delay) { - return ( - /*window.*/ setTimeout(function_, delay)); - } - call.timeout = timeout; - /** - * @desc a definition for a value being "defined" - * @author neuc - */ - function is_def(obj, null_is_valid = false) { - return (!((typeof (obj) === "undefined") - || - (!null_is_valid && (obj === null)))); - } - call.is_def = is_def; - /** - * @desc returns the value if set and, when a type is specified, if the type is correct, if not return default_value - * @author neuc - */ - function def_val(value, default_value, type = null, null_is_valid = false) { - if (is_def(value, null_is_valid) - && - (is_def(type) - ? ((typeof value === type) - || - ((value === null) - && - null_is_valid)) - : true)) { - return value; - } - else { - return default_value; - } - } - call.def_val = def_val; - ; - /** - * @desc just the empty function; useful for some callbacks etc. - * @author fenris - */ - function nothing() { - } - call.nothing = nothing; - /** - * @desc outputs - * @author fenris - */ - /* - export function output(...args : Array) : void { - lib_plankton.log.info.apply(lib_log, args); - } - */ - /** - * @desc converts the "arguments"-map into an array - * @param {Object} args - * @author fenris - */ - function args2list(args) { - return Object.keys(args).map(key => args[key]); - } - call.args2list = args2list; - /** - * @desc provides the call for an attribute of a class as a regular function - * @param {string} name the name of the attribute - * @return {*} - * @author fenris - */ - function attribute(name) { - return ((object) => object[name]); - } - call.attribute = attribute; - /** - * @desc provides a method of a class as a regular function - * @param {string} name the name of the method - * @return {function} - * @author fenris - */ - function method(name) { - return (function (object) { return object[name].apply(object, args2list(arguments).slice(1)); }); - } - call.method = method; - /** - * @author fenris - */ - function distinguish(unival, handlers, fallback = null) { - if (unival.kind in handlers) { - let handler = handlers[unival.kind]; - return handler(unival.data); - } - else { - let message = ("unhandled kind '" + unival.kind + "'"); - if (fallback !== null) { - console.warn(message); - return fallback(unival); - } - else { - throw (new Error(message)); - } - } - } - call.distinguish = distinguish; - /** - * Promise version of "setTimeout" - * - * @author fenris - */ - function defer(seconds, action) { - return (new Promise((resolve, reject) => { - setTimeout(() => resolve(action()), seconds); - })); - } - call.defer = defer; - /** - * rate limiting algorithm, based on the idea of mana (magic power) in video games: - * - an actor has a fixed mana capacity, i.e. the maximum amount of available power - * - an actor has a fixed rate of mana regeneration, i.e. how fast the power is filled up (linear growth) - * - an action has a defined mana heft, i.e. how much power is required and deducted in order to execute it - * - mana states are represented by snapshots, i.e. the amount of power at a certain point in time - * - * @author fenris - */ - function rate_limit_check(setup, heft) { - return __awaiter(this, void 0, void 0, function* () { - if (heft > setup.capacity) { - return Promise.resolve({ - "granted": false, - "seconds": null, - }); - } - else { - // get current value - const current_timestamp = (Date.now() / 1000); - const old_snapshot_raw = (yield setup.get_snapshot()); - const old_snapshot = (old_snapshot_raw !== null && old_snapshot_raw !== void 0 ? old_snapshot_raw : { "timestamp": current_timestamp, "value": setup.capacity }); - const seconds_passed = (current_timestamp - old_snapshot.timestamp); - const current_value = Math.min(setup.capacity, (old_snapshot.value - + - (setup.regeneration_rate - * - seconds_passed))); - // analyze - if (current_value < heft) { - // too less - const seconds_needed = ((setup.regeneration_rate <= 0) - ? null - : ((heft - old_snapshot.value) / setup.regeneration_rate)); - return Promise.resolve({ - "granted": false, - "seconds": ((seconds_needed === null) ? null : (seconds_needed - seconds_passed)), - }); - } - else { - // enough -> update snapshot - const new_value = (current_value - heft); - // set_snapshot - if (old_snapshot_raw === null) { - yield setup.set_snapshot({ "timestamp": current_timestamp, "value": new_value }); - } - else { - yield setup.update_snapshot(current_timestamp, (new_value - old_snapshot.value)); - } - return Promise.resolve({ - "granted": true, - "seconds": 0, - }); - } - } - }); - } - call.rate_limit_check = rate_limit_check; - })(call = lib_plankton.call || (lib_plankton.call = {})); -})(lib_plankton || (lib_plankton = {})); -/* This file is part of »bacterio-plankton:translate«. Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' diff --git a/source/logic/channels/_interface.py b/source/logic.old/channels/_interface.py similarity index 100% rename from source/logic/channels/_interface.py rename to source/logic.old/channels/_interface.py diff --git a/source/logic/channels/console.py b/source/logic.old/channels/console.py similarity index 100% rename from source/logic/channels/console.py rename to source/logic.old/channels/console.py diff --git a/source/logic/channels/email.py b/source/logic.old/channels/email.py similarity index 100% rename from source/logic/channels/email.py rename to source/logic.old/channels/email.py diff --git a/source/logic/channels/libnotify.py b/source/logic.old/channels/libnotify.py similarity index 100% rename from source/logic/channels/libnotify.py rename to source/logic.old/channels/libnotify.py diff --git a/source/logic/checks/_interface.py b/source/logic.old/check_kinds/_interface.py similarity index 100% rename from source/logic/checks/_interface.py rename to source/logic.old/check_kinds/_interface.py diff --git a/source/logic/checks/file_state.py b/source/logic.old/check_kinds/file_state.py similarity index 100% rename from source/logic/checks/file_state.py rename to source/logic.old/check_kinds/file_state.py diff --git a/source/logic/checks/generic_remote.py b/source/logic.old/check_kinds/generic_remote.py similarity index 100% rename from source/logic/checks/generic_remote.py rename to source/logic.old/check_kinds/generic_remote.py diff --git a/source/logic/checks/http_request.py b/source/logic.old/check_kinds/http_request.py similarity index 100% rename from source/logic/checks/http_request.py rename to source/logic.old/check_kinds/http_request.py diff --git a/source/logic/checks/script.py b/source/logic.old/check_kinds/script.py similarity index 100% rename from source/logic/checks/script.py rename to source/logic.old/check_kinds/script.py diff --git a/source/logic/checks/tls_certificate.py b/source/logic.old/check_kinds/tls_certificate.py similarity index 100% rename from source/logic/checks/tls_certificate.py rename to source/logic.old/check_kinds/tls_certificate.py diff --git a/source/logic/condition.py b/source/logic.old/condition.py similarity index 100% rename from source/logic/condition.py rename to source/logic.old/condition.py diff --git a/source/logic/lib.py b/source/logic.old/lib.py similarity index 100% rename from source/logic/lib.py rename to source/logic.old/lib.py diff --git a/source/logic/localization.py b/source/logic.old/localization.py similarity index 100% rename from source/logic/localization.py rename to source/logic.old/localization.py diff --git a/source/logic/main.py b/source/logic.old/main.py similarity index 100% rename from source/logic/main.py rename to source/logic.old/main.py diff --git a/source/logic/order.py b/source/logic.old/order.py similarity index 100% rename from source/logic/order.py rename to source/logic.old/order.py diff --git a/source/logic/packages.py b/source/logic.old/packages.py similarity index 100% rename from source/logic/packages.py rename to source/logic.old/packages.py diff --git a/source/logic/checks/_type.ts b/source/logic/check_kinds/_abstract.ts similarity index 77% rename from source/logic/checks/_type.ts rename to source/logic/check_kinds/_abstract.ts index b6c85aa..4d125c6 100644 --- a/source/logic/checks/_type.ts +++ b/source/logic/check_kinds/_abstract.ts @@ -1,9 +1,9 @@ -namespace _heimdall.checks +namespace _heimdall.check_kinds { /** */ - export type type_check = { + export type type_check_kind = { parameters_schema : (() => _heimdall.helpers.json_schema.type_schema); normalize_order_node : ((node : any) => any); run : (parameters) => Promise<{condition : _heimdall.enum_condition; info : any;}>; diff --git a/source/logic/helpers/json_schema.ts b/source/logic/helpers/json_schema.ts index eb00171..49b40b2 100644 --- a/source/logic/helpers/json_schema.ts +++ b/source/logic/helpers/json_schema.ts @@ -38,7 +38,9 @@ namespace _heimdall.helpers.json_schema description ?: string; default ?: any; minimum ?: int; + exclusiveMinimum ?: int; maximum ?: int; + exclusiveMaximum ?: int; enum ?: Array; items ?: type_schema; anyOf ?: Array; diff --git a/source/logic/helpers/sqlite.ts b/source/logic/helpers/sqlite.ts new file mode 100644 index 0000000..09f4229 --- /dev/null +++ b/source/logic/helpers/sqlite.ts @@ -0,0 +1,25 @@ +namespace _heimdall.helpers.sqlite +{ + + /** + */ + export function query_put( + database_path : string, + query_template : string, + query_arguments : Record + ) : Promise + { + } + + + /** + */ + export function query_set( + database_path : string, + query_template : string, + query_arguments : Record + ) : Promise + { + } + +} diff --git a/source/logic/main.ts b/source/logic/main.ts index 441dd35..758f0b9 100644 --- a/source/logic/main.ts +++ b/source/logic/main.ts @@ -209,16 +209,16 @@ async function main( process.stdout.write(version + "\n"); } else { - const check_kind_implementations : Record = { + const check_kind_implementations : Record = { }; - const channel_kind_implementations : Record = { + const notification_kind_implementations : Record = { }; if (args.show_schema) { process.stdout.write( lib_plankton.json.encode( _heimdall.order.schema_root( check_kind_implementations, - channel_kind_implementations + notification_kind_implementations ), true ) @@ -227,7 +227,96 @@ async function main( ) } else { - process.stdout.write(JSON.stringify(args, undefined, "\t") + "\n"); + 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"], + } + ) + ); + } + 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_path.exists(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"], ""); + + order.checks.forEach( + check => { + if (! check.active) { + // do nothing + } + else { + process.stdout.write(JSON.stringify(order, undefined, "\t") + "\n"); + } + } + ); + + // drop mutex file + await lib_plankton.file.delete(args["mutex_path"]); + } + } + } } } } diff --git a/source/logic/channels/_type.ts b/source/logic/notification_kinds/_abstract.ts similarity index 83% rename from source/logic/channels/_type.ts rename to source/logic/notification_kinds/_abstract.ts index 27b3583..03859b3 100644 --- a/source/logic/channels/_type.ts +++ b/source/logic/notification_kinds/_abstract.ts @@ -1,9 +1,9 @@ -namespace _heimdall.channels +namespace _heimdall.notification_kinds { /** */ - export type type_channel = { + export type type_notification_kind = { parameters_schema : (() => _heimdall.helpers.json_schema.type_schema); normalize_order_node : ((node : any) => any); notify : (parameters, name, data, state, info) => Promise; diff --git a/source/logic/order.ts b/source/logic/order.ts index 79b6c10..b69c0c5 100644 --- a/source/logic/order.ts +++ b/source/logic/order.ts @@ -1,6 +1,55 @@ namespace _heimdall.order { + /** + * @todo + */ + type type_schedule = any; + + + /** + */ + export type type_notification = { + kind : string; + parameters : any; + }; + + + /** + */ + export type type_check_common = { + active ?: boolean; + threshold ?: int; + annoy ?: boolean; + schedule ?: type_schedule; + notifications ?: Array; + }; + + + /** + */ + export type type_check = ( + type_check_common + & + { + name : string; + title : string; + kind : string; + parameters : any; + custom : any; + } + ); + + + /** + */ + export type type_order = { + defaults : type_check_common; + includes : Array; + checks : Array; + }; + + function schema_active( ) : _heimdall.helpers.json_schema.type_schema { @@ -81,14 +130,14 @@ namespace _heimdall.order function schema_notifications( - channel_implementations : Record + notification_kind_implementations : Record ) { return { "type": "array", "items": { "anyOf": ( - Object.entries(channel_implementations) + Object.entries(notification_kind_implementations) .map( ([key, value]) => ({ "title": ("notification channel '" + key + "'"), @@ -121,8 +170,8 @@ namespace _heimdall.order export function schema_root( - check_kind_implementations : Record, - channel_implementations : Record, + check_kind_implementations : Record, + notification_kind_implementations : Record, ) { return { @@ -138,7 +187,7 @@ namespace _heimdall.order "threshold": schema_threshold(), "annoy": schema_annoy(), "schedule": schema_schedule(), - "notifications": schema_notifications(channel_implementations), + "notifications": schema_notifications(notification_kind_implementations), }, "required": [ ], @@ -170,7 +219,7 @@ namespace _heimdall.order "threshold": schema_threshold(), "annoy": schema_annoy(), "schedule": schema_schedule(), - "notifications": schema_notifications(channel_implementations), + "notifications": schema_notifications(notification_kind_implementations), }, "required": [ "name", @@ -266,24 +315,24 @@ namespace _heimdall.order function normalize_notification( - channel_implementations : Record, + notification_kind_implementations : Record, node ) { - if (! (node["kind"] in channel_implementations)) { + if (! (node["kind"] in notification_kind_implementations)) { throw new Error("invalid notification kind: " + node["kind"]); } else { return { "kind": node["kind"], - "parameters": channel_implementations[node["kind"]].normalize_order_node(node["parameters"]), + "parameters": notification_kind_implementations[node["kind"]].normalize_order_node(node["parameters"]), }; } } function normalize_defaults( - channel_implementations : Record, + notification_kind_implementations : Record, node ) { @@ -309,18 +358,23 @@ namespace _heimdall.order "schedule": node_["schedule"], "notifications": ( node_["notifications"] - .map(x => normalize_notification(channel_implementations, x)) + .map(x => normalize_notification(notification_kind_implementations, x)) ), }; } + /** + */ function normalize_check( - check_kind_implementations : Record, - channel_implementations : Record, - defaults, - node - ) + check_kind_implementations : Record, + notification_kind_implementations : Record, + defaults : type_check_common, + node : { + name : string; + kind : string; + } + ) : type_check { if (! ("name" in node)) { throw new Error("missing mandatory field in 'check' node: 'name'"); @@ -330,70 +384,68 @@ namespace _heimdall.order throw new Error("missing mandatory field in 'check' node: 'kind'"); } else { - if (! (node["kind"] in check_kind_implementations)) { - throw new Error("invalid check kind: " + node["kind"]); + if (! (node.kind in check_kind_implementations)) { + throw new Error("invalid check kind: " + node.kind); } else { - const node_ = Object.assign( + const node_ : type_check = Object.assign( Object.assign( defaults, { - "title": node["name"], + "title": node.name, "parameters": {}, "custom": null, }, ), node ); - let node__ = {}; - if (true) { - node__["name"] = node_["name"]; - } - if (true) { - node__["title"] = node_["title"]; - } + let check : type_check = { + "name": node_.name, + "title": node_.title, + "kind": node_.kind, + "parameters": check_kind_implementations[node_.kind].normalize_order_node(node_.parameters), + "custom": node_.custom, + }; if ("active" in node_) { - node__["active"] = node_["active"]; + check.active = node_["active"]; } if ("threshold" in node_) { - node__["threshold"] = node_["threshold"]; + check.threshold = node_["threshold"]; } if ("annoy" in node_) { - node__["annoy"] = node_["annoy"]; + check.annoy = node_["annoy"]; } if ("schedule" in node_) { - node__["schedule"] = normalize_schedule(node_["schedule"]); + check.schedule = normalize_schedule(node_["schedule"]); } if ("notifications" in node_) { - node__["notifications"] = ( + check.notifications = ( node_["notifications"] .map( - x => normalize_notification(channel_implementations, x), + x => normalize_notification(notification_kind_implementations, x), ) ); } - if ("kind" in node_) { - node__["kind"] = node_["kind"]; - } - if (true) { - node__["parameters"] = check_kind_implementations[node_["kind"]].normalize_order_node(node_["parameters"]); - } if ("custom" in node_) { - node__["custom"] = node_["custom"]; + check.custom = node_["custom"]; } - return node__; + return check; } } } } + /** + */ function normalize_root( - check_kind_implementations : Record, - channel_implementations : Record, + check_kind_implementations : Record, + notification_kind_implementations : Record, node, - options = {} - ) + options : { + use_implicit_default_values ?: boolean; + } = {} + ) : type_order { options = Object.assign( { @@ -401,8 +453,8 @@ namespace _heimdall.order }, options ) - let counts = {}; - let checks_raw = ( + let counts : Record = {}; + const checks_raw : Array = ( ("checks" in node) ? node["checks"] : [] @@ -415,7 +467,7 @@ namespace _heimdall.order counts[node_["name"]] += 1; } ); - let fails : Array<[string, int]> = ( + const fails : Array<[string, int]> = ( Object.entries(counts) .filter( ([key, value]) => (value > 1) @@ -432,20 +484,20 @@ namespace _heimdall.order ); } else { - let defaults_raw = ( + const defaults_raw : any = ( ("defaults" in node) ? node["defaults"] : {} ) - let defaults = ( - options["use_implicit_default_values"] + const defaults : type_check_common = ( + options.use_implicit_default_values ? normalize_defaults( - channel_implementations, + notification_kind_implementations, defaults_raw ) : defaults_raw ) - let includes = ( + const includes : Array = ( ("includes" in node) ? node["includes"] : [] @@ -458,7 +510,7 @@ namespace _heimdall.order .map( node_ => normalize_check( check_kind_implementations, - channel_implementations, + notification_kind_implementations, defaults, node_ ) @@ -470,16 +522,21 @@ namespace _heimdall.order export async function load( - check_kind_implementations : Record, - channel_implementations : Record, + check_kind_implementations : Record, + notification_kind_implementations : Record, path : string, - options = {} - ) + options : { + root ?: boolean; + already_included ?: Array; + } = {} + ) : Promise { + const nm_path = require("path"); + options = Object.assign( { "root": true, - "already_included": new Set([]), + "already_included": [], }, options ) @@ -497,16 +554,16 @@ namespace _heimdall.order let path_ = includes[index]; let sub_order = load( check_kind_implementations, - channel_implementations, + notification_kind_implementations, ( - _os.path.isabs(path_) + nm_path.isAbsolute(path_) ? path_ - : _os.path.join(_os.path.dirname(path), path_) + : nm_path.join(nm_path.dirname(path), path_) ), { "root": false, // TODO set union - "already_included": (options["already_included"] | {path}) + "already_included": options.already_included.concat([path]), } ) if (! ("checks" in order_raw)) { @@ -521,7 +578,7 @@ namespace _heimdall.order "name": lib_plankton.string.coin( "{{prefix}}.{{original_name}}", { - "prefix": _os.path.basename(path_).split(".")[0], + "prefix": nm_path.basename(path_).split(".")[0], "original_name": check["name"], } ), @@ -534,7 +591,7 @@ namespace _heimdall.order } return normalize_root( check_kind_implementations, - channel_implementations, + notification_kind_implementations, order_raw, { "use_implicit_default_values": options["root"], diff --git a/source/logic/state_repository.ts b/source/logic/state_repository.ts new file mode 100644 index 0000000..e68f6f3 --- /dev/null +++ b/source/logic/state_repository.ts @@ -0,0 +1,37 @@ +namespace _heimdall.state_repository +{ + + /** + */ + export async function setup( + database_path : string, + ) : Promise + { + const result = await _heimdall.helpers.sqlite.query_set( + database_path, + "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);", + {} + ); + } + + + /** + */ + export async function clean( + database_path : string, + time_to_live : int, + erase_state : boolean, + ) : Promise + { + const result = await _heimdall.helpers.sqlite.query_put( + database_path, + "DELETE FROM results WHERE ((timestamp < :timestamp_min) OR :erase_state);", + { + "timestamp_min": ((Date.now() / 1000) - time_to_live), + "erase_state": erase_state, + } + ); + return result.rowcount; + } + +} diff --git a/tools/heimdall.prj.json b/tools/heimdall.prj.json index 6106e61..3eac8a4 100644 --- a/tools/heimdall.prj.json +++ b/tools/heimdall.prj.json @@ -21,8 +21,10 @@ "lib/plankton/plankton.d.ts", "source/logic/condition.ts", "source/logic/helpers/json_schema.ts", - "source/logic/checks/_type.ts", - "source/logic/channels/_type.ts", + "source/logic/helpers/sqlite.ts", + "source/logic/check_kinds/_abstract.ts", + "source/logic/notification_kinds/_abstract.ts", + "source/logic/state_repository.ts", "source/logic/order.ts", "source/logic/main.ts" ], diff --git a/tools/update-plankton b/tools/update-plankton index 655223f..9ce428b 100755 --- a/tools/update-plankton +++ b/tools/update-plankton @@ -9,6 +9,8 @@ dir_plankton=${dir_lib}/plankton ## vars modules="" +modules="${modules} call" +modules="${modules} sha256" modules="${modules} string" modules="${modules} json" modules="${modules} file"