Add Loki and Sentinel utility classes for web API endpoints

- Implemented LokiUtils class with GET and POST endpoints for managing scripts, jobs, and payloads.
- Added SentinelUtils class with GET and POST endpoints for managing events, rules, devices, and notifications.
- Both classes include error handling and JSON response formatting.
This commit is contained in:
infinition
2026-03-14 22:33:10 +01:00
parent eb20b168a6
commit aac77a3e76
525 changed files with 29400 additions and 13136 deletions

45
loki/layouts/__init__.py Normal file
View File

@@ -0,0 +1,45 @@
"""
Keyboard layout loader for Loki HID subsystem.
Caches loaded layouts in memory.
"""
import json
import os
import logging
from logger import Logger
logger = Logger(name="loki.layouts", level=logging.DEBUG)
_LAYOUT_DIR = os.path.dirname(os.path.abspath(__file__))
_cache = {}
def load(name: str = "us") -> dict:
"""Load a keyboard layout by name. Returns char → (modifier, keycode) map."""
name = name.lower()
if name in _cache:
return _cache[name]
path = os.path.join(_LAYOUT_DIR, f"{name}.json")
if not os.path.isfile(path):
logger.warning("Layout '%s' not found, falling back to 'us'", name)
path = os.path.join(_LAYOUT_DIR, "us.json")
name = "us"
if name in _cache:
return _cache[name]
with open(path, "r") as f:
data = json.load(f)
_cache[name] = data
logger.debug("Loaded keyboard layout '%s' (%d chars)", name, len(data))
return data
def available() -> list:
"""List available layout names."""
layouts = []
for f in os.listdir(_LAYOUT_DIR):
if f.endswith(".json"):
layouts.append(f[:-5])
return sorted(layouts)

41
loki/layouts/us.json Normal file
View File

@@ -0,0 +1,41 @@
{
"a": [0, 4], "b": [0, 5], "c": [0, 6], "d": [0, 7],
"e": [0, 8], "f": [0, 9], "g": [0, 10], "h": [0, 11],
"i": [0, 12], "j": [0, 13], "k": [0, 14], "l": [0, 15],
"m": [0, 16], "n": [0, 17], "o": [0, 18], "p": [0, 19],
"q": [0, 20], "r": [0, 21], "s": [0, 22], "t": [0, 23],
"u": [0, 24], "v": [0, 25], "w": [0, 26], "x": [0, 27],
"y": [0, 28], "z": [0, 29],
"A": [2, 4], "B": [2, 5], "C": [2, 6], "D": [2, 7],
"E": [2, 8], "F": [2, 9], "G": [2, 10], "H": [2, 11],
"I": [2, 12], "J": [2, 13], "K": [2, 14], "L": [2, 15],
"M": [2, 16], "N": [2, 17], "O": [2, 18], "P": [2, 19],
"Q": [2, 20], "R": [2, 21], "S": [2, 22], "T": [2, 23],
"U": [2, 24], "V": [2, 25], "W": [2, 26], "X": [2, 27],
"Y": [2, 28], "Z": [2, 29],
"1": [0, 30], "2": [0, 31], "3": [0, 32], "4": [0, 33],
"5": [0, 34], "6": [0, 35], "7": [0, 36], "8": [0, 37],
"9": [0, 38], "0": [0, 39],
"!": [2, 30], "@": [2, 31], "#": [2, 32], "$": [2, 33],
"%": [2, 34], "^": [2, 35], "&": [2, 36], "*": [2, 37],
"(": [2, 38], ")": [2, 39],
"\n": [0, 40], "\r": [0, 40],
"\t": [0, 43],
" ": [0, 44],
"-": [0, 45], "_": [2, 45],
"=": [0, 46], "+": [2, 46],
"[": [0, 47], "{": [2, 47],
"]": [0, 48], "}": [2, 48],
"\\": [0, 49], "|": [2, 49],
";": [0, 51], ":": [2, 51],
"'": [0, 52], "\"": [2, 52],
"`": [0, 53], "~": [2, 53],
",": [0, 54], "<": [2, 54],
".": [0, 55], ">": [2, 55],
"/": [0, 56], "?": [2, 56]
}