mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-26 19:47:42 +00:00
95 lines
4.4 KiB
Python
95 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Run only the standalone NSURLSession probe, against a loopback HTTP fixture.
|
|
|
|
Uses a fresh private DPREFIX and never shuts down the user's normal prefix.
|
|
No Riot processes, account data, client APIs or client input are used.
|
|
"""
|
|
import argparse
|
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import socket
|
|
import subprocess
|
|
import tempfile
|
|
from threading import Thread
|
|
import time
|
|
|
|
root = Path(__file__).resolve().parents[1]
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('--probe', type=Path, default=root / 'build/riot-urlsession-check')
|
|
parser.add_argument('--frameworks', type=Path, help='Host directory containing the installed framework overlays')
|
|
parser.add_argument('--libraries', type=Path, help='Host directory containing the installed dylib overlays')
|
|
parser.add_argument('--log', type=Path, default=root / 'build/urlsession-check.log')
|
|
args = parser.parse_args()
|
|
if not args.probe.is_file():
|
|
parser.error('build the probe first')
|
|
config_file = root / 'build/config.json'
|
|
config = json.loads(config_file.read_text()) if config_file.exists() else {}
|
|
guest_user = config.get('guest_user', os.environ.get('USER', ''))
|
|
runtime = Path.home() / '.darling/Users' / guest_user
|
|
frameworks = args.frameworks or runtime / 'RuntimeFrameworks'
|
|
libraries = args.libraries or runtime / 'RuntimeLibraries'
|
|
|
|
|
|
class Fixture(BaseHTTPRequestHandler):
|
|
def do_GET(self):
|
|
time.sleep(0.05) # Ensure finishTasksAndInvalidate sees an in-flight task.
|
|
body = b'darling-session-ok'
|
|
self.send_response(200)
|
|
self.send_header('Content-Length', str(len(body)))
|
|
self.end_headers()
|
|
self.wfile.write(body)
|
|
|
|
def log_message(self, *unused):
|
|
pass
|
|
|
|
|
|
server = ThreadingHTTPServer(('127.0.0.1', 0), Fixture)
|
|
reserved = socket.socket()
|
|
reserved.bind(('127.0.0.1', 0)) # Reserved but not listening: deterministic connection refusal.
|
|
Thread(target=server.serve_forever, daemon=True).start()
|
|
(root / 'build').mkdir(exist_ok=True)
|
|
# Darling initializes account/configuration files only for an absent prefix.
|
|
# Reserve its private parent, not DPREFIX itself.
|
|
private_root = Path(tempfile.mkdtemp(prefix='urlsession-', dir=root / 'build'))
|
|
prefix = private_root / 'prefix'
|
|
env = {key: os.environ[key] for key in ('PATH', 'HOME', 'USER', 'LOGNAME', 'DISPLAY',
|
|
'XAUTHORITY', 'XDG_RUNTIME_DIR', 'DBUS_SESSION_BUS_ADDRESS', 'LANG') if key in os.environ}
|
|
env.update(DPREFIX=str(prefix), EGL_PLATFORM='x11', LC_ALL='en_US.UTF-8')
|
|
log = args.log
|
|
result = None
|
|
try:
|
|
with log.open('w') as stream:
|
|
os.chmod(log, 0o600)
|
|
# Apply overlays to the probe only, after the private namespace boots.
|
|
# launchd/shellspawn must start against the installed base runtime.
|
|
result = subprocess.run(['darling', 'shell', 'env',
|
|
'DYLD_FRAMEWORK_PATH=/Volumes/SystemRoot' + str(frameworks.resolve()),
|
|
'DYLD_LIBRARY_PATH=/Volumes/SystemRoot' + str(libraries.resolve()),
|
|
'/Volumes/SystemRoot' + str(args.probe.resolve()),
|
|
f'http://127.0.0.1:{server.server_port}/payload',
|
|
f'http://127.0.0.1:{reserved.getsockname()[1]}/payload'],
|
|
env=env, stdout=stream, stderr=subprocess.STDOUT, timeout=90)
|
|
text = log.read_text(errors='replace')
|
|
for line in text.splitlines():
|
|
if line.startswith(('LIFECYCLE_PASS:', 'URLSESSION_PASS:', 'SHARED_SESSION_PASS:', 'QUEUE_PASS:',
|
|
'LIFECYCLE_FAIL', 'SHARED_SESSION_FAIL', 'QUEUE_FAIL', 'FAIL ', 'TIMEOUT')):
|
|
print(line)
|
|
required = ('LIFECYCLE_PASS:', 'URLSESSION_PASS:', 'SHARED_SESSION_PASS:', 'QUEUE_PASS:')
|
|
if result.returncode or not all(marker in text for marker in required):
|
|
raise SystemExit(f'Probe failed (exit {result.returncode}); inspect private log {log}')
|
|
finally:
|
|
server.shutdown()
|
|
server.server_close()
|
|
reserved.close()
|
|
try:
|
|
stopped = subprocess.run(['darling', 'shutdown'], env=env, capture_output=True, timeout=25)
|
|
if stopped.returncode == 0:
|
|
shutil.rmtree(private_root)
|
|
else:
|
|
print('Private test artifacts retained for inspection:', private_root)
|
|
except (OSError, subprocess.SubprocessError):
|
|
print('Private test artifacts retained for inspection:', private_root)
|