LittlePlyResearch notebook

mate_ipc.py

python · 36 lines · Exact bytes

Line 1 ↗
Version & provenance · service-foundation-dc8989b92ba1

Recorded SHA-256 8ec15d549dd9cd7f678e4d7cb82b39d3c439572b1b139860e30202ffac844c87Rendered SHA-256 8ec15d549dd9cd7f678e4d7cb82b39d3c439572b1b139860e30202ffac844c87

Service code retains Apache-2.0; the Rust helper component and its adapters are distributed with GPL-3.0-or-later notices and corresponding source. Dependencies retain their own licenses. License notes. Line links are stable within this snapshot. Exact allowlisted files from active release 857bc93bfffb-dc8989b92ba1, verified against its manifest. Service files originate under lichess_service/; helper adapter files at release root. No launcher, account state, credentials or private game logs. Complete GPL helper source is separately downloadable.

1"""Bounded native helper IPC. No unbounded communicate buffers or worker threads."""
2import os,selectors,subprocess,time
3MAX_STDOUT=2*1024*1024
4MAX_STDERR=16*1024
5
6def invoke(binary,payload,deadline,pass_fds=()):
7    proc=subprocess.Popen([str(binary)],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,pass_fds=pass_fds)
8    output=bytearray();errors=bytearray();pending=memoryview(payload.encode('utf-8'))
9    try:
10        with selectors.DefaultSelector() as sel:
11            for pipe,event in ((proc.stdin,selectors.EVENT_WRITE),(proc.stdout,selectors.EVENT_READ),(proc.stderr,selectors.EVENT_READ)):
12                os.set_blocking(pipe.fileno(),False);sel.register(pipe,event)
13            while sel.get_map():
14                remaining=deadline-time.monotonic()
15                if remaining<=0:raise TimeoutError
16                for key,_ in sel.select(remaining):
17                    pipe=key.fileobj
18                    if pipe is proc.stdin:
19                        try:n=os.write(pipe.fileno(),pending)
20                        except BrokenPipeError:n=len(pending)
21                        pending=pending[n:]
22                        if not pending:sel.unregister(pipe);pipe.close()
23                    else:
24                        chunk=os.read(pipe.fileno(),65536)
25                        if not chunk:sel.unregister(pipe);pipe.close();continue
26                        buf,cap=(output,MAX_STDOUT) if pipe is proc.stdout else (errors,MAX_STDERR)
27                        if len(buf)+len(chunk)>cap:raise OverflowError('backend output limit')
28                        buf.extend(chunk)
29            proc.wait(timeout=max(.001,deadline-time.monotonic()))
30        return proc.returncode,output.decode('utf-8')
31    except subprocess.TimeoutExpired:raise TimeoutError
32    finally:
33        if proc.poll() is None:proc.kill()
34        proc.wait()
35        for pipe in (proc.stdin,proc.stdout,proc.stderr):pipe.close()
36