From ac1daf8a689e078e661d34496e93a2ff2ea7d868 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Sun, 27 Apr 2025 22:30:22 +0200 Subject: [PATCH] [mod] conf [del] kalender_digital [add] ical_feed --- .gitignore | 1 + ivaldi.json | 4 +- libs/plankton/plankton.d.ts | 73 +- libs/plankton/plankton.js | 243 ++++++- source/conf.ts | 633 +++++++++++++----- source/main.ts | 32 +- source/sources/_functions.ts | 6 +- .../{kalender_digital.ts => ical_feed.ts} | 27 +- 8 files changed, 810 insertions(+), 209 deletions(-) rename source/sources/{kalender_digital.ts => ical_feed.ts} (80%) diff --git a/.gitignore b/.gitignore index 82389ca..f33ae7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /build/ /temp/ /conf/ +/.geany diff --git a/ivaldi.json b/ivaldi.json index 87e1136..75d4741 100644 --- a/ivaldi.json +++ b/ivaldi.json @@ -8,7 +8,9 @@ "pit", "http", "ical", + "string", "telegram", + "url", "conf", "log", "args" @@ -18,7 +20,7 @@ ], "sources": [ "types.ts", - "sources/kalender_digital.ts", + "sources/ical_feed.ts", "sources/_functions.ts", "targets/telegram_bot.ts", "targets/_functions.ts", diff --git a/libs/plankton/plankton.d.ts b/libs/plankton/plankton.d.ts index 7c85a19..085b52d 100644 --- a/libs/plankton/plankton.d.ts +++ b/libs/plankton/plankton.d.ts @@ -650,6 +650,9 @@ declare namespace lib_plankton.call { value: (null | type_value); error: (null | any); }>; + /** + */ + export function sleep(seconds: float): Promise; export {}; } declare namespace lib_plankton.email { @@ -2262,6 +2265,57 @@ declare namespace lib_plankton.telegram { parse_mode?: (null | string); }): Promise; } +declare namespace lib_plankton.url { + /** + * @author fenris + */ + type type_url = { + scheme: (null | string); + host: (null | string); + username: (null | string); + password: (null | string); + port: (null | int); + path: (null | string); + query: (null | string); + hash: (null | string); + }; +} +declare namespace lib_plankton.url { + /** + * @author fenris + */ + function encode(url: type_url): string; + /** + * @author fenris + * @todo arguments + */ + function decode(url_raw: string): type_url; + /** + * @author fenris + */ + function implementation_code(): lib_plankton.code.type_code; +} +declare namespace lib_plankton.url { + /** + * @author fenris + */ + class class_url implements lib_plankton.code.interface_code { + /** + * @author fenris + */ + constructor(); + /** + * @implementation + * @author fenris + */ + encode(x: any): string; + /** + * @implementation + * @author fenris + */ + decode(x: string): any; + } +} declare namespace lib_plankton.file { /** * @author fenris @@ -2607,6 +2661,12 @@ declare namespace lib_plankton.conf { } | { not: type_schema; }); + /** + */ + type type_sheet = { + version: (null | string); + content: type_content; + }; /** */ type type_report = { @@ -2619,15 +2679,24 @@ declare namespace lib_plankton.conf { reports: Array; result: lib_plankton.pod.type_pod; }; + /** + */ + type type_migration = (null | { + target: string; + function: ((content: type_from) => type_to); + }); } declare namespace lib_plankton.conf { /** - * @todo versioning */ - function refine(schema: type_schema, value_raw: any): type_result; + function refine(schema: type_schema, content: any): type_result; /** + * @deprecated */ function load(schema: type_schema, path: (null | string)): Promise; + /** + */ + function load_versioned(path: string, get_schema: ((version: string) => type_schema), migrations: Record>): Promise>; } declare namespace lib_plankton.args { /** diff --git a/libs/plankton/plankton.js b/libs/plankton/plankton.js index 2431de4..95d0d95 100644 --- a/libs/plankton/plankton.js +++ b/libs/plankton/plankton.js @@ -1459,6 +1459,16 @@ var lib_plankton; }))); } call.try_catch_wrap_async = try_catch_wrap_async; + /** + */ + function sleep(seconds) { + return (new Promise((resolve, reject) => { + setTimeout(() => { + resolve(undefined); + }, Math.floor(seconds * 1000)); + })); + } + call.sleep = sleep; })(call = lib_plankton.call || (lib_plankton.call = {})); })(lib_plankton || (lib_plankton = {})); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { @@ -6254,6 +6264,202 @@ var lib_plankton; })(telegram = lib_plankton.telegram || (lib_plankton.telegram = {})); })(lib_plankton || (lib_plankton = {})); /* +This file is part of »bacterio-plankton:url«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:url« 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:url« 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:url«. If not, see . + */ +/* +This file is part of »bacterio-plankton:url«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:url« 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:url« 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:url«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var url; + (function (url_1) { + /** + * @author fenris + */ + function encode(url) { + let result = ""; + // scheme + { + if (url.scheme !== null) { + result += (url.scheme + ":"); + } + } + // host + { + if (url.host !== null) { + result += "//"; + // username + { + if (url.username !== null) { + result += url.username; + // password + { + if (url.password !== null) { + result += (":" + url.password); + } + } + result += "@"; + } + } + result += url.host; + } + } + // port + { + if (url.port !== null) { + result += (":" + url.port.toString()); + } + } + // path + { + if (url.path !== null) { + result += url.path; + } + } + // query + { + if (url.query !== null) { + result += ("?" + url.query); + } + } + // hash + { + if (url.hash !== null) { + result += ("#" + url.hash); + } + } + return result; + } + url_1.encode = encode; + /** + * @author fenris + * @todo arguments + */ + function decode(url_raw) { + const builtin_url = new URL(url_raw); + return { + "scheme": builtin_url.protocol.slice(0, -1), + "host": builtin_url.hostname, + "username": ((builtin_url.username !== "") + ? + builtin_url.username + : + null), + "password": ((builtin_url.password !== "") + ? + builtin_url.password + : + null), + "port": ((builtin_url.port !== "") + ? + parseInt(builtin_url.port) + : + null), + "path": builtin_url.pathname, + "query": builtin_url.search.slice(1), + "hash": ((builtin_url.hash !== "") + ? + builtin_url.hash.slice(1) + : + null), + }; + } + url_1.decode = decode; + /** + * @author fenris + */ + function implementation_code() { + return { + "encode": encode, + "decode": decode, + }; + } + url_1.implementation_code = implementation_code; + })(url = lib_plankton.url || (lib_plankton.url = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:url«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:url« 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:url« 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:url«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var url; + (function (url) { + /** + * @author fenris + */ + class class_url { + /** + * @author fenris + */ + constructor() { + } + /** + * @implementation + * @author fenris + */ + encode(x) { + return url.encode(x); + } + /** + * @implementation + * @author fenris + */ + decode(x) { + return url.decode(x); + } + } + url.class_url = class_url; + })(url = lib_plankton.url || (lib_plankton.url = {})); +})(lib_plankton || (lib_plankton = {})); +/* This file is part of »bacterio-plankton:file«. Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' @@ -7786,10 +7992,9 @@ var lib_plankton; } } /** - * @todo versioning */ - function refine(schema, value_raw) { - const adaption = adapt(schema, value_raw); + function refine(schema, content) { + const adaption = adapt(schema, content); if (!lib_plankton.pod.is_filled(adaption.result)) { throw (new Error("conf could not be loaded:\n" + @@ -7803,6 +8008,7 @@ var lib_plankton; } conf.refine = refine; /** + * @deprecated */ function load(schema, path) { return (((path === null) @@ -7814,6 +8020,37 @@ var lib_plankton; .then((data_raw) => Promise.resolve(refine(schema, data_raw)))); } conf.load = load; + /** + */ + async function load_versioned(path, get_schema, migrations) { + const file_content = await lib_plankton.file.read(path); + const sheet_raw = lib_plankton.json.decode(file_content); + const schema = get_schema(sheet_raw.version); + let sheet = { + "version": sheet_raw.version, + "content": refine(schema, sheet_raw.content), + }; + while (sheet.version in migrations) { + const migration = migrations[sheet.version]; + if (!(migration === null)) { + lib_plankton.log._info("plankton.conf.load.migration", { + "details": { + "from": sheet.version, + "to": migration.target, + } + }); + sheet = { + "version": migration.target, + "content": migration.function(sheet.content), + }; + } + else { + break; + } + } + return sheet; + } + conf.load_versioned = load_versioned; })(conf = lib_plankton.conf || (lib_plankton.conf = {})); })(lib_plankton || (lib_plankton = {})); /* diff --git a/source/conf.ts b/source/conf.ts index cded882..92277a0 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -26,7 +26,7 @@ namespace _munin.conf /** */ - export type type_conf = { + type type_conf_v1 = { sources : Array< ( { @@ -56,9 +56,6 @@ namespace _munin.conf } ) >; - /** - * in hours - */ frequency : float; labels : { head : string; @@ -68,179 +65,493 @@ namespace _munin.conf }; }; - + /** */ - export const schema : lib_plankton.conf.type_schema = { - "nullable": false, - "type": "object", - "properties": { - "version": { - "nullable": false, - "type": "string", - }, - "sources": { - "nullable": false, - "type": "array", - "items": { - "nullable": false, - "anyOf": [ - { - "type": "object", - "properties": { - "kind": { - "nullable": false, - "type": "string", - "enum": ["kalender_digital"] - }, - "data": { - "nullable": false, - "type": "object", - "properties": { - "path": { - "nullable": false, - "type": "string" - }, - "filtration": { - "nullable": false, - "type": "object", - "properties": { - "category_blacklist": { - "nullable": false, - "type": "array", - "items": { - "nullable": false, - "type": "string", - }, - "default": [], - }, - "title_blacklist": { - "nullable": false, - "type": "array", - "items": { - "nullable": false, - "type": "string", - }, - "default": [], - }, - }, - "additionalProperties": false, - "required": [ - ], - "default": {} - }, - }, - "additionalProperties": false, - "required": [ - "id", - ] - } - }, - "additionalProperties": false, - "required": [ - "kind", - "data", - ] - } - ] + type type_conf_v2 = { + sources : Array< + ( + { + kind : "ical_feed", + data : { + url : string; + filtration : { + category_blacklist : Array; + title_blacklist : Array; + }; + }; } + ) + >; + targets : Array< + ( + { + kind : "telegram_bot", + data : { + bot_token : string; + chat_id : int; + /** + * in hours + */ + interval : Array; + } + } + ) + >; + settings : { + poll_delay : float; + }; + labels : { + head : string; + title : string; + time : string; + location : string; + }; + }; + + + /** + */ + export type type_conf = type_conf_v2; + + + /** + */ + function convert_from_v1( + conf_v1 : type_conf_v1 + ) : type_conf_v2 + { + return { + "sources": conf_v1.sources.map( + source => { + switch (source.kind) { + case "kalender_digital": { + return { + "kind": "ical_feed", + "data": { + "url": lib_plankton.url.encode( + { + "scheme": "https", + "host": "export.kalender.digital", + "username": null, + "password": null, + "port": null, + "path": ("/ics/" + source.data.path + ".ics"), + "query": "past_months=0&future_months=1", + "hash": null, + } + ), + "filtration": source.data.filtration, + } + }; + break; + } + default: { + // return source; + throw (new Error("unhandled source kind: " + source.kind)); + break; + } + } + } + ), + "targets": conf_v1.targets, + "settings": { + "poll_delay": conf_v1.frequency, }, - "targets": { - "nullable": false, - "type": "array", - "items": { + "labels": conf_v1.labels, + }; + } + + + /** + */ + function schema_source_kalender_digital( + version : string + ) : lib_plankton.conf.type_schema + { + return { + "type": "object", + "properties": { + "kind": { "nullable": false, - "anyOf": [ - { + "type": "string", + "enum": ["kalender_digital"] + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "path": { + "nullable": false, + "type": "string" + }, + "filtration": { "nullable": false, "type": "object", "properties": { - "kind": { + "category_blacklist": { "nullable": false, - "type": "string", - "enum": ["telegram_bot"] - }, - "data": { - "nullable": false, - "type": "object", - "properties": { - "bot_token": { - "nullable": false, - "type": "string", - }, - "chat_id": { - "nullable": false, - "type": "integer", - }, - "interval": { - "nullable": false, - "type": "array", - "items": { - "nullable": false, - "type": "integer" - }, - "default": [24.0], - }, + "type": "array", + "items": { + "nullable": false, + "type": "string", }, - "additionalProperties": false, - "required": [ - "bot_token", - "chat_id", - ] - } + "default": [], + }, + "title_blacklist": { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "type": "string", + }, + "default": [], + }, }, "additionalProperties": false, "required": [ - "kind", - "data", - ] - } - ], + ], + "default": {} + }, + }, + "additionalProperties": false, + "required": [ + "path", + ] } }, - "frequency": { - "nullable": false, - "type": "number", - "default": 1.0, - }, - "labels": { - "nullable": false, - "type": "object", - "properties": { - "head": { - "nullable": false, - "type": "string", - "default": "Termin-Erinnerung" - }, - "title": { - "nullable": false, - "type": "string", - "default": "was" - }, - "time": { - "nullable": false, - "type": "string", - "default": "wann" - }, - "location": { - "nullable": false, - "type": "string", - "default": "wo" - }, + "additionalProperties": false, + "required": [ + "kind", + "data", + ] + }; + } + + + /** + */ + function schema_source_ical_feed( + version : string + ) : lib_plankton.conf.type_schema + { + return { + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["ical_feed"] }, - "additionalProperties": false, - "required": [ - ], - "default": {} + "data": { + "nullable": false, + "type": "object", + "properties": { + "url": { + "nullable": false, + "type": "string" + }, + "filtration": { + "nullable": false, + "type": "object", + "properties": { + "category_blacklist": { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "type": "string", + }, + "default": [], + }, + "title_blacklist": { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "type": "string", + }, + "default": [], + }, + }, + "additionalProperties": false, + "required": [ + ], + "default": {} + }, + }, + "additionalProperties": false, + "required": [ + "url", + ] + } }, - }, - "additionalProperties": false, - "required": [ - "version", - "sources", - "targets", - ], - }; + "additionalProperties": false, + "required": [ + "kind", + "data", + ] + }; + } + + + /** + */ + function schema_sources( + version : string + ) : lib_plankton.conf.type_schema + { + switch (version) { + case "1": { + return { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "anyOf": [ + schema_source_kalender_digital(version), + ], + } + }; + break; + } + default: + case "2": { + return { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "anyOf": [ + schema_source_ical_feed(version), + ], + } + }; + break; + } + } + } + + + /** + */ + function schema_target_telegram_bot( + version : string + ) : lib_plankton.conf.type_schema + { + return { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["telegram_bot"] + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "bot_token": { + "nullable": false, + "type": "string", + }, + "chat_id": { + "nullable": false, + "type": "integer", + }, + "interval": { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "type": "integer" + }, + "default": [24.0], + }, + }, + "additionalProperties": false, + "required": [ + "bot_token", + "chat_id", + ] + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data", + ] + }; + } + + + /** + */ + function schema_targets( + version : string + ) : lib_plankton.conf.type_schema + { + return { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "anyOf": [ + schema_target_telegram_bot(version), + ], + } + }; + } + + + /** + */ + function schema_settings( + version : string + ) : lib_plankton.conf.type_schema + { + return { + "nullable": false, + "type": "object", + "properties": { + "poll_delay": { + "nullable": false, + "type": "number", + "default": 1.0 + } + }, + "additionalProperties": false, + "required": [ + ], + "default": { + } + }; + } + + + /** + */ + function schema_labels( + version : string + ) : lib_plankton.conf.type_schema + { + return { + "nullable": false, + "type": "object", + "properties": { + "head": { + "nullable": false, + "type": "string", + "default": "Termin-Erinnerung" + }, + "title": { + "nullable": false, + "type": "string", + "default": "was" + }, + "time": { + "nullable": false, + "type": "string", + "default": "wann" + }, + "location": { + "nullable": false, + "type": "string", + "default": "wo" + }, + }, + "additionalProperties": false, + "required": [ + ], + "default": {} + }; + } + + + /** + */ + function schema( + version : string + ) : lib_plankton.conf.type_schema + { + switch (version) { + case "1": { + return { + "nullable": false, + "type": "object", + "properties": { + "sources": schema_sources(version), + "targets": schema_targets(version), + "frequency": { + "nullable": false, + "type": "number", + "default": 1.0, + }, + "labels": schema_labels(version), + }, + "additionalProperties": false, + "required": [ + "sources", + "targets", + ], + }; + break; + } + default: + case "2": { + return { + "nullable": false, + "type": "object", + "properties": { + "sources": schema_sources(version), + "targets": schema_targets(version), + "settings": schema_settings(version), + "labels": schema_labels(version), + }, + "additionalProperties": false, + "required": [ + "sources", + "targets", + ], + }; + break; + } + } + } + + + /** + */ + export async function load( + path : string + ) : Promise + { + const conf_raw : {version : string; content : any} = await lib_plankton.conf.load_versioned( + path, + schema, + { + "1": {"target": "2", "function": convert_from_v1}, + "2": null, + } + ); + + switch (conf_raw.version) { + case "1": { + const conf_v2 : type_conf_v2 = convert_from_v1(conf_raw.content); + return conf_v2; + break; + } + case "2": { + const conf_v2 : type_conf_v2 = (conf_raw.content as type_conf_v2); + return conf_v2; + break; + } + default: { + throw (new Error("invalid version: " + conf_raw.version)); + break; + } + } + } } - diff --git a/source/main.ts b/source/main.ts index e347e40..1daa642 100644 --- a/source/main.ts +++ b/source/main.ts @@ -56,7 +56,7 @@ namespace _munin ); const window_to : lib_plankton.pit.type_pit = lib_plankton.pit.shift_hour( now, - hours + (conf.frequency / 2) + hours + (conf.settings.poll_delay / 2) ); for (const event of events) { const event_begin : lib_plankton.pit.type_pit = lib_plankton.pit.from_datetime(event.begin); @@ -103,7 +103,7 @@ namespace _munin /** */ - function run( + async function run( conf : _munin.conf.type_conf, { "dry_run": dry_run = false, @@ -111,7 +111,7 @@ namespace _munin dry_run ?: boolean; } = { } - ) : void + ) : Promise { const sources : Array<_munin.type_source> = conf.sources.map( source_raw => _munin.sources.factory(source_raw) @@ -126,15 +126,10 @@ namespace _munin } } ); - run_iteration(conf, sources, targets, {"dry_run": dry_run}); - /** - * outsource setInterval logic - */ - setInterval( - () => {run_iteration(conf, sources, targets, {"dry_run": dry_run});}, - (conf.frequency * 60 * 60 * 1000) - ); - + while (true) { + await run_iteration(conf, sources, targets, {"dry_run": dry_run}); + await lib_plankton.call.sleep(conf.settings.poll_delay * 60 * 60); + } } @@ -147,14 +142,16 @@ namespace _munin // args const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler( { + /* "action": lib_plankton.args.class_argument.positional({ "index": 0, "type": lib_plankton.args.enum_type.string, "mode": lib_plankton.args.enum_mode.replace, "default": "run", - "info": "what to do : help | fetch | send | run", + "info": "what to do : help | run", "name": "action", }), + */ "conf_path": lib_plankton.args.class_argument.volatile({ "indicators_long": ["conf-path"], "indicators_short": ["c"], @@ -207,7 +204,7 @@ namespace _munin args_raw.join(" ") ); - if (args.help || (args.action === "help")) { + if (args.help) { process.stdout.write( arg_handler.generate_help( { @@ -220,10 +217,7 @@ namespace _munin } else { // init - const conf : _munin.conf.type_conf = await lib_plankton.conf.load<_munin.conf.type_conf>( - _munin.conf.schema, - args.conf_path - ); + const conf : _munin.conf.type_conf = await _munin.conf.load(args.conf_path); lib_plankton.log.set_main_logger( [ { @@ -270,7 +264,7 @@ namespace _munin "\n" ); } - switch (args.action) { + switch (/*args.action*/"run") { default: { throw (new Error("unhandled action: " + args.action)); break; diff --git a/source/sources/_functions.ts b/source/sources/_functions.ts index 6f09abd..7a144ae 100644 --- a/source/sources/_functions.ts +++ b/source/sources/_functions.ts @@ -35,9 +35,9 @@ namespace _munin.sources throw (new Error("unhandled source kind: " + description.kind)); break; } - case "kalender_digital": { - return _munin.sources.kalender_digital.implementation_source( - description.data as _munin.sources.kalender_digital.type_parameters + case "ical_feed": { + return _munin.sources.ical_feed.implementation_source( + description.data as _munin.sources.ical_feed.type_parameters ); return } diff --git a/source/sources/kalender_digital.ts b/source/sources/ical_feed.ts similarity index 80% rename from source/sources/kalender_digital.ts rename to source/sources/ical_feed.ts index 3af37ba..cb11ca1 100644 --- a/source/sources/kalender_digital.ts +++ b/source/sources/ical_feed.ts @@ -1,10 +1,10 @@ -namespace _munin.sources.kalender_digital +namespace _munin.sources.ical_feed { /** */ export type type_parameters = { - path : string; + url : string; filtration : { category_blacklist : Array; title_blacklist : Array; @@ -18,27 +18,14 @@ namespace _munin.sources.kalender_digital parameters : type_parameters ) : Promise> { + const url : lib_plankton.url.type_url = lib_plankton.url.decode(parameters.url); const http_request : lib_plankton.http.type_request = { - "scheme": "https", - "host": "export.kalender.digital", - "path": lib_plankton.string.coin( - "/ics/{{path}}.ics", - { - "path": parameters.path, - } - ), + "scheme": (url.scheme as ("http" | "https")), + "host": url.host, + "path": url.path, "version": "HTTP/2", "method": lib_plankton.http.enum_method.get, - "query": lib_plankton.string.coin( - "?past_months={{past_months}}&future_months={{future_months}}", - { - "past_months": (0).toFixed(0), - /** - * anpassen an frequency? - */ - "future_months": (1).toFixed(0), - } - ), + "query": url.query, "headers": {}, "body": null, };