backend/source/main.ts

311 lines
8.6 KiB
TypeScript

/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
/**
*/
async function main(
args_raw : Array<string>
) : Promise<void>
{
// init
await lib_plankton.translate.initialize(
{
"verbosity": 1,
"packages": [
JSON.parse(await lib_plankton.file.read("data/localization/deu.loc.json")),
JSON.parse(await lib_plankton.file.read("data/localization/eng.loc.json")),
],
"order": ["deu", "eng"],
"autopromote": false,
}
);
// 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": "serve",
"name": "action",
"info": lib_plankton.string.coin(
"{{description}}:\n{{options}}\n\t\t",
{
"description": lib_plankton.translate.get("help.args.action.options.serve"),
"options": (
[
{
"name": "serve",
"description": lib_plankton.translate.get("help.args.action.options.serve"),
},
{
"name": "api-doc",
"description": lib_plankton.translate.get("help.args.action.options.api_doc")
},
{
"name": "expose-conf",
"description": lib_plankton.translate.get("help.args.action.options.expose_conf")
},
{
"name": "password-image",
"description": lib_plankton.translate.get("help.args.action.options.password_image")
},
{
"name": "export-authelia",
"description": lib_plankton.translate.get("help.args.action.options.export_authelia")
},
{
"name": "help",
"description": lib_plankton.translate.get("help.args.action.options.help")
},
]
.map(
entry => lib_plankton.string.coin(
"\t\t- {{name}}\n\t\t\t{{description}}\n",
{
"name": entry.name,
"description": entry.description,
}
)
)
.join("")
),
}
),
}),
"arg1": lib_plankton.args.class_argument.positional({
"index": 1,
"type": lib_plankton.args.enum_type.string,
"mode": lib_plankton.args.enum_mode.replace,
"default": null,
// "info": null,
"name": "arg1",
"hidden": true,
}),
"arg2": lib_plankton.args.class_argument.positional({
"index": 2,
"type": lib_plankton.args.enum_type.string,
"mode": lib_plankton.args.enum_mode.replace,
"default": null,
// "info": null,
"name": "arg2",
"hidden": true,
}),
"conf_path": lib_plankton.args.class_argument.volatile({
"indicators_long": ["conf_path"],
"indicators_short": ["c"],
"type": lib_plankton.args.enum_type.string,
"mode": lib_plankton.args.enum_mode.replace,
"default": "conf.json",
"info": lib_plankton.translate.get("help.args.conf_path.description"),
"name": "conf-path",
}),
"help": lib_plankton.args.class_argument.volatile({
"indicators_long": ["help"],
"indicators_short": ["h"],
"type": lib_plankton.args.enum_type.boolean,
"mode": lib_plankton.args.enum_mode.replace,
"default": false,
"info": lib_plankton.translate.get("help.args.help.description"),
"name": "help",
}),
});
const args : Record<string, any> = arg_handler.read(lib_plankton.args.enum_environment.cli, args_raw.join(" "));
// init
await _espe.conf.load(args["conf_path"]);
if (_espe.conf.get().general.language === null) {
// do nothing
}
else {
lib_plankton.translate.promote(_espe.conf.get().general.language);
}
lib_plankton.log.conf_push(
[
new lib_plankton.log.class_channel_minlevel(
new lib_plankton.log.class_channel_stdout(),
{
"none": lib_plankton.log.enum_level.error,
"error": lib_plankton.log.enum_level.error,
"warning": lib_plankton.log.enum_level.warning,
"notice": lib_plankton.log.enum_level.notice,
"info": lib_plankton.log.enum_level.info,
"debug":lib_plankton.log.enum_level.debug,
}[_espe.conf.get().general.verbosity]
),
]
);
// exec
if (args["help"] || (args["action"] === "help")) {
process.stdout.write(
arg_handler.generate_help(
{
"programname": "espe",
"description": "Espe | Backend",
"executable": "espe",
}
)
+
"\n"
);
}
else {
switch (args["action"]) {
default: {
process.stderr.write("invalid action: " + args["action"] + "\n");
break;
}
case "password-image": {
const input : (null | string) = args["arg1"];
if (input === null) {
throw (new Error("SYNTAX: password-image <password>"));
}
else {
const result : string = await _espe.helpers.bcrypt_compute(input);
process.stdout.write(result + "\n")
}
break;
}
case "expose-conf": {
process.stdout.write(
JSON.stringify(
_espe.conf.get(),
undefined,
"\t"
)
+
"\n"
);
break;
}
case "api-doc": {
lib_plankton.log.conf_push([]);
const rest_subject : lib_plankton.rest.type_rest = _espe.api.make();
lib_plankton.log.conf_pop();
process.stdout.write(
JSON.stringify(
lib_plankton.rest.to_oas(rest_subject),
undefined,
"\t"
)
);
break;
}
case "serve": {
// prepare database
await _espe.database.check();
await lib_plankton.session.setup(
{
"data_chest": (
_espe.conf.get().session_management.in_memory
? lib_plankton.storage.memory.implementation_chest<lib_plankton.session.type_session>({})
: lib_plankton.call.convey(
lib_plankton.storage.sql_table_common.chest(
{
"database_implementation": _espe.helpers.database_implementation(),
"table_name": "sessions",
"key_names": ["key"],
}
),
[
(core) => ({
"setup": (input) => core.setup(undefined),
"clear": () => core.clear(),
"write": (key, value) => core.write([key], {"data": JSON.stringify(value)}),
"delete": (key) => core.delete([key]),
"read": (key) => core.read([key]).then(row => JSON.parse(row["data"])),
// "search": (term) => core.search(term).then(() => []),
"search": (term) => Promise.reject(new Error("not implemented")),
}),
]
)
),
"default_lifetime": _espe.conf.get().session_management.lifetime,
}
);
_espe.service.member.listen_change(
() => {
lib_plankton.log.info(
"member_change",
{
}
);
}
);
// outputs
{
if (_espe.conf.get().output.authelia === null) {
// do nothing
}
else {
_espe.service.member.listen_change(
async () => {
const authelia_export : string = await _espe.service.member.export_authelia_user_file();
lib_plankton.file.write(
_espe.conf.get().output.authelia,
authelia_export
);
}
);
}
}
const rest_subject : lib_plankton.rest.type_rest = _espe.api.make();
const server : lib_plankton.server.type_subject = lib_plankton.server.make(
_espe.conf.get().server.port,
async (input, metadata) => {
const http_request : lib_plankton.http.type_request = lib_plankton.http.decode_request(input);
const http_response : lib_plankton.http.type_response = await lib_plankton.rest.call(
rest_subject,
http_request,
{
"checklevel_restriction": lib_plankton.api.enum_checklevel.hard,
// "checklevel_input": lib_plankton.api.enum_checklevel.soft,
// "checklevel_output": lib_plankton.api.enum_checklevel.soft,
}
);
const output : string = lib_plankton.http.encode_response(http_response);
return output;
}
);
lib_plankton.server.start(server);
break;
}
case "export-authelia": {
process.stdout.write(await _espe.service.member.export_authelia_user_file() + "\n");
break;
}
}
}
}
(
main(process.argv.slice(2))
.then(
() => {
}
)
.catch(
(error) => {
process.stderr.write(String(error) + "\n");
}
)
);