mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-06 12:33:51 +08:00
87 lines
3.4 KiB
Python
87 lines
3.4 KiB
Python
"""Unprivileged manager process; a closed pipe revokes the root worker's lease."""
|
|
import json
|
|
import os
|
|
import select
|
|
import signal
|
|
import subprocess
|
|
import threading
|
|
import time
|
|
|
|
from openpilot.starpilot.galaxy.hotspot import HotspotSettings, STATUS_PATH, atomic_json
|
|
from openpilot.starpilot.system.pipe_worker import spawn
|
|
|
|
|
|
def main():
|
|
from openpilot.common.hardware import PC
|
|
if PC or os.environ.get('OPENPILOT_PREFIX'):
|
|
raise RuntimeError('Hotspot requires the primary comma instance')
|
|
settings = HotspotSettings()
|
|
stop = threading.Event()
|
|
signal.signal(signal.SIGINT, lambda *_: stop.set())
|
|
signal.signal(signal.SIGTERM, lambda *_: stop.set())
|
|
child, revision, buffer, last_reply = None, None, b'', 0.0
|
|
runtime = {'active': False, 'state': 'disabled', 'reason': ''}
|
|
try:
|
|
while not stop.is_set():
|
|
try:
|
|
config = settings.read()
|
|
revision = settings.revision(config)
|
|
if not config['enabled']:
|
|
if child is not None:
|
|
child.stdin.close()
|
|
child.wait(timeout=20)
|
|
child.stdout.close()
|
|
child = None
|
|
runtime = {'active': False, 'state': 'disabled', 'reason': ''}
|
|
else:
|
|
if child is None:
|
|
child = spawn('starpilot-galaxy-hotspot', 'openpilot.starpilot.galaxy.hotspot_worker')
|
|
buffer = b''
|
|
last_reply = time.monotonic()
|
|
runtime = {'active': False, 'state': 'starting', 'reason': 'Starting hotspot service.'}
|
|
if child.poll() is not None:
|
|
raise RuntimeError('Worker exited')
|
|
child.stdin.write(json.dumps(config).encode() + b'\n')
|
|
child.stdin.flush()
|
|
stdout = child.stdout
|
|
if stdout is None:
|
|
raise RuntimeError('Worker output pipe unavailable')
|
|
if select.select([stdout], [], [], 1)[0]:
|
|
data = os.read(stdout.fileno(), 4097)
|
|
if not data:
|
|
raise RuntimeError('Worker disconnected')
|
|
buffer += data
|
|
if len(buffer) > 4096:
|
|
raise ValueError('Oversized status')
|
|
while b'\n' in buffer:
|
|
line, buffer = buffer.split(b'\n', 1)
|
|
runtime = json.loads(line)
|
|
last_reply = time.monotonic()
|
|
if time.monotonic() - last_reply > 20:
|
|
raise RuntimeError('Worker unresponsive')
|
|
atomic_json(STATUS_PATH, {**runtime, 'revision': runtime.get('revision', revision), 'updated': time.monotonic()})
|
|
except (OSError, ValueError, RuntimeError, subprocess.SubprocessError):
|
|
if child is not None:
|
|
if not child.stdin.closed:
|
|
child.stdin.close()
|
|
try:
|
|
child.wait(timeout=20)
|
|
except subprocess.TimeoutExpired:
|
|
# Lease expiry is enforced independently inside the privileged worker.
|
|
pass
|
|
child.stdout.close()
|
|
child = None
|
|
atomic_json(STATUS_PATH, {'active': False, 'state': 'error', 'reason': 'Hotspot service unavailable.',
|
|
'revision': revision, 'updated': time.monotonic()})
|
|
stop.wait(15)
|
|
stop.wait(2)
|
|
finally:
|
|
if child is not None and not child.stdin.closed:
|
|
child.stdin.close()
|
|
atomic_json(STATUS_PATH, {'active': False, 'state': 'disabled', 'reason': 'Hotspot service stopped.',
|
|
'revision': revision, 'updated': time.monotonic()})
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|