Erster Stand der Hintergrundprozesse, die auf der Synology unter /volume1/homes/wagner/SolarManager laufen: der Manager selbst, die Sammler je Geraet, die MQTT-Bruecke, der Wecker und - neu hinzugezogen - der AutoAction-Runner, der als Hintergrundprozess hierher gehoert und nicht ins Web-Verzeichnis. Zugangsdaten stehen nicht mehr im Quelltext, sondern in config.ini, die nicht mit eingecheckt wird. Vorlage ist config.ini.example, gelesen wird sie von konfig.py. Betroffen waren solarManager.py (Datenbank und Wattpilot), zeit.py, gatherWaterData.py, wecker.py und skoda_testdaten.py, das sich das Passwort bisher aus dem Quelltext eines anderen Moduls herausgesucht hat. Die Kia-Anbindung ist mit dem Fahrzeug entfallen: kiaTest.py, gatherCarData.py und hyundai_kia_connect_api sind nicht mehr dabei, ebenso gatherInverterData.py, auf das nur noch eine auskommentierte Zeile zeigte. Die mitgelieferten Bibliotheken bleiben im Repository - die NAS hat kein pip, sie muessen neben den Skripten liegen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
164 lines
4.5 KiB
Cython
164 lines
4.5 KiB
Cython
from cpython.bytes cimport PyBytes_FromStringAndSize
|
|
from cpython.exc cimport PyErr_NoMemory
|
|
from cpython.mem cimport PyMem_Free, PyMem_Malloc, PyMem_Realloc
|
|
from cpython.object cimport PyObject_Str
|
|
from libc.stdint cimport uint8_t, uint64_t
|
|
from libc.string cimport memcpy
|
|
|
|
from multidict import istr
|
|
|
|
DEF BUF_SIZE = 16 * 1024 # 16KiB
|
|
cdef char BUFFER[BUF_SIZE]
|
|
|
|
cdef object _istr = istr
|
|
|
|
|
|
# ----------------- writer ---------------------------
|
|
|
|
cdef struct Writer:
|
|
char *buf
|
|
Py_ssize_t size
|
|
Py_ssize_t pos
|
|
|
|
|
|
cdef inline void _init_writer(Writer* writer):
|
|
writer.buf = &BUFFER[0]
|
|
writer.size = BUF_SIZE
|
|
writer.pos = 0
|
|
|
|
|
|
cdef inline void _release_writer(Writer* writer):
|
|
if writer.buf != BUFFER:
|
|
PyMem_Free(writer.buf)
|
|
|
|
|
|
cdef inline int _write_byte(Writer* writer, uint8_t ch):
|
|
cdef char * buf
|
|
cdef Py_ssize_t size
|
|
|
|
if writer.pos == writer.size:
|
|
# reallocate
|
|
size = writer.size + BUF_SIZE
|
|
if writer.buf == BUFFER:
|
|
buf = <char*>PyMem_Malloc(size)
|
|
if buf == NULL:
|
|
PyErr_NoMemory()
|
|
return -1
|
|
memcpy(buf, writer.buf, writer.size)
|
|
else:
|
|
buf = <char*>PyMem_Realloc(writer.buf, size)
|
|
if buf == NULL:
|
|
PyErr_NoMemory()
|
|
return -1
|
|
writer.buf = buf
|
|
writer.size = size
|
|
writer.buf[writer.pos] = <char>ch
|
|
writer.pos += 1
|
|
return 0
|
|
|
|
|
|
cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol):
|
|
cdef uint64_t utf = <uint64_t> symbol
|
|
|
|
if utf < 0x80:
|
|
return _write_byte(writer, <uint8_t>utf)
|
|
elif utf < 0x800:
|
|
if _write_byte(writer, <uint8_t>(0xc0 | (utf >> 6))) < 0:
|
|
return -1
|
|
return _write_byte(writer, <uint8_t>(0x80 | (utf & 0x3f)))
|
|
elif 0xD800 <= utf <= 0xDFFF:
|
|
# surogate pair, ignored
|
|
return 0
|
|
elif utf < 0x10000:
|
|
if _write_byte(writer, <uint8_t>(0xe0 | (utf >> 12))) < 0:
|
|
return -1
|
|
if _write_byte(writer, <uint8_t>(0x80 | ((utf >> 6) & 0x3f))) < 0:
|
|
return -1
|
|
return _write_byte(writer, <uint8_t>(0x80 | (utf & 0x3f)))
|
|
elif utf > 0x10FFFF:
|
|
# symbol is too large
|
|
return 0
|
|
else:
|
|
if _write_byte(writer, <uint8_t>(0xf0 | (utf >> 18))) < 0:
|
|
return -1
|
|
if _write_byte(writer,
|
|
<uint8_t>(0x80 | ((utf >> 12) & 0x3f))) < 0:
|
|
return -1
|
|
if _write_byte(writer,
|
|
<uint8_t>(0x80 | ((utf >> 6) & 0x3f))) < 0:
|
|
return -1
|
|
return _write_byte(writer, <uint8_t>(0x80 | (utf & 0x3f)))
|
|
|
|
|
|
cdef inline int _write_str(Writer* writer, str s):
|
|
cdef Py_UCS4 ch
|
|
for ch in s:
|
|
if _write_utf8(writer, ch) < 0:
|
|
return -1
|
|
|
|
|
|
# --------------- _serialize_headers ----------------------
|
|
|
|
cdef str to_str(object s):
|
|
typ = type(s)
|
|
if typ is str:
|
|
return <str>s
|
|
elif typ is _istr:
|
|
return PyObject_Str(s)
|
|
elif not isinstance(s, str):
|
|
raise TypeError("Cannot serialize non-str key {!r}".format(s))
|
|
else:
|
|
return str(s)
|
|
|
|
|
|
cdef void _safe_header(str string) except *:
|
|
if "\r" in string or "\n" in string:
|
|
raise ValueError(
|
|
"Newline or carriage return character detected in HTTP status message or "
|
|
"header. This is a potential security issue."
|
|
)
|
|
|
|
|
|
def _serialize_headers(str status_line, headers):
|
|
cdef Writer writer
|
|
cdef object key
|
|
cdef object val
|
|
cdef bytes ret
|
|
|
|
_init_writer(&writer)
|
|
|
|
for key, val in headers.items():
|
|
_safe_header(to_str(key))
|
|
_safe_header(to_str(val))
|
|
|
|
try:
|
|
if _write_str(&writer, status_line) < 0:
|
|
raise
|
|
if _write_byte(&writer, b'\r') < 0:
|
|
raise
|
|
if _write_byte(&writer, b'\n') < 0:
|
|
raise
|
|
|
|
for key, val in headers.items():
|
|
if _write_str(&writer, to_str(key)) < 0:
|
|
raise
|
|
if _write_byte(&writer, b':') < 0:
|
|
raise
|
|
if _write_byte(&writer, b' ') < 0:
|
|
raise
|
|
if _write_str(&writer, to_str(val)) < 0:
|
|
raise
|
|
if _write_byte(&writer, b'\r') < 0:
|
|
raise
|
|
if _write_byte(&writer, b'\n') < 0:
|
|
raise
|
|
|
|
if _write_byte(&writer, b'\r') < 0:
|
|
raise
|
|
if _write_byte(&writer, b'\n') < 0:
|
|
raise
|
|
|
|
return PyBytes_FromStringAndSize(writer.buf, writer.pos)
|
|
finally:
|
|
_release_writer(&writer)
|