feat: add annotations about functionalities of some endpoints

This commit is contained in:
2025-05-28 14:47:49 +02:00
parent 67307f216f
commit 72141768d4
2 changed files with 84 additions and 6 deletions

View File

@@ -1,4 +1,4 @@
# API is expected to return:
# API is expected to return a tuple of:
# - HTTP status code,
# - human-readable status message,
# - json with appropriate data
@@ -11,6 +11,14 @@ import lewy_db as ldb
import lewy_globals
def require_authentication(func):
"""
Ten dekorator służy do wymuszenia parametru "token"
podczas obsługi zapytania. Powinien on zostać doklejony
do żądania, np. /api/v1/halt?token=XXX...
Wartość tokenu jest pobierana z pola api_key w config.toml.
Jeżeli skrypt jej tam nie znajdzie, jest generowana losowo
na starcie i drukowana w terminalu.
"""
@wraps(func)
def wrapper(*args, **kwargs):
token = kwargs["r"].args.get('token')
@@ -26,19 +34,44 @@ def require_authentication(func):
return wrapper
def increment_bad_requests():
"""
Zwiększa globalny, tymczasowy licznik nieprawidłowych zapytań.
"""
lewy_globals.apiFailedRequests += 1
def not_implemented(data):
"""
Zwraca kod 501 wraz z endpointem, który wywołał błąd.
:param data: Ścieżka zapytania
:type data: list
"""
# TODO: change list to string -> data, not data[0]
return 501, f"not recognised/implemented: {data[0]}", []
# GET /api/v1
def stub_hello():
"""
Prosta funkcja witająca użytkowników w /api/v1
"""
return 200, 'hello from v1! stats are at /api/v1/stats', []
def epoch_to_date(epoch):
"""
Zamienia Unix'owy epoch na lokalny czas,
w formacie przypominającym format ISO.
:param epoch: Epoch - sekundy po 1. stycznia 1970
:type epoch: int
"""
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(epoch))
# GET /api/v1/
# GET /api/v1/stats
def stats():
"""
Zwraca ogólne statystyki serwera.
"""
data_to_send = {
"start_time": lewy_globals.starttime,
"uptime": lewy_globals.getUptime(),
@@ -50,11 +83,20 @@ def stats():
}
return 200, "ok", data_to_send
def get_matches():
# GET /api/v1/matches
def get_matches(r):
"""
TODO: Zwraca mecze.
"""
pass
# GET /api/v1/debugger_halt?token=XXX...
@require_authentication
def debugger_halt(r):
"""
Zatrzymuje wykonywanie skryptu, aby pozwolić
administratorowi na wykonywanie dowolnego polecenia z konsoli.
"""
if lewy_globals.config['general']['is_proxied']:
print(f"{c.WARNING}[{epoch_to_date(time.time())}]{c.ENDC} {r.headers['X-Forwarded-For']} triggered a debugger halt!")
else:
@@ -63,6 +105,16 @@ def debugger_halt(r):
return 200, "ok", []
def lookup(data, request):
"""
Obsługuje zapytania zwrócone do /api/v1/...
:param data: Lista ze ścieżką zapytania
:type data: list
:param request: Zapytanie
:type request: flask.request
:returns: Wartość zwróconą przez którąś z przywołanych funkcji.
"""
if data == []:
return stub_hello()
match data[0].lower():
@@ -74,6 +126,8 @@ def lookup(data, request):
return stub_hello()
case 'halt':
return debugger_halt(r = request)
case 'matches':
get_matches(r = request)
case _:
increment_bad_requests()
return not_implemented(data)

View File

@@ -29,7 +29,7 @@ def safeTraverse(obj: dict, path: list, default=None):
finally:
return result
def getCommit():
def getCommit() -> str | None:
try:
return Repo(search_parent_directories=True).head.object.hexsha
except Exception as e:
@@ -65,7 +65,7 @@ def ensureRandomlyGeneratedPassword():
print(f"{colors.WARNING}WARNING{colors.ENDC}: Default config populated with one-time, insecure pseudorandom API key: {colors.OKCYAN}{randomly_generated_passcode}{colors.ENDC}.\n"
f" The API key is not the Flask debugger PIN. You need to provide a config file for persistence!{colors.ENDL}")
def getConfig(configfile):
def getConfig(configfile: str) -> dict:
global randomly_generated_passcode
if not os.path.exists(configfile):
@@ -82,15 +82,26 @@ def getConfig(configfile):
else:
return toml.load(configfile)
def setupDb(app, config):
def setupDb(app, config) -> lewy_db.baza:
global db
db = lewy_db.baza(app, config)
return db
def getDb():
def getDb() -> lewy_db.baza:
"""
Akcesor dla wrappera bazy danych wspólnego dla całego projektu
(klasy baza z lewy_db)
"""
return db
def setConfig(configfile):
"""
Zapewnia, że konfiguracja nie jest pusta,
nawet, gdy sam plik jest pusty.
:param configfile: Ścieżka do pliku
:type configfile: str
"""
global config
config = getConfig(configfile)
@@ -100,6 +111,11 @@ def setConfig(configfile):
def getHeaders():
"""
Zwraca hardkodowane nagłówki do scrapowania, bądź te,
z config.toml (o ile użytkownik jakieś podał).
"""
# NOTE: use ESR user-agent
# user_agent = 'Mozilla/5.0 (Windows NT 10.0; rv:130.0) Gecko/20100101 Firefox/130.0'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0'
@@ -110,10 +126,18 @@ def getHeaders():
return user_agent
def getUptime():
"""
Zwraca informację o czasie działania serwera.
"""
return int(time.time()) - starttime
def extractIpAndPortFromPublicUrl() -> tuple:
"""
Pobiera dane z konfiguracji i zwraca
krotkę: adres IP i port.
"""
ip, port = "127.0.0.1", "5000"
try: