mate_ipc.py
python · 36 lines · Exact bytes
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