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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,10 +5,10 @@ namespace _zeitbild.api
/**
*/
export function register_meta_ping(
rest_subject : lib_plankton.rest.type_rest
rest_subject : lib_plankton.rest_http.type_rest
) : void
{
lib_plankton.rest.register<
lib_plankton.rest_http.register<
null,
string
>
@ -17,7 +17,7 @@ namespace _zeitbild.api
lib_plankton.http.enum_method.get,
_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": () => ({
"nullable": true,
}),
@ -25,8 +25,10 @@ namespace _zeitbild.api
"nullable": false,
"type": "string",
}),
"restriction": restriction_none,
"execution": () => {
"response_body_encode": () => (body) => Promise.resolve<string>(body),
"response_body_mimetype": () => "text/plain",
"restriction": () => restriction_none,
"execution": () => () => {
return Promise.resolve({
"status_code": 200,
"data": "pong",

View file

@ -5,10 +5,10 @@ namespace _zeitbild.api
/**
*/
export function register_meta_spec(
rest_subject : lib_plankton.rest.type_rest
rest_subject : lib_plankton.rest_http.type_rest
) : void
{
lib_plankton.rest.register<
lib_plankton.rest_http.register<
null,
any
>
@ -17,17 +17,17 @@ namespace _zeitbild.api
lib_plankton.http.enum_method.get,
_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": () => ({
"nullable": true,
}),
"output_schema": () => ({
}),
"restriction": restriction_none,
"execution": () => {
"restriction": () => restriction_none,
"execution": () => () => {
return Promise.resolve({
"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(
rest_subject : lib_plankton.rest.type_rest
rest_subject : lib_plankton.rest_http.type_rest
) : void
{
lib_plankton.rest.register<
lib_plankton.rest_http.register<
{
name : string;
password : string;
@ -23,7 +23,7 @@ namespace _zeitbild.api
lib_plankton.http.enum_method.post,
"/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": () => ({
"type": "object",
"properties": {
@ -44,8 +44,8 @@ namespace _zeitbild.api
"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",
}),
"restriction": restriction_none,
"execution": async ({"input": input}) => {
"restriction": () => restriction_none,
"execution": () => async ({"input": input}) => {
if (input === null) {
return Promise.reject(new Error("impossible"));
}

View file

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

View file

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

View file

@ -5,10 +5,10 @@ namespace _zeitbild.api
/**
*/
export function register_session_prepare(
rest_subject : lib_plankton.rest.type_rest
rest_subject : lib_plankton.rest_http.type_rest
) : void
{
lib_plankton.rest.register<
lib_plankton.rest_http.register<
any,
{
kind : string;
@ -19,15 +19,15 @@ namespace _zeitbild.api
lib_plankton.http.enum_method.post,
"/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": () => ({
"nullable": true,
}),
"output_schema": () => ({
"nullable": false
}),
"restriction": restriction_none,
"execution": async (stuff) => {
"restriction": () => restriction_none,
"execution": () => async (stuff) => {
const preparation = await _zeitbild.auth.prepare(stuff.input);
return Promise.resolve({
"status_code": 200,

View file

@ -5,7 +5,7 @@ namespace _zeitbild.api
/**
*/
export function register_users(
rest_subject : lib_plankton.rest.type_rest
rest_subject : lib_plankton.rest_http.type_rest
) : void
{
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"
],
"default": "info"
}
},
"format": {
"nullable": false,
"type": "string",
"enum": [
"human_readable",
"jsonl",
"jsonl_structured",
],
"default": "human_readable",
},
},
"required": [
]

View file

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

View file

@ -68,7 +68,8 @@ async function data_init(
"user": {},
"calendar": {},
};
for await (const user_raw of data.users) {
for await (const user_raw of data.users)
{
const user_object : _zeitbild.type_user_object = {
"name": user_raw.name,
"email_address": user_raw.email_address,
@ -82,11 +83,14 @@ async function data_init(
);
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_id : _zeitbild.type_resource_id;
switch (calendar_raw.resource.kind) {
case "local": {
switch (calendar_raw.resource.kind)
{
case "local":
{
resource_object = {
"kind": "local",
"data": {
@ -104,7 +108,8 @@ async function data_init(
);
break;
}
case "caldav": {
case "caldav":
{
resource_object = {
"kind": "caldav",
"data": {
@ -119,7 +124,8 @@ async function data_init(
break;
}
}
const calendar_object : _zeitbild.type_calendar_object = {
const calendar_object : _zeitbild.type_calendar_object =
{
"name": calendar_raw.name,
"access": {
"public": (calendar_raw.access.public ?? false),
@ -159,11 +165,17 @@ async function main(
) : Promise<void>
{
// 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
const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler({
@ -246,30 +258,79 @@ async function main(
"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
await _zeitbild.conf.init(
args["conf_path"]
);
lib_plankton.log.conf_push(
lib_plankton.log.set_main_logger(
_zeitbild.conf.get().log.map(
(log_output : any) => lib_plankton.log.channel_make(
{
"kind": log_output.kind,
"data": log_output.data
(log_output : any) => {
switch (log_output.kind) {
case "stdout": {
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
if (args["help"]) {
@ -321,7 +382,7 @@ async function main(
break;
}
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();
lib_plankton.log.conf_pop();
process.stdout.write(
@ -389,6 +450,7 @@ async function main(
"checklevel_restriction": lib_plankton.api.enum_checklevel.hard,
// "checklevel_input": 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);

View file

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

View file

@ -401,7 +401,7 @@ namespace _zeitbild.repository.resource
"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);
break;
}
@ -419,7 +419,7 @@ namespace _zeitbild.repository.resource
"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);
break;
}
@ -499,7 +499,7 @@ namespace _zeitbild.repository.resource
"read_only": resource_object.data.read_only,
}
);
await _zeitbild.cache.clear();
await lib_plankton.cache.clear(_zeitbild.cache_regular);
break;
}
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);
}
}
@ -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);
}
}
@ -602,7 +602,7 @@ namespace _zeitbild.repository.resource
local_resource_event_id : _zeitbild.type_local_resource_event_id
) : 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);
if (! (dataset_core.kind === "local")) {
throw (new Error("not a local resource"));