From 0eb578b70ff6c510ba1b0530de4834ca9c57dbb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 23 Jun 2024 09:31:05 +0200 Subject: [PATCH] [mod] session management: cache for key --- source/backend.py | 82 ++++++++++++++++++++++++++++++++++++++--------- source/conf.py | 44 ++++++++++++++++++------- source/main.py | 32 +++++++++++++++--- 3 files changed, 126 insertions(+), 32 deletions(-) diff --git a/source/backend.py b/source/backend.py index c9c360a..6059747 100644 --- a/source/backend.py +++ b/source/backend.py @@ -1,5 +1,7 @@ import typing as _typing +import os as _os import json as _json +import time as _time import requests as _requests from helpers import * @@ -7,19 +9,24 @@ from conf import * from log import * -_session_key = None - def backend_api_call_generic( - http_method, - action_path, - data + session_key : _typing.Optional[str], + http_method : str, + action_path : str, + data, + options : _typing.Optional[dict] = None ): - global _session_key + options = ( + { + } + | + (options or {}) + ) log_info( "backend_api_call", { - "with_session_key": (not (_session_key is None)), + "with_session_key": (not (session_key is None)), "http_method": http_method, "path": action_path, } @@ -36,8 +43,8 @@ def backend_api_call_generic( ) headers_common = ( {} - if (_session_key is None) else - {"X-Session-Key": _session_key} + if (session_key is None) else + {"X-Session-Key": session_key} ) if (http_method == "GET"): response_raw = _requests.get( @@ -76,8 +83,8 @@ def backend_api_call_generic( def backend_api_call_session_begin( ): - global _session_key - session_key = backend_api_call_generic( + return backend_api_call_generic( + None, "POST", "/session/begin", { @@ -85,13 +92,45 @@ def backend_api_call_session_begin( "password": conf_get()["account"]["password"], } ) - _session_key = session_key - return None + + +def get_session_key( +): + path = conf_get()["session"]["key_path"] + if ( + _os.path.exists(path) + and + ( + (_time.time() - _os.path.getmtime(path)) + < + conf_get()["session"]["lifetime"] + ) + ): + session_key = file_text_read(path) + else: + session_key = backend_api_call_session_begin() + file_text_write(path, session_key) + return session_key + + +def backend_api_call_wrapped( + needs_session : bool, + http_method : str, + action_path : str, + data +): + return backend_api_call_generic( + (get_session_key() if needs_session else None), + http_method, + action_path, + data + ) def backend_api_call_session_end( ): return backend_api_call_generic( + True, "DELETE", "/session/end", None @@ -100,7 +139,8 @@ def backend_api_call_session_end( def backend_api_call_member_list( ): - return backend_api_call_generic( + return backend_api_call_wrapped( + True, "GET", "/member/list", None @@ -113,7 +153,8 @@ def backend_api_call_member_project( email_address_private : _typing.Optional[str], notification_target_url_template : _typing.Optional[str] ): - return backend_api_call_generic( + return backend_api_call_wrapped( + True, "POST", "/member/project", { @@ -124,3 +165,14 @@ def backend_api_call_member_project( } ) + +def backend_api_call_member_delete( + member_id +): + return backend_api_call_wrapped( + True, + "DELETE", + string_coin("/member/{{id}}", {"id": member_id}), + None + ) + diff --git a/source/conf.py b/source/conf.py index 298c6cc..7206399 100644 --- a/source/conf.py +++ b/source/conf.py @@ -86,6 +86,22 @@ def conf_schema( "password", ] }, + "session": { + "type": "object", + "properties": { + "lifetime": { + "type": "string", + }, + "key_path": { + "type": "string", + }, + }, + "additionalProperties": False, + "required": [ + "name", + "password", + ] + }, } } @@ -108,32 +124,36 @@ def conf_refine( version = data_raw["version"] if (version == 1): # log - if True: - data_raw_log = data_raw.get("log", {}) - data_log = { + def refine_log(data_raw_log): + return { "format": data_raw_log.get("format", "human_readable"), "min_level": data_raw_log.get("min_level", "notice"), } # api - if True: - data_raw_api = data_raw.get("api", {}) - data_api = { + def refine_api(data_raw_api): + return { "scheme": data_raw_api.get("scheme", "https"), "host": data_raw_api["host"], "port": data_raw_api.get("port", 4916), "path": data_raw_api.get("path", ""), } # account - if True: - data_raw_account = data_raw.get("account", {}) - data_account = { + def refine_account(data_raw_account): + return { "name": data_raw_account["name"], "password": data_raw_account["password"], } + # session + def refine_session(data_raw_session): + return { + "lifetime": data_raw_session.get("lifetime", 3600), + "key_path": data_raw_session.get("key_path", _os.path.join(_os.path.expanduser("~"), ".mondvogel", "session_key")), + } data = { - "log": data_log, - "api": data_api, - "account": data_account, + "log": refine_log(data_raw.get("log", {})), + "api": refine_api(data_raw.get("api", {})), + "account": refine_account(data_raw.get("account", {})), + "session": refine_session(data_raw.get("session", {})), } else: flaws.append( diff --git a/source/main.py b/source/main.py index 1958579..ad206f8 100644 --- a/source/main.py +++ b/source/main.py @@ -24,9 +24,10 @@ def main(): choices = [ "member-list", "member-project", + "member-delete" ], metavar = "", - help = "auszuführende Aktion; Optionen: 'conf-schema' : JSON-Schema der Konfiguration ausgeben | 'conf-expose' : vervollständigte Konfiguration ausgegeben | 'member-list' : Liste der Mitglieder ausgeben | 'member-project' : ein Mitglied anlegen und die ID des erzeugten Datensatzes ausgeben", + help = "auszuführende Aktion; Optionen: 'conf-schema' : JSON-Schema der Konfiguration ausgeben | 'conf-expose' : vervollständigte Konfiguration ausgegeben | 'member-list' : Liste der Mitglieder ausgeben | 'member-project' : ein Mitglied anlegen und die ID des erzeugten Datensatzes ausgeben | 'member-delete' : einer Mitglieder-Datensatz löschen", ) argument_parser.add_argument( "-c", @@ -37,6 +38,15 @@ def main(): metavar = "", help = "Pfad zur Konfigurations-Datei", ) + argument_parser.add_argument( + "-i", + "--id", + type = int, + dest = "id", + default = None, + metavar = "", + help = "ID des Mitglieds", + ) argument_parser.add_argument( "-m", "--membership-number", @@ -88,10 +98,8 @@ def main(): elif (args.action == "conf-expose"): _sys.stdout.write(_json.dumps(conf_get(), indent = "\t") + "\n") elif (args.action == "member-list"): - backend_api_call_session_begin() data = backend_api_call_member_list( ) - backend_api_call_session_end() _sys.stdout.write(_json.dumps(data, indent = "\t") + "\n") elif (args.action == "member-project"): if ( @@ -112,15 +120,29 @@ def main(): } ) else: - backend_api_call_session_begin() member_id = backend_api_call_member_project( args.membership_number, args.name, args.email_address, None ) - backend_api_call_session_end() _sys.stdout.write(_json.dumps(member_id, indent = "\t") + "\n") + elif (args.action == "member-delete"): + if ( + (args.id is None) + ): + log_error( + "mandatory_parameters_missing", + { + "parameters": [ + "id", + ] + } + ) + else: + member_id = backend_api_call_member_delete( + args.id + ) else: raise NotImplementedError()