Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-09 10:47:22

0001 #!/usr/bin/env python3
0002 """Check a deployed ES page and capture its first core plot in Chromium."""
0003 import argparse
0004 import json
0005 import os
0006 from pathlib import Path
0007 import re
0008 import shlex
0009 import subprocess
0010 import tempfile
0011 import time
0012 
0013 import requests
0014 import websocket
0015 
0016 
0017 def credentials():
0018     wanted = ('SWF_REMOTE_CLAUDE_USER', 'SWF_REMOTE_CLAUDE_PASSWORD')
0019     values = {key: os.environ.get(key) for key in wanted}
0020     for line in (Path.home() / '.env').read_text().splitlines():
0021         key, separator, value = line.strip().removeprefix('export ').partition('=')
0022         if separator and key in wanted and not values[key]:
0023             parts = shlex.split(value, comments=True)
0024             if len(parts) != 1:
0025                 raise RuntimeError('Cannot parse the configured login field ' + key)
0026             values[key] = parts[0]
0027     if not all(values.values()):
0028         raise RuntimeError('The configured read-only browser login is incomplete')
0029     return values
0030 
0031 
0032 def main():
0033     parser = argparse.ArgumentParser(description=__doc__)
0034     parser.add_argument('--url', required=True)
0035     parser.add_argument('--output', type=Path, required=True)
0036     parser.add_argument('--expect', default='Unit occupancy')
0037     args = parser.parse_args()
0038     session = requests.Session()
0039     response = session.get(args.url, timeout=40)
0040     response.raise_for_status()
0041     if args.expect not in response.text:
0042         token = re.search(r'name=["\']csrfmiddlewaretoken["\']\s+value=["\']([^"\']+)', response.text)
0043         if token is None:
0044             raise RuntimeError('The requested page has neither the expected marker nor a login form')
0045         auth = credentials()
0046         response = session.post(response.url, data={
0047             'username': auth['SWF_REMOTE_CLAUDE_USER'],
0048             'password': auth['SWF_REMOTE_CLAUDE_PASSWORD'],
0049             'csrfmiddlewaretoken': token.group(1), 'next': args.url},
0050             headers={'Referer': response.url}, timeout=40)
0051         response.raise_for_status()
0052     if args.expect not in response.text:
0053         raise RuntimeError('The deployed page did not contain the expected marker after login')
0054     args.output.parent.mkdir(parents=True, exist_ok=True)
0055     executable = sorted((Path.home() / '.cache/ms-playwright').glob(
0056         'chromium_headless_shell-*/chrome-headless-shell-linux64/chrome-headless-shell'))[-1]
0057     with tempfile.TemporaryDirectory(prefix='es-browser-', dir='/data/swf-tmp') as profile:
0058         process = subprocess.Popen([str(executable), '--no-sandbox', '--disable-gpu',
0059             '--remote-debugging-port=0', '--remote-allow-origins=*',
0060             '--user-data-dir=' + profile, 'about:blank'],
0061             stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
0062         try:
0063             active = Path(profile) / 'DevToolsActivePort'
0064             deadline = time.monotonic() + 15
0065             while not active.exists():
0066                 if process.poll() is not None or time.monotonic() > deadline:
0067                     raise RuntimeError('Chromium did not expose its local inspection endpoint')
0068                 time.sleep(.1)
0069             port = active.read_text().splitlines()[0]
0070             page = requests.get('http://127.0.0.1:' + port + '/json/list', timeout=10).json()[0]
0071             connection = websocket.create_connection(page['webSocketDebuggerUrl'], timeout=30)
0072             sequence = 0
0073 
0074             def call(method, params=None):
0075                 nonlocal sequence
0076                 sequence += 1
0077                 connection.send(json.dumps({'id': sequence, 'method': method, 'params': params or {}}))
0078                 while True:
0079                     answer = json.loads(connection.recv())
0080                     if answer.get('id') == sequence:
0081                         if answer.get('error'):
0082                             raise RuntimeError('Browser inspection failed for ' + method)
0083                         return answer.get('result', {})
0084 
0085             call('Network.enable')
0086             call('Network.setCookies', {'cookies': [
0087                 {'name': c.name, 'value': c.value, 'domain': c.domain,
0088                  'path': c.path, 'secure': c.secure} for c in session.cookies]})
0089             call('Page.enable')
0090             call('Emulation.setDeviceMetricsOverride',
0091                  {'width': 1600, 'height': 1200, 'deviceScaleFactor': 1, 'mobile': False})
0092             call('Page.navigate', {'url': args.url})
0093             deadline = time.monotonic() + 30
0094             expression = ('document.readyState === "complete" && document.body.innerText.includes('
0095                           + json.dumps(args.expect) + ')')
0096             while not call('Runtime.evaluate', {'expression': expression})['result'].get('value'):
0097                 if time.monotonic() > deadline:
0098                     raise RuntimeError('The authenticated browser did not render the expected page')
0099                 time.sleep(.25)
0100             box = call('Runtime.evaluate', {'returnByValue': True, 'expression':
0101                 '(()=>{const e=document.querySelector(\'svg[aria-label="core occupancy"]\');'
0102                 'if(!e)return null;const r=e.getBoundingClientRect();return {x:Math.max(0,r.x-20),'
0103                 'y:Math.max(0,r.y+window.scrollY-145),width:r.width+40,height:r.height+420,scale:1}})()'
0104                 })['result'].get('value')
0105             if not box:
0106                 raise RuntimeError('The deployed page has no rendered core plot')
0107             import base64
0108             capture = call('Page.captureScreenshot', {'format': 'png', 'captureBeyondViewport': True, 'clip': box})
0109             args.output.write_bytes(base64.b64decode(capture['data']))
0110             connection.close()
0111             print(json.dumps({'url': args.url, 'expected_marker': args.expect,
0112                               'screenshot': str(args.output), 'status': 'passed'}))
0113         finally:
0114             process.terminate()
0115             process.wait(timeout=10)
0116 
0117 
0118 if __name__ == '__main__':
0119     main()