Publish LumaOps source

This commit is contained in:
LumaOps release export
2026-09-03 01:18:36 +02:00
commit 7f1c0e5f71
2363 changed files with 501543 additions and 0 deletions
+152
View File
@@ -0,0 +1,152 @@
#!/usr/bin/env python3
"""Minimal two-process supervisor with bounded restart and graceful shutdown."""
from __future__ import annotations
import logging
import logging.handlers
import os
import signal
import subprocess
import sys
import threading
import time
from pathlib import Path
STOP = threading.Event()
RUN_DIR = Path("/run/lumaops")
LOG_DIR = Path(os.environ.get("LOGS_DIR", "/logs"))
def configure_logging() -> None:
logging.basicConfig(
level=os.environ.get("LOG_LEVEL", "INFO"),
format="%(asctime)s %(levelname)s supervisor %(message)s",
stream=sys.stdout,
)
def signal_handler(signum: int, _frame: object) -> None:
logging.info("received signal %s; starting graceful shutdown", signum)
STOP.set()
class ManagedProcess:
def __init__(self, name: str, command: list[str], log_name: str) -> None:
self.name = name
self.command = command
self.log_name = log_name
self.process: subprocess.Popen[str] | None = None
self.restarts = 0
self.next_start = 0.0
def start(self) -> None:
if STOP.is_set():
return
logging.info("starting %s", self.name)
self.process = subprocess.Popen( # noqa: S603 - fixed administrator-controlled argv
self.command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
env=os.environ.copy(),
)
(RUN_DIR / f"{self.name}.pid").write_text(str(self.process.pid), encoding="ascii")
threading.Thread(target=self._pump_output, daemon=True, name=f"{self.name}-logs").start()
def _pump_output(self) -> None:
assert self.process is not None and self.process.stdout is not None
handler = logging.handlers.RotatingFileHandler(
LOG_DIR / self.log_name,
maxBytes=int(os.environ.get("LOG_MAX_BYTES", str(10 * 1024 * 1024))),
backupCount=int(os.environ.get("LOG_BACKUP_COUNT", "5")),
encoding="utf-8",
)
handler.setFormatter(logging.Formatter("%(asctime)s %(message)s"))
logger = logging.getLogger(f"process.{self.name}")
logger.handlers = [handler]
logger.propagate = False
logger.setLevel(logging.INFO)
for line in self.process.stdout:
logger.info("%s", line.rstrip())
handler.close()
def poll_and_restart(self) -> None:
if self.process is None:
if time.monotonic() >= self.next_start:
self.start()
return
code = self.process.poll()
if code is None:
if time.monotonic() - self.next_start > 60:
self.restarts = 0
return
logging.error("%s exited with code %s", self.name, code)
(RUN_DIR / f"{self.name}.pid").unlink(missing_ok=True)
self.process = None
delay = min(30.0, 0.5 * (2 ** min(self.restarts, 6)))
self.restarts += 1
self.next_start = time.monotonic() + delay
def terminate(self, timeout: float = 12.0) -> None:
process = self.process
if process is None or process.poll() is not None:
return
logging.info("stopping %s", self.name)
process.send_signal(signal.SIGTERM)
try:
process.wait(timeout=timeout)
except subprocess.TimeoutExpired:
logging.warning("%s did not stop in %.1fs; sending SIGKILL", self.name, timeout)
process.kill()
process.wait(timeout=3)
(RUN_DIR / f"{self.name}.pid").unlink(missing_ok=True)
def main() -> int:
configure_logging()
for sig in (signal.SIGINT, signal.SIGTERM):
signal.signal(sig, signal_handler)
RUN_DIR.mkdir(parents=True, exist_ok=True)
LOG_DIR.mkdir(parents=True, exist_ok=True)
openrgb_config = Path(os.environ.get("OPENRGB_CONFIG_DIR", "/config/openrgb"))
openrgb_config.mkdir(parents=True, exist_ok=True)
port = os.environ.get("OPENRGB_PORT", "6742")
openrgb = ManagedProcess(
"openrgb",
[
"/usr/local/bin/openrgb",
"--server",
"--server-host",
"127.0.0.1",
"--server-port",
port,
"--config",
str(openrgb_config),
"--noautoconnect",
],
"openrgb.log",
)
backend = ManagedProcess(
"backend",
["/opt/venv/bin/python", "-m", "lumaops_backend.main"],
"backend.log",
)
processes = [openrgb, backend]
for process in processes:
process.start()
process.next_start = time.monotonic()
try:
while not STOP.wait(0.5):
for process in processes:
process.poll_and_restart()
finally:
backend.terminate()
openrgb.terminate()
return 0
if __name__ == "__main__":
raise SystemExit(main())