Compare commits

...

5 commits

Author SHA1 Message Date
fenris 3d7ba02b78 [fix] api actions 2025-09-25 16:48:16 +02:00
fenris a08f7f3bf4 [mod] caching 2025-09-25 16:44:50 +02:00
fenris c96a0aef4a [mod] caching 2025-09-25 16:41:17 +02:00
fenris 834953b635 [mod] logging 2025-09-25 16:35:22 +02:00
fenris 43c1cda101 [sty] main 2025-09-25 16:29:29 +02:00
23 changed files with 172 additions and 94 deletions

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_calendar_add( export function register_calendar_add(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<
@ -64,7 +64,8 @@ namespace _zeitbild.api
else { else {
// TODO move logic to calendar service // TODO move logic to calendar service
let resource_object : _zeitbild.type_resource_object; let resource_object : _zeitbild.type_resource_object;
switch (stuff.input.resource.kind) { switch (stuff.input.resource.kind)
{
case "local": { case "local": {
resource_object = { resource_object = {
"kind": "local", "kind": "local",

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_calendar_change( export function register_calendar_change(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_calendar_event_add( export function register_calendar_event_add(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_calendar_event_change( export function register_calendar_event_change(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_calendar_event_get( export function register_calendar_event_get(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_calendar_event_remove( export function register_calendar_event_remove(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_calendar_get( export function register_calendar_get(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_calendar_list( export function register_calendar_list(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_calendar_remove( export function register_calendar_remove(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_events( export function register_events(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,10 +5,10 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_meta_ping( export function register_meta_ping(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
lib_plankton.rest.register< lib_plankton.rest_http.register<
null, null,
string string
> >
@ -17,7 +17,7 @@ namespace _zeitbild.api
lib_plankton.http.enum_method.get, lib_plankton.http.enum_method.get,
_zeitbild.conf.get().server.path_base + "/meta/ping", _zeitbild.conf.get().server.path_base + "/meta/ping",
{ {
"description": "sendet ein 'pong' zurück; gedacht um die Erreichbarkeit des Backends zu prüfen", "description": () => "sendet ein 'pong' zurück; gedacht um die Erreichbarkeit des Backends zu prüfen",
"input_schema": () => ({ "input_schema": () => ({
"nullable": true, "nullable": true,
}), }),
@ -25,8 +25,10 @@ namespace _zeitbild.api
"nullable": false, "nullable": false,
"type": "string", "type": "string",
}), }),
"restriction": restriction_none, "response_body_encode": () => (body) => Promise.resolve<string>(body),
"execution": () => { "response_body_mimetype": () => "text/plain",
"restriction": () => restriction_none,
"execution": () => () => {
return Promise.resolve({ return Promise.resolve({
"status_code": 200, "status_code": 200,
"data": "pong", "data": "pong",

View file

@ -5,10 +5,10 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_meta_spec( export function register_meta_spec(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
lib_plankton.rest.register< lib_plankton.rest_http.register<
null, null,
any any
> >
@ -17,17 +17,17 @@ namespace _zeitbild.api
lib_plankton.http.enum_method.get, lib_plankton.http.enum_method.get,
_zeitbild.conf.get().server.path_base + "/meta/spec", _zeitbild.conf.get().server.path_base + "/meta/spec",
{ {
"description": "gibt die API-Spezifikation im OpenAPI-Format aus", "description": () => "gibt die API-Spezifikation im OpenAPI-Format aus",
"input_schema": () => ({ "input_schema": () => ({
"nullable": true, "nullable": true,
}), }),
"output_schema": () => ({ "output_schema": () => ({
}), }),
"restriction": restriction_none, "restriction": () => restriction_none,
"execution": () => { "execution": () => () => {
return Promise.resolve({ return Promise.resolve({
"status_code": 200, "status_code": 200,
"data": lib_plankton.rest.to_oas(rest_subject), "data": lib_plankton.rest_http.to_oas(rest_subject),
}); });
}, },
} }

View file

@ -5,10 +5,10 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_session_begin( export function register_session_begin(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
lib_plankton.rest.register< lib_plankton.rest_http.register<
{ {
name : string; name : string;
password : string; password : string;
@ -23,7 +23,7 @@ namespace _zeitbild.api
lib_plankton.http.enum_method.post, lib_plankton.http.enum_method.post,
"/session/begin", "/session/begin",
{ {
"description": "führt die Anmeldung am System aus um geschützte Aktionen nutzen zu können", "description": () => "führt die Anmeldung am System aus um geschützte Aktionen nutzen zu können",
"input_schema": () => ({ "input_schema": () => ({
"type": "object", "type": "object",
"properties": { "properties": {
@ -44,8 +44,8 @@ namespace _zeitbild.api
"type": "string", "type": "string",
"description": "der Sitzungs-Schlüssel, der als Header 'X-Session-Key' gesetzt werden muss um Erlaubnis zur Ausführung geschützter Aktionen zu erhalten", "description": "der Sitzungs-Schlüssel, der als Header 'X-Session-Key' gesetzt werden muss um Erlaubnis zur Ausführung geschützter Aktionen zu erhalten",
}), }),
"restriction": restriction_none, "restriction": () => restriction_none,
"execution": async ({"input": input}) => { "execution": () => async ({"input": input}) => {
if (input === null) { if (input === null) {
return Promise.reject(new Error("impossible")); return Promise.reject(new Error("impossible"));
} }

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_session_end( export function register_session_end(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register<null, null>( register<null, null>(

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_session_oidc( export function register_session_oidc(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -5,10 +5,10 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_session_prepare( export function register_session_prepare(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
lib_plankton.rest.register< lib_plankton.rest_http.register<
any, any,
{ {
kind : string; kind : string;
@ -19,15 +19,15 @@ namespace _zeitbild.api
lib_plankton.http.enum_method.post, lib_plankton.http.enum_method.post,
"/session/prepare", "/session/prepare",
{ {
"description": "gibt die nötigen Werkzeuge für eine Anmeldung aus", "description": () => "gibt die nötigen Werkzeuge für eine Anmeldung aus",
"input_schema": () => ({ "input_schema": () => ({
"nullable": true, "nullable": true,
}), }),
"output_schema": () => ({ "output_schema": () => ({
"nullable": false "nullable": false
}), }),
"restriction": restriction_none, "restriction": () => restriction_none,
"execution": async (stuff) => { "execution": () => async (stuff) => {
const preparation = await _zeitbild.auth.prepare(stuff.input); const preparation = await _zeitbild.auth.prepare(stuff.input);
return Promise.resolve({ return Promise.resolve({
"status_code": 200, "status_code": 200,

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/** /**
*/ */
export function register_users( export function register_users(
rest_subject : lib_plankton.rest.type_rest rest_subject : lib_plankton.rest_http.type_rest
) : void ) : void
{ {
register< register<

View file

@ -3,6 +3,16 @@ namespace _zeitbild
/** /**
*/ */
export var cache : lib_plankton.cache.type_cache<any>; export var cache_regular : lib_plankton.cache.type_subject<any>;
/**
*/
export var cache_external_resources : lib_plankton.cache.type_subject<any>;
/**
*/
export var cache_templates : lib_plankton.cache.type_subject<string>;
} }

View file

@ -41,7 +41,17 @@ namespace _zeitbild.conf
"error" "error"
], ],
"default": "info" "default": "info"
} },
"format": {
"nullable": false,
"type": "string",
"enum": [
"human_readable",
"jsonl",
"jsonl_structured",
],
"default": "human_readable",
},
}, },
"required": [ "required": [
] ]

View file

@ -60,37 +60,29 @@ namespace _zeitbild.helpers
/** /**
*/ */
var _template_cache : Record<string, string> = {};
/**
* @todo caching
*/
export async function template_coin( export async function template_coin(
name : string, name : string,
data : Record<string, string> data : Record<string, string>
) : Promise<string> ) : Promise<string>
{ {
let content : string; const content : string = await lib_plankton.cache.get<string>(
if (! (name in _template_cache)) { _zeitbild.cache_templates,
content = ( name,
( null,
await lib_plankton.file.read( () => (
lib_plankton.string.coin( lib_plankton.file.read(
"templates/{{name}}.html.tpl", lib_plankton.string.coin(
{ "templates/{{name}}.html.tpl",
"name": name, {
} "name": name,
) }
) )
) )
.toString() .then(
); x => Promise.resolve<string>(x.toString())
_template_cache[name] = content; )
} )
else { );
content = _template_cache[name];
}
return Promise.resolve<string>( return Promise.resolve<string>(
lib_plankton.string.coin( lib_plankton.string.coin(
content, content,

View file

@ -68,7 +68,8 @@ async function data_init(
"user": {}, "user": {},
"calendar": {}, "calendar": {},
}; };
for await (const user_raw of data.users) { for await (const user_raw of data.users)
{
const user_object : _zeitbild.type_user_object = { const user_object : _zeitbild.type_user_object = {
"name": user_raw.name, "name": user_raw.name,
"email_address": user_raw.email_address, "email_address": user_raw.email_address,
@ -82,11 +83,14 @@ async function data_init(
); );
track.user[user_raw.id] = user_id; track.user[user_raw.id] = user_id;
} }
for await (const calendar_raw of data.calendars) { for await (const calendar_raw of data.calendars)
{
let resource_object : _zeitbild.type_resource_object; let resource_object : _zeitbild.type_resource_object;
let resource_id : _zeitbild.type_resource_id; let resource_id : _zeitbild.type_resource_id;
switch (calendar_raw.resource.kind) { switch (calendar_raw.resource.kind)
case "local": { {
case "local":
{
resource_object = { resource_object = {
"kind": "local", "kind": "local",
"data": { "data": {
@ -104,7 +108,8 @@ async function data_init(
); );
break; break;
} }
case "caldav": { case "caldav":
{
resource_object = { resource_object = {
"kind": "caldav", "kind": "caldav",
"data": { "data": {
@ -119,7 +124,8 @@ async function data_init(
break; break;
} }
} }
const calendar_object : _zeitbild.type_calendar_object = { const calendar_object : _zeitbild.type_calendar_object =
{
"name": calendar_raw.name, "name": calendar_raw.name,
"access": { "access": {
"public": (calendar_raw.access.public ?? false), "public": (calendar_raw.access.public ?? false),
@ -159,11 +165,17 @@ async function main(
) : Promise<void> ) : Promise<void>
{ {
// init1 // init1
lib_plankton.log.conf_push( /*
lib_plankton.log.set_main_logger(
[ [
lib_plankton.log.channel_make({"kind": "stdout", "data": {"threshold": "info"}}), {
"kind": "std",
"data": {
}
}
] ]
); );
*/
// args // args
const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler({ const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler({
@ -246,30 +258,79 @@ async function main(
"name": "help", "name": "help",
}), }),
}); });
const args : Record<string, any> = arg_handler.read(lib_plankton.args.enum_environment.cli, args_raw.join(" ")); const args : Record<string, any> = arg_handler.read(
lib_plankton.args.enum_environment.cli,
args_raw.join(" ")
);
// init2 // init2
await _zeitbild.conf.init( await _zeitbild.conf.init(
args["conf_path"] args["conf_path"]
); );
lib_plankton.log.conf_push( lib_plankton.log.set_main_logger(
_zeitbild.conf.get().log.map( _zeitbild.conf.get().log.map(
(log_output : any) => lib_plankton.log.channel_make( (log_output : any) => {
{ switch (log_output.kind) {
"kind": log_output.kind, case "stdout": {
"data": log_output.data return {
"kind": "minlevel",
"data": {
"core": {
"kind": "std",
"data": {
"target": "stdout",
"format": lib_plankton.call.distinguish(
{
"kind": log_output.data.format,
"data": null,
},
{
"jsonl": () => ({
"kind": "jsonl",
"data": {
"structured": false,
}
}),
"jsonl_structured": () => ({
"kind": "jsonl",
"data": {
"structured": true,
}
}),
"human_readable": () => ({
"kind": "human_readable",
"data": {
}
}),
}
),
}
},
"threshold": log_output.data.threshold,
}
};
break;
}
default: {
throw (new Error("unhandled"));
break;
}
} }
)
)
);
_zeitbild.cache = lib_plankton.cache.chest.implementation<any>(
lib_plankton.cache.chest.make<any>(
{
"chest": lib_plankton.storage.memory.implementation_chest<any>({}),
} }
) )
); );
await _zeitbild.cache.init(); {
_zeitbild.cache_regular = lib_plankton.cache.make<any>();
await lib_plankton.cache.init(_zeitbild.cache_regular);
}
{
_zeitbild.cache_external_resources = lib_plankton.cache.make<any>();
await lib_plankton.cache.init(_zeitbild.cache_external_resources);
}
{
_zeitbild.cache_templates = lib_plankton.cache.make<any>();
await lib_plankton.cache.init(_zeitbild.cache_templates);
}
// exec // exec
if (args["help"]) { if (args["help"]) {
@ -321,7 +382,7 @@ async function main(
break; break;
} }
case "api-doc": { case "api-doc": {
lib_plankton.log.conf_push([]); lib_plankton.log.set_main_logger([]);
const rest_subject : lib_plankton.rest.type_rest = _zeitbild.api.make(); const rest_subject : lib_plankton.rest.type_rest = _zeitbild.api.make();
lib_plankton.log.conf_pop(); lib_plankton.log.conf_pop();
process.stdout.write( process.stdout.write(
@ -389,6 +450,7 @@ async function main(
"checklevel_restriction": lib_plankton.api.enum_checklevel.hard, "checklevel_restriction": lib_plankton.api.enum_checklevel.hard,
// "checklevel_input": lib_plankton.api.enum_checklevel.soft, // "checklevel_input": lib_plankton.api.enum_checklevel.soft,
// "checklevel_output": lib_plankton.api.enum_checklevel.soft, // "checklevel_output": lib_plankton.api.enum_checklevel.soft,
"set_content_length": false,
} }
); );
const output : string = lib_plankton.http.encode_response(http_response); const output : string = lib_plankton.http.encode_response(http_response);

View file

@ -251,7 +251,7 @@ namespace _zeitbild.repository.calendar
{"level": access_attributed_row["level"]} {"level": access_attributed_row["level"]}
); );
} }
await _zeitbild.cache.clear(); await lib_plankton.cache.clear(_zeitbild.cache_regular);
return Promise.resolve<_zeitbild.type_calendar_id>(calendar_id); return Promise.resolve<_zeitbild.type_calendar_id>(calendar_id);
} }
@ -313,7 +313,7 @@ namespace _zeitbild.repository.calendar
); );
} }
} }
await _zeitbild.cache.clear(); await lib_plankton.cache.clear(_zeitbild.cache_regular);
return Promise.resolve<void>(undefined); return Promise.resolve<void>(undefined);
} }
@ -325,7 +325,7 @@ namespace _zeitbild.repository.calendar
calendar_id : _zeitbild.type_calendar_id calendar_id : _zeitbild.type_calendar_id
) : Promise<void> ) : Promise<void>
{ {
await _zeitbild.cache.clear(); await lib_plankton.cache.clear(_zeitbild.cache_regular);
const core_store = get_core_store(); const core_store = get_core_store();
const access_attributed_chest = get_access_attributed_chest(); const access_attributed_chest = get_access_attributed_chest();
// attributed access // attributed access
@ -375,11 +375,12 @@ namespace _zeitbild.repository.calendar
> >
{ {
return lib_plankton.cache.get_complex<any, Array<type_overview_entry>>( return lib_plankton.cache.get_complex<any, Array<type_overview_entry>>(
_zeitbild.cache, _zeitbild.cache_regular,
"calendar_overview", "calendar_overview",
{ {
"user_id": user_id, "user_id": user_id,
}, },
null,
() => ( () => (
lib_plankton.file.read("sql/calendar_overview.sql") lib_plankton.file.read("sql/calendar_overview.sql")
.then( .then(

View file

@ -401,7 +401,7 @@ namespace _zeitbild.repository.resource
"sub_id": local_resource_id, "sub_id": local_resource_id,
} }
); );
await _zeitbild.cache.clear(); await lib_plankton.cache.clear(_zeitbild.cache_regular);
return Promise.resolve<_zeitbild.type_resource_id>(resource_id); return Promise.resolve<_zeitbild.type_resource_id>(resource_id);
break; break;
} }
@ -419,7 +419,7 @@ namespace _zeitbild.repository.resource
"sub_id": caldav_resource_id, "sub_id": caldav_resource_id,
} }
); );
await _zeitbild.cache.clear(); await lib_plankton.cache.clear(_zeitbild.cache_regular);
return Promise.resolve<_zeitbild.type_resource_id>(resource_id); return Promise.resolve<_zeitbild.type_resource_id>(resource_id);
break; break;
} }
@ -499,7 +499,7 @@ namespace _zeitbild.repository.resource
"read_only": resource_object.data.read_only, "read_only": resource_object.data.read_only,
} }
); );
await _zeitbild.cache.clear(); await lib_plankton.cache.clear(_zeitbild.cache_regular);
break; break;
} }
default: { default: {
@ -561,7 +561,7 @@ namespace _zeitbild.repository.resource
} }
) )
); );
await _zeitbild.cache.clear(); await lib_plankton.cache.clear(_zeitbild.cache_regular);
return Promise.resolve(local_resource_event_id); return Promise.resolve(local_resource_event_id);
} }
} }
@ -589,7 +589,7 @@ namespace _zeitbild.repository.resource
} }
) )
); );
await _zeitbild.cache.clear(); await lib_plankton.cache.clear(_zeitbild.cache_regular);
return Promise.resolve<void>(undefined); return Promise.resolve<void>(undefined);
} }
} }
@ -602,7 +602,7 @@ namespace _zeitbild.repository.resource
local_resource_event_id : _zeitbild.type_local_resource_event_id local_resource_event_id : _zeitbild.type_local_resource_event_id
) : Promise<void> ) : Promise<void>
{ {
await _zeitbild.cache.clear(); await lib_plankton.cache.clear(_zeitbild.cache_regular);
const dataset_core : Record<string, any> = await get_resource_core_store().read(resource_id); const dataset_core : Record<string, any> = await get_resource_core_store().read(resource_id);
if (! (dataset_core.kind === "local")) { if (! (dataset_core.kind === "local")) {
throw (new Error("not a local resource")); throw (new Error("not a local resource"));