@volter/browser-python 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +14 -0
- package/dist/asgi-bridge.d.ts +3 -0
- package/dist/asgi-bridge.d.ts.map +1 -0
- package/dist/asgi-bridge.js +307 -0
- package/dist/asgi-bridge.js.map +1 -0
- package/dist/command.d.ts +20 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +154 -0
- package/dist/command.js.map +1 -0
- package/dist/filesystem.d.ts +9 -0
- package/dist/filesystem.d.ts.map +1 -0
- package/dist/filesystem.js +96 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/package-manager.d.ts +8 -0
- package/dist/package-manager.d.ts.map +1 -0
- package/dist/package-manager.js +103 -0
- package/dist/package-manager.js.map +1 -0
- package/dist/process-host.d.ts +27 -0
- package/dist/process-host.d.ts.map +1 -0
- package/dist/process-host.js +326 -0
- package/dist/process-host.js.map +1 -0
- package/dist/protocol.d.ts +169 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +2 -0
- package/dist/protocol.js.map +1 -0
- package/dist/pyodide-runtime.d.ts +37 -0
- package/dist/pyodide-runtime.d.ts.map +1 -0
- package/dist/pyodide-runtime.js +13 -0
- package/dist/pyodide-runtime.js.map +1 -0
- package/dist/server-host.d.ts +21 -0
- package/dist/server-host.d.ts.map +1 -0
- package/dist/server-host.js +526 -0
- package/dist/server-host.js.map +1 -0
- package/dist/sqlite-coherence.d.ts +19 -0
- package/dist/sqlite-coherence.d.ts.map +1 -0
- package/dist/sqlite-coherence.js +167 -0
- package/dist/sqlite-coherence.js.map +1 -0
- package/dist/subprocess-bridge.d.ts +12 -0
- package/dist/subprocess-bridge.d.ts.map +1 -0
- package/dist/subprocess-bridge.js +407 -0
- package/dist/subprocess-bridge.js.map +1 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +251 -0
- package/dist/worker.js.map +1 -0
- package/dist/wsgi-bridge.d.ts +21 -0
- package/dist/wsgi-bridge.d.ts.map +1 -0
- package/dist/wsgi-bridge.js +268 -0
- package/dist/wsgi-bridge.js.map +1 -0
- package/package.json +23 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { BrowserFileCoherenceClient, coherentFileFamily, } from "@volter/browser-runtime/browser-file-coherence.js";
|
|
2
|
+
import { BrowserFileLockClient } from "@volter/browser-runtime/browser-file-locks.js";
|
|
3
|
+
/** Serializes unchanged CPython sqlite connections with every browser lane. */
|
|
4
|
+
export class PythonSqliteCoherence {
|
|
5
|
+
filesystem;
|
|
6
|
+
locks;
|
|
7
|
+
coherence;
|
|
8
|
+
counts = new Map();
|
|
9
|
+
owner;
|
|
10
|
+
constructor(filesystem, locks, coherence, ownerPrefix) {
|
|
11
|
+
this.filesystem = filesystem;
|
|
12
|
+
this.locks = locks;
|
|
13
|
+
this.coherence = coherence;
|
|
14
|
+
this.owner = `${ownerPrefix}:sqlite`;
|
|
15
|
+
}
|
|
16
|
+
install(pyodide) {
|
|
17
|
+
pyodide.globals.set("_browser_runtime_sqlite_acquire", (path) => this.acquire(path));
|
|
18
|
+
pyodide.globals.set("_browser_runtime_sqlite_release", (path) => this.release(path));
|
|
19
|
+
return pyodide.runPythonAsync(PYTHON_SQLITE_BOOTSTRAP);
|
|
20
|
+
}
|
|
21
|
+
releaseAll() {
|
|
22
|
+
for (const path of [...this.counts.keys()]) {
|
|
23
|
+
this.counts.set(path, 1);
|
|
24
|
+
this.release(path);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
acquire(path) {
|
|
28
|
+
if (!path.startsWith("/") || path.includes("\0"))
|
|
29
|
+
throw new Error("Invalid SQLite path.");
|
|
30
|
+
const count = this.counts.get(path) ?? 0;
|
|
31
|
+
if (count > 0) {
|
|
32
|
+
this.counts.set(path, count + 1);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const response = this.locks.request({
|
|
36
|
+
operation: "set",
|
|
37
|
+
owner: this.owner,
|
|
38
|
+
namespace: "posix",
|
|
39
|
+
path,
|
|
40
|
+
range: { start: 0 },
|
|
41
|
+
mode: "write",
|
|
42
|
+
pid: 1,
|
|
43
|
+
blocking: true,
|
|
44
|
+
});
|
|
45
|
+
if (response.result < 0)
|
|
46
|
+
throw new Error(`SQLite lock acquisition failed with ${response.result}.`);
|
|
47
|
+
try {
|
|
48
|
+
for (const member of coherentFileFamily(path))
|
|
49
|
+
this.writeLocal(member, this.coherence.pull(member));
|
|
50
|
+
this.counts.set(path, 1);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
this.locks.request({
|
|
54
|
+
operation: "unlock",
|
|
55
|
+
owner: this.owner,
|
|
56
|
+
namespace: "posix",
|
|
57
|
+
path,
|
|
58
|
+
range: { start: 0 },
|
|
59
|
+
});
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
release(path) {
|
|
64
|
+
const count = this.counts.get(path) ?? 0;
|
|
65
|
+
if (count > 1) {
|
|
66
|
+
this.counts.set(path, count - 1);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (count === 0)
|
|
70
|
+
return;
|
|
71
|
+
for (const member of coherentFileFamily(path))
|
|
72
|
+
this.coherence.push(member, this.readLocal(member));
|
|
73
|
+
const response = this.locks.request({
|
|
74
|
+
operation: "unlock",
|
|
75
|
+
owner: this.owner,
|
|
76
|
+
namespace: "posix",
|
|
77
|
+
path,
|
|
78
|
+
range: { start: 0 },
|
|
79
|
+
});
|
|
80
|
+
if (response.result < 0)
|
|
81
|
+
throw new Error(`SQLite lock release failed with ${response.result}.`);
|
|
82
|
+
this.counts.delete(path);
|
|
83
|
+
}
|
|
84
|
+
readLocal(path) {
|
|
85
|
+
if (!this.filesystem.analyzePath(path).exists)
|
|
86
|
+
return;
|
|
87
|
+
const stat = this.filesystem.stat(path);
|
|
88
|
+
if ((stat.mode & 0o170000) === 0o040000)
|
|
89
|
+
return;
|
|
90
|
+
const mtimeMs = stat.mtime instanceof Date ? stat.mtime.getTime() : stat.mtime;
|
|
91
|
+
return {
|
|
92
|
+
bytes: this.filesystem.readFile(path),
|
|
93
|
+
mode: stat.mode & 0o7777,
|
|
94
|
+
...(typeof mtimeMs === "number" && Number.isFinite(mtimeMs) ? { mtimeMs } : {}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
writeLocal(path, file) {
|
|
98
|
+
if (!file) {
|
|
99
|
+
if (this.filesystem.analyzePath(path).exists
|
|
100
|
+
&& (this.filesystem.stat(path).mode & 0o170000) !== 0o040000)
|
|
101
|
+
this.filesystem.unlink(path);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const parent = path.slice(0, path.lastIndexOf("/")) || "/";
|
|
105
|
+
if (!this.filesystem.analyzePath(parent).exists)
|
|
106
|
+
this.filesystem.mkdirTree(parent);
|
|
107
|
+
this.filesystem.writeFile(path, file.bytes);
|
|
108
|
+
if (file.mode !== undefined)
|
|
109
|
+
this.filesystem.chmod(path, file.mode);
|
|
110
|
+
if (file.mtimeMs !== undefined)
|
|
111
|
+
this.filesystem.utime(path, file.mtimeMs, file.mtimeMs);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const PYTHON_SQLITE_BOOTSTRAP = String.raw `
|
|
115
|
+
import os as _browser_runtime_sqlite_os, sqlite3 as _browser_runtime_sqlite
|
|
116
|
+
|
|
117
|
+
_browser_runtime_sqlite_connect_original = _browser_runtime_sqlite.connect
|
|
118
|
+
|
|
119
|
+
def _browser_runtime_sqlite_path(database, uri=False):
|
|
120
|
+
try:
|
|
121
|
+
value = _browser_runtime_sqlite_os.fspath(database)
|
|
122
|
+
except TypeError:
|
|
123
|
+
return None
|
|
124
|
+
if isinstance(value, bytes):
|
|
125
|
+
value = _browser_runtime_sqlite_os.fsdecode(value)
|
|
126
|
+
if value == ":memory:" or value.startswith("file::memory:"):
|
|
127
|
+
return None
|
|
128
|
+
if uri and value.startswith("file:"):
|
|
129
|
+
value = value[5:].split("?", 1)[0]
|
|
130
|
+
return _browser_runtime_sqlite_os.path.abspath(value)
|
|
131
|
+
|
|
132
|
+
class _BrowserRuntimeSqliteConnection(_browser_runtime_sqlite.Connection):
|
|
133
|
+
def __init__(self, *args, **kwargs):
|
|
134
|
+
database = args[0] if args else kwargs.get("database")
|
|
135
|
+
self._browser_runtime_path = _browser_runtime_sqlite_path(database, bool(kwargs.get("uri", False)))
|
|
136
|
+
self._browser_runtime_released = False
|
|
137
|
+
if self._browser_runtime_path:
|
|
138
|
+
_browser_runtime_sqlite_acquire(self._browser_runtime_path)
|
|
139
|
+
try:
|
|
140
|
+
super().__init__(*args, **kwargs)
|
|
141
|
+
except BaseException:
|
|
142
|
+
if self._browser_runtime_path:
|
|
143
|
+
_browser_runtime_sqlite_release(self._browser_runtime_path)
|
|
144
|
+
self._browser_runtime_released = True
|
|
145
|
+
raise
|
|
146
|
+
|
|
147
|
+
def close(self):
|
|
148
|
+
if self._browser_runtime_released:
|
|
149
|
+
return super().close()
|
|
150
|
+
try:
|
|
151
|
+
return super().close()
|
|
152
|
+
finally:
|
|
153
|
+
if self._browser_runtime_path:
|
|
154
|
+
_browser_runtime_sqlite_release(self._browser_runtime_path)
|
|
155
|
+
self._browser_runtime_released = True
|
|
156
|
+
|
|
157
|
+
def _browser_runtime_sqlite_connect(database, *args, **kwargs):
|
|
158
|
+
factory = kwargs.get("factory")
|
|
159
|
+
if factory is not None and factory is not _browser_runtime_sqlite.Connection:
|
|
160
|
+
raise NotImplementedError("custom sqlite connection factories are not yet supported by browser coherence")
|
|
161
|
+
kwargs["factory"] = _BrowserRuntimeSqliteConnection
|
|
162
|
+
return _browser_runtime_sqlite_connect_original(database, *args, **kwargs)
|
|
163
|
+
|
|
164
|
+
_browser_runtime_sqlite.connect = _browser_runtime_sqlite_connect
|
|
165
|
+
_browser_runtime_sqlite.dbapi2.connect = _browser_runtime_sqlite_connect
|
|
166
|
+
`;
|
|
167
|
+
//# sourceMappingURL=sqlite-coherence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-coherence.js","sourceRoot":"","sources":["../src/sqlite-coherence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PyodideRuntime } from "./pyodide-runtime.js";
|
|
2
|
+
/** Synchronous CPython subprocess calls backed by the page's shared process host. */
|
|
3
|
+
export declare class PythonProcessClient {
|
|
4
|
+
private readonly pyodide;
|
|
5
|
+
private readonly port;
|
|
6
|
+
private nextRequestId;
|
|
7
|
+
constructor(pyodide: PyodideRuntime, port: MessagePort);
|
|
8
|
+
private run;
|
|
9
|
+
private exchange;
|
|
10
|
+
}
|
|
11
|
+
export declare const PYTHON_SUBPROCESS_BOOTSTRAP: string;
|
|
12
|
+
//# sourceMappingURL=subprocess-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subprocess-bridge.d.ts","sourceRoot":"","sources":["../src/subprocess-bridge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAO3D,qFAAqF;AACrF,qBAAa,mBAAmB;IAI5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,OAAO,CAAC,aAAa,CAAK;gBAGP,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,WAAW;IAMpC,OAAO,CAAC,GAAG;IA0CX,OAAO,CAAC,QAAQ;CA8BjB;AAED,eAAO,MAAM,2BAA2B,QAuUvC,CAAC"}
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import { restorePythonSnapshot } from "./filesystem.js";
|
|
2
|
+
const RESPONSE_BYTES = 16 * 1024 * 1024;
|
|
3
|
+
const TIMEOUT_MS = 30_000;
|
|
4
|
+
const POPEN_TIMEOUT_MS = 5 * 60_000;
|
|
5
|
+
/** Synchronous CPython subprocess calls backed by the page's shared process host. */
|
|
6
|
+
export class PythonProcessClient {
|
|
7
|
+
pyodide;
|
|
8
|
+
port;
|
|
9
|
+
nextRequestId = 1;
|
|
10
|
+
constructor(pyodide, port) {
|
|
11
|
+
this.pyodide = pyodide;
|
|
12
|
+
this.port = port;
|
|
13
|
+
pyodide.globals.set("__browser_runtime_run_process", (payload) => this.run(payload));
|
|
14
|
+
pyodide.globals.set("__browser_runtime_process_exchange", (payload) => this.exchange(payload));
|
|
15
|
+
}
|
|
16
|
+
run(payload) {
|
|
17
|
+
const request = JSON.parse(payload);
|
|
18
|
+
const controlBuffer = new SharedArrayBuffer(2 * Int32Array.BYTES_PER_ELEMENT);
|
|
19
|
+
const responseBuffer = new SharedArrayBuffer(RESPONSE_BYTES);
|
|
20
|
+
const control = new Int32Array(controlBuffer);
|
|
21
|
+
const requestId = this.nextRequestId++;
|
|
22
|
+
this.port.postMessage({
|
|
23
|
+
type: "process-run",
|
|
24
|
+
requestId,
|
|
25
|
+
...request,
|
|
26
|
+
control: controlBuffer,
|
|
27
|
+
response: responseBuffer,
|
|
28
|
+
});
|
|
29
|
+
const result = Atomics.wait(control, 0, 0, TIMEOUT_MS);
|
|
30
|
+
if (result === "timed-out" || Atomics.load(control, 0) !== 1) {
|
|
31
|
+
this.port.postMessage({ type: "process-cancel", requestId });
|
|
32
|
+
throw new Error("Python subprocess timed out after 30 seconds.");
|
|
33
|
+
}
|
|
34
|
+
const length = Atomics.load(control, 1);
|
|
35
|
+
if (!Number.isSafeInteger(length) || length < 0 || length > responseBuffer.byteLength) {
|
|
36
|
+
throw new Error("Invalid Python subprocess response.");
|
|
37
|
+
}
|
|
38
|
+
// TextDecoder deliberately rejects SAB-backed views. Copy out of shared
|
|
39
|
+
// memory once the host has published the completion state.
|
|
40
|
+
const responseBytes = new Uint8Array(length);
|
|
41
|
+
responseBytes.set(new Uint8Array(responseBuffer, 0, length));
|
|
42
|
+
const response = JSON.parse(new TextDecoder().decode(responseBytes));
|
|
43
|
+
if (response.error)
|
|
44
|
+
throw new Error(response.error);
|
|
45
|
+
if (!response.result || !response.filesystem)
|
|
46
|
+
throw new Error("Incomplete Python subprocess response.");
|
|
47
|
+
restorePythonSnapshot(this.pyodide.FS, response.filesystem);
|
|
48
|
+
return JSON.stringify(response.result);
|
|
49
|
+
}
|
|
50
|
+
exchange(payload) {
|
|
51
|
+
const request = JSON.parse(payload);
|
|
52
|
+
const controlBuffer = new SharedArrayBuffer(2 * Int32Array.BYTES_PER_ELEMENT);
|
|
53
|
+
const responseBuffer = new SharedArrayBuffer(RESPONSE_BYTES);
|
|
54
|
+
const control = new Int32Array(controlBuffer);
|
|
55
|
+
this.port.postMessage({
|
|
56
|
+
...request,
|
|
57
|
+
requestId: this.nextRequestId++,
|
|
58
|
+
control: controlBuffer,
|
|
59
|
+
response: responseBuffer,
|
|
60
|
+
});
|
|
61
|
+
const result = Atomics.wait(control, 0, 0, POPEN_TIMEOUT_MS);
|
|
62
|
+
if (result === "timed-out" || Atomics.load(control, 0) !== 1) {
|
|
63
|
+
throw new Error("Python Popen operation timed out after 5 minutes.");
|
|
64
|
+
}
|
|
65
|
+
const length = Atomics.load(control, 1);
|
|
66
|
+
if (!Number.isSafeInteger(length) || length < 0 || length > responseBuffer.byteLength) {
|
|
67
|
+
throw new Error("Invalid Python Popen response.");
|
|
68
|
+
}
|
|
69
|
+
const responseBytes = new Uint8Array(length);
|
|
70
|
+
responseBytes.set(new Uint8Array(responseBuffer, 0, length));
|
|
71
|
+
const response = JSON.parse(new TextDecoder().decode(responseBytes));
|
|
72
|
+
if (response.filesystem)
|
|
73
|
+
restorePythonSnapshot(this.pyodide.FS, response.filesystem);
|
|
74
|
+
if (response.error)
|
|
75
|
+
throw new Error(response.error);
|
|
76
|
+
return JSON.stringify(response);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export const PYTHON_SUBPROCESS_BOOTSTRAP = String.raw `
|
|
80
|
+
import base64 as __browser_runtime_base64
|
|
81
|
+
import codecs as _browser_runtime_codecs
|
|
82
|
+
import json as __browser_runtime_json
|
|
83
|
+
import os
|
|
84
|
+
import shlex as __browser_runtime_shlex
|
|
85
|
+
import subprocess as __browser_runtime_subprocess
|
|
86
|
+
import sys
|
|
87
|
+
|
|
88
|
+
def __browser_runtime_subprocess_run(args, *, stdin=None, input=None, stdout=None, stderr=None,
|
|
89
|
+
capture_output=False, shell=False, cwd=None, timeout=None,
|
|
90
|
+
check=False, encoding=None, errors=None, text=False, env=None, **kwargs):
|
|
91
|
+
if timeout is not None:
|
|
92
|
+
raise NotImplementedError("browser subprocess timeout is fixed at 30 seconds")
|
|
93
|
+
if kwargs:
|
|
94
|
+
raise NotImplementedError("unsupported browser subprocess options: " + ", ".join(kwargs.keys()))
|
|
95
|
+
if capture_output:
|
|
96
|
+
if stdout is not None or stderr is not None:
|
|
97
|
+
raise ValueError("stdout and stderr arguments may not be used with capture_output")
|
|
98
|
+
stdout = stderr = __browser_runtime_subprocess.PIPE
|
|
99
|
+
if stdin not in (None, __browser_runtime_subprocess.PIPE, __browser_runtime_subprocess.DEVNULL):
|
|
100
|
+
raise NotImplementedError("browser subprocess stdin must be PIPE, DEVNULL, or None")
|
|
101
|
+
if stdout not in (None, __browser_runtime_subprocess.PIPE, __browser_runtime_subprocess.DEVNULL):
|
|
102
|
+
raise NotImplementedError("browser subprocess stdout must be PIPE, DEVNULL, or None")
|
|
103
|
+
if stderr not in (None, __browser_runtime_subprocess.PIPE, __browser_runtime_subprocess.DEVNULL, __browser_runtime_subprocess.STDOUT):
|
|
104
|
+
raise NotImplementedError("browser subprocess stderr must be PIPE, DEVNULL, STDOUT, or None")
|
|
105
|
+
if input is not None and stdin not in (None, __browser_runtime_subprocess.PIPE):
|
|
106
|
+
raise ValueError("stdin argument may not be used with input")
|
|
107
|
+
if isinstance(args, str):
|
|
108
|
+
command = args if shell else __browser_runtime_shlex.join([args])
|
|
109
|
+
else:
|
|
110
|
+
command = __browser_runtime_shlex.join([str(value) for value in args])
|
|
111
|
+
if input is None:
|
|
112
|
+
input_bytes = b""
|
|
113
|
+
elif isinstance(input, str):
|
|
114
|
+
input_bytes = input.encode(encoding or "utf-8", errors or "strict")
|
|
115
|
+
else:
|
|
116
|
+
input_bytes = bytes(input)
|
|
117
|
+
payload = __browser_runtime_json.dumps({
|
|
118
|
+
"command": command,
|
|
119
|
+
"cwd": os.path.abspath(cwd or os.getcwd()),
|
|
120
|
+
"env": {str(key): str(value) for key, value in (env or os.environ).items()},
|
|
121
|
+
"stdinBase64": __browser_runtime_base64.b64encode(input_bytes).decode("ascii"),
|
|
122
|
+
})
|
|
123
|
+
result = __browser_runtime_json.loads(__browser_runtime_run_process(payload))
|
|
124
|
+
use_text = text or encoding is not None or errors is not None
|
|
125
|
+
out_text, err_text = result["stdout"], result["stderr"]
|
|
126
|
+
if stderr == __browser_runtime_subprocess.STDOUT:
|
|
127
|
+
out_text += err_text
|
|
128
|
+
err_text = ""
|
|
129
|
+
if stdout != __browser_runtime_subprocess.PIPE:
|
|
130
|
+
if stdout != __browser_runtime_subprocess.DEVNULL and out_text:
|
|
131
|
+
sys.stdout.write(out_text)
|
|
132
|
+
completed_stdout = None
|
|
133
|
+
else:
|
|
134
|
+
completed_stdout = out_text if use_text else out_text.encode(encoding or "utf-8", errors or "strict")
|
|
135
|
+
if stderr not in (__browser_runtime_subprocess.PIPE, __browser_runtime_subprocess.STDOUT):
|
|
136
|
+
if stderr != __browser_runtime_subprocess.DEVNULL and err_text:
|
|
137
|
+
sys.stderr.write(err_text)
|
|
138
|
+
completed_stderr = None
|
|
139
|
+
else:
|
|
140
|
+
completed_stderr = None if stderr == __browser_runtime_subprocess.STDOUT else (err_text if use_text else err_text.encode(encoding or "utf-8", errors or "strict"))
|
|
141
|
+
completed = __browser_runtime_subprocess.CompletedProcess(args, int(result["exitCode"]), completed_stdout, completed_stderr)
|
|
142
|
+
if check:
|
|
143
|
+
completed.check_returncode()
|
|
144
|
+
return completed
|
|
145
|
+
|
|
146
|
+
def __browser_runtime_subprocess_call(*popenargs, timeout=None, **kwargs):
|
|
147
|
+
return __browser_runtime_subprocess_run(*popenargs, timeout=timeout, **kwargs).returncode
|
|
148
|
+
|
|
149
|
+
def __browser_runtime_subprocess_check_call(*popenargs, **kwargs):
|
|
150
|
+
result = __browser_runtime_subprocess_run(*popenargs, **kwargs)
|
|
151
|
+
result.check_returncode()
|
|
152
|
+
return 0
|
|
153
|
+
|
|
154
|
+
def __browser_runtime_process_command(args, shell):
|
|
155
|
+
if isinstance(args, str):
|
|
156
|
+
return args if shell else __browser_runtime_shlex.join([args])
|
|
157
|
+
return __browser_runtime_shlex.join([str(value) for value in args])
|
|
158
|
+
|
|
159
|
+
def __browser_runtime_process_action(payload):
|
|
160
|
+
return __browser_runtime_json.loads(__browser_runtime_process_exchange(__browser_runtime_json.dumps(payload)))
|
|
161
|
+
|
|
162
|
+
_browser_runtime_base64 = __browser_runtime_base64
|
|
163
|
+
_browser_runtime_process_action = __browser_runtime_process_action
|
|
164
|
+
_browser_runtime_process_command = __browser_runtime_process_command
|
|
165
|
+
_browser_runtime_subprocess = __browser_runtime_subprocess
|
|
166
|
+
|
|
167
|
+
class __browser_runtime_BrowserPipe:
|
|
168
|
+
def __init__(self, process, stream, writable=False):
|
|
169
|
+
self.process = process
|
|
170
|
+
self.stream = stream
|
|
171
|
+
self.writable = writable
|
|
172
|
+
self.closed = False
|
|
173
|
+
self._buffer = "" if self.process.text_mode else bytearray()
|
|
174
|
+
self._decoder = _browser_runtime_codecs.getincrementaldecoder(self.process.encoding)(self.process.errors) if self.process.text_mode else None
|
|
175
|
+
self._eof = False
|
|
176
|
+
|
|
177
|
+
def write(self, value):
|
|
178
|
+
if not self.writable or self.closed:
|
|
179
|
+
raise ValueError("write to closed or read-only browser subprocess pipe")
|
|
180
|
+
raw = value.encode(self.process.encoding, self.process.errors) if isinstance(value, str) else bytes(value)
|
|
181
|
+
result = self.process._action("write", stdinBase64=_browser_runtime_base64.b64encode(raw).decode("ascii"))
|
|
182
|
+
return len(value) if isinstance(value, str) else int(result.get("written", len(raw)))
|
|
183
|
+
|
|
184
|
+
def flush(self):
|
|
185
|
+
if self.closed:
|
|
186
|
+
raise ValueError("flush of closed browser subprocess pipe")
|
|
187
|
+
|
|
188
|
+
def close(self):
|
|
189
|
+
if self.closed:
|
|
190
|
+
return
|
|
191
|
+
self.closed = True
|
|
192
|
+
if self.writable:
|
|
193
|
+
self.process._action("close")
|
|
194
|
+
|
|
195
|
+
def _pull(self, maximum=65536):
|
|
196
|
+
if self.writable or self.closed:
|
|
197
|
+
raise ValueError("read from closed or write-only browser subprocess pipe")
|
|
198
|
+
if self._eof:
|
|
199
|
+
return
|
|
200
|
+
result = self.process._action("read", stream=self.stream, maximum=maximum)
|
|
201
|
+
raw = _browser_runtime_base64.b64decode(result.get("dataBase64", ""))
|
|
202
|
+
self._eof = bool(result.get("eof", False))
|
|
203
|
+
if self.process.text_mode:
|
|
204
|
+
self._buffer += self._decoder.decode(raw, final=self._eof)
|
|
205
|
+
elif raw:
|
|
206
|
+
self._buffer.extend(raw)
|
|
207
|
+
|
|
208
|
+
def read(self, size=-1):
|
|
209
|
+
if size is None or size < 0:
|
|
210
|
+
while not self._eof:
|
|
211
|
+
self._pull()
|
|
212
|
+
value = self._buffer if self.process.text_mode else bytes(self._buffer)
|
|
213
|
+
self._buffer = "" if self.process.text_mode else bytearray()
|
|
214
|
+
return value
|
|
215
|
+
if size == 0:
|
|
216
|
+
return "" if self.process.text_mode else b""
|
|
217
|
+
while not self._buffer and not self._eof:
|
|
218
|
+
self._pull(min(max(size, 1), 1048576))
|
|
219
|
+
count = min(size, len(self._buffer))
|
|
220
|
+
value = self._buffer[:count] if self.process.text_mode else bytes(self._buffer[:count])
|
|
221
|
+
if self.process.text_mode:
|
|
222
|
+
self._buffer = self._buffer[count:]
|
|
223
|
+
else:
|
|
224
|
+
del self._buffer[:count]
|
|
225
|
+
return value
|
|
226
|
+
|
|
227
|
+
def readline(self, size=-1):
|
|
228
|
+
limit = None if size is None or size < 0 else size
|
|
229
|
+
newline_value = "\n" if self.process.text_mode else b"\n"
|
|
230
|
+
while not self._eof and newline_value not in self._buffer and (limit is None or len(self._buffer) < limit):
|
|
231
|
+
self._pull()
|
|
232
|
+
newline = self._buffer.find(newline_value)
|
|
233
|
+
count = len(self._buffer) if newline < 0 else newline + 1
|
|
234
|
+
if limit is not None:
|
|
235
|
+
count = min(count, limit)
|
|
236
|
+
value = self._buffer[:count] if self.process.text_mode else bytes(self._buffer[:count])
|
|
237
|
+
if self.process.text_mode:
|
|
238
|
+
self._buffer = self._buffer[count:]
|
|
239
|
+
else:
|
|
240
|
+
del self._buffer[:count]
|
|
241
|
+
return value
|
|
242
|
+
|
|
243
|
+
def readlines(self, hint=-1):
|
|
244
|
+
lines = []
|
|
245
|
+
total = 0
|
|
246
|
+
while True:
|
|
247
|
+
line = self.readline()
|
|
248
|
+
if not line:
|
|
249
|
+
break
|
|
250
|
+
lines.append(line)
|
|
251
|
+
total += len(line)
|
|
252
|
+
if hint is not None and hint >= 0 and total >= hint:
|
|
253
|
+
break
|
|
254
|
+
return lines
|
|
255
|
+
|
|
256
|
+
def __iter__(self):
|
|
257
|
+
return self
|
|
258
|
+
|
|
259
|
+
def __next__(self):
|
|
260
|
+
line = self.readline()
|
|
261
|
+
if not line:
|
|
262
|
+
raise StopIteration
|
|
263
|
+
return line
|
|
264
|
+
|
|
265
|
+
def __enter__(self):
|
|
266
|
+
return self
|
|
267
|
+
|
|
268
|
+
def __exit__(self, exc_type, value, traceback):
|
|
269
|
+
self.close()
|
|
270
|
+
|
|
271
|
+
_browser_runtime_BrowserPipe = __browser_runtime_BrowserPipe
|
|
272
|
+
|
|
273
|
+
class __browser_runtime_BrowserPopen:
|
|
274
|
+
def __init__(self, args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None,
|
|
275
|
+
preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None,
|
|
276
|
+
universal_newlines=None, startupinfo=None, creationflags=0,
|
|
277
|
+
restore_signals=True, start_new_session=False, pass_fds=(), *, user=None,
|
|
278
|
+
group=None, extra_groups=None, encoding=None, errors=None, text=None,
|
|
279
|
+
umask=-1, pipesize=-1, process_group=None):
|
|
280
|
+
unsupported = {
|
|
281
|
+
"executable": executable, "preexec_fn": preexec_fn, "startupinfo": startupinfo,
|
|
282
|
+
"creationflags": creationflags or None, "start_new_session": start_new_session or None,
|
|
283
|
+
"pass_fds": pass_fds or None, "user": user, "group": group,
|
|
284
|
+
"extra_groups": extra_groups, "umask": None if umask == -1 else umask,
|
|
285
|
+
"pipesize": None if pipesize == -1 else pipesize, "process_group": process_group,
|
|
286
|
+
}
|
|
287
|
+
rejected = [name for name, value in unsupported.items() if value is not None]
|
|
288
|
+
if rejected:
|
|
289
|
+
raise NotImplementedError("unsupported browser Popen options: " + ", ".join(rejected))
|
|
290
|
+
if stdin not in (None, _browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL):
|
|
291
|
+
raise NotImplementedError("browser Popen stdin must be PIPE, DEVNULL, or None")
|
|
292
|
+
if stdout not in (None, _browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL):
|
|
293
|
+
raise NotImplementedError("browser Popen stdout must be PIPE, DEVNULL, or None")
|
|
294
|
+
if stderr not in (None, _browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL, _browser_runtime_subprocess.STDOUT):
|
|
295
|
+
raise NotImplementedError("browser Popen stderr must be PIPE, DEVNULL, STDOUT, or None")
|
|
296
|
+
self.args = args
|
|
297
|
+
self.returncode = None
|
|
298
|
+
self.encoding = encoding or "utf-8"
|
|
299
|
+
self.errors = errors or "strict"
|
|
300
|
+
self.text_mode = bool(text or universal_newlines or encoding is not None or errors is not None)
|
|
301
|
+
self._stdout_mode = stdout
|
|
302
|
+
self._stderr_mode = stderr
|
|
303
|
+
self._stdout = "" if self.text_mode else b""
|
|
304
|
+
self._stderr = "" if self.text_mode else b""
|
|
305
|
+
self._completion = None
|
|
306
|
+
result = _browser_runtime_process_action({
|
|
307
|
+
"type": "process-start",
|
|
308
|
+
"command": _browser_runtime_process_command(args, shell),
|
|
309
|
+
"cwd": os.path.abspath(cwd or os.getcwd()),
|
|
310
|
+
"env": {str(key): str(value) for key, value in (env or os.environ).items()},
|
|
311
|
+
"stdinPipe": stdin == _browser_runtime_subprocess.PIPE,
|
|
312
|
+
"stdoutPipe": stdout == _browser_runtime_subprocess.PIPE,
|
|
313
|
+
"stderrPipe": stderr == _browser_runtime_subprocess.PIPE,
|
|
314
|
+
"stderrToStdout": stderr == _browser_runtime_subprocess.STDOUT,
|
|
315
|
+
})
|
|
316
|
+
self.pid = int(result["childId"])
|
|
317
|
+
self.stdin = _browser_runtime_BrowserPipe(self, "stdin", True) if stdin == _browser_runtime_subprocess.PIPE else None
|
|
318
|
+
self.stdout = _browser_runtime_BrowserPipe(self, "stdout") if stdout == _browser_runtime_subprocess.PIPE else None
|
|
319
|
+
self.stderr = _browser_runtime_BrowserPipe(self, "stderr") if stderr == _browser_runtime_subprocess.PIPE else None
|
|
320
|
+
|
|
321
|
+
def _action(self, action, **values):
|
|
322
|
+
return _browser_runtime_process_action({"type": "process-action", "childId": self.pid, "action": action, **values})
|
|
323
|
+
|
|
324
|
+
def _wait_result(self, input_value=None, close_stdin=False):
|
|
325
|
+
if self._completion is not None:
|
|
326
|
+
return self._completion
|
|
327
|
+
raw_input = b""
|
|
328
|
+
if input_value is not None:
|
|
329
|
+
if self.stdin is None:
|
|
330
|
+
raise ValueError("Cannot send input after starting communication without stdin=PIPE")
|
|
331
|
+
raw_input = input_value.encode(self.encoding, self.errors) if isinstance(input_value, str) else bytes(input_value)
|
|
332
|
+
result = self._action(
|
|
333
|
+
"wait",
|
|
334
|
+
stdinBase64=_browser_runtime_base64.b64encode(raw_input).decode("ascii"),
|
|
335
|
+
closeStdin=close_stdin,
|
|
336
|
+
)
|
|
337
|
+
completed = result["result"]
|
|
338
|
+
self.returncode = int(completed["exitCode"])
|
|
339
|
+
out_text, err_text = completed["stdout"], completed["stderr"]
|
|
340
|
+
if self._stdout_mode == _browser_runtime_subprocess.PIPE:
|
|
341
|
+
self._stdout = ("" if self.text_mode else b"") if self.stdout.closed else self.stdout.read()
|
|
342
|
+
out_text = ""
|
|
343
|
+
else:
|
|
344
|
+
self._stdout = "" if self.text_mode else b""
|
|
345
|
+
if self._stderr_mode == _browser_runtime_subprocess.PIPE:
|
|
346
|
+
self._stderr = ("" if self.text_mode else b"") if self.stderr.closed else self.stderr.read()
|
|
347
|
+
err_text = ""
|
|
348
|
+
else:
|
|
349
|
+
self._stderr = "" if self.text_mode else b""
|
|
350
|
+
if self._stderr_mode == _browser_runtime_subprocess.STDOUT and self._stdout_mode != _browser_runtime_subprocess.PIPE:
|
|
351
|
+
out_text += err_text
|
|
352
|
+
err_text = ""
|
|
353
|
+
if self._stdout_mode not in (_browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL) and out_text:
|
|
354
|
+
sys.stdout.write(out_text)
|
|
355
|
+
if self._stderr_mode not in (_browser_runtime_subprocess.PIPE, _browser_runtime_subprocess.DEVNULL, _browser_runtime_subprocess.STDOUT) and err_text:
|
|
356
|
+
sys.stderr.write(err_text)
|
|
357
|
+
self._completion = completed
|
|
358
|
+
self._action("release")
|
|
359
|
+
return completed
|
|
360
|
+
|
|
361
|
+
def poll(self):
|
|
362
|
+
if self.returncode is None:
|
|
363
|
+
value = self._action("poll").get("returncode")
|
|
364
|
+
if value is not None:
|
|
365
|
+
self.returncode = int(value)
|
|
366
|
+
return self.returncode
|
|
367
|
+
|
|
368
|
+
def wait(self, timeout=None):
|
|
369
|
+
if timeout is not None:
|
|
370
|
+
raise NotImplementedError("browser Popen wait timeout is fixed at five minutes")
|
|
371
|
+
self._wait_result()
|
|
372
|
+
return self.returncode
|
|
373
|
+
|
|
374
|
+
def communicate(self, input=None, timeout=None):
|
|
375
|
+
if timeout is not None:
|
|
376
|
+
raise NotImplementedError("browser Popen communicate timeout is fixed at five minutes")
|
|
377
|
+
self._wait_result(input, self.stdin is not None)
|
|
378
|
+
if self.stdin is not None:
|
|
379
|
+
self.stdin.closed = True
|
|
380
|
+
return (
|
|
381
|
+
self._stdout if self._stdout_mode == _browser_runtime_subprocess.PIPE else None,
|
|
382
|
+
self._stderr if self._stderr_mode == _browser_runtime_subprocess.PIPE else None,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
def terminate(self):
|
|
386
|
+
if self.returncode is None:
|
|
387
|
+
self._action("terminate")
|
|
388
|
+
|
|
389
|
+
kill = terminate
|
|
390
|
+
|
|
391
|
+
def send_signal(self, sig):
|
|
392
|
+
self.terminate()
|
|
393
|
+
|
|
394
|
+
def __enter__(self):
|
|
395
|
+
return self
|
|
396
|
+
|
|
397
|
+
def __exit__(self, exc_type, value, traceback):
|
|
398
|
+
if self.stdin is not None and not self.stdin.closed:
|
|
399
|
+
self.stdin.close()
|
|
400
|
+
self.wait()
|
|
401
|
+
|
|
402
|
+
__browser_runtime_subprocess.run = __browser_runtime_subprocess_run
|
|
403
|
+
__browser_runtime_subprocess.call = __browser_runtime_subprocess_call
|
|
404
|
+
__browser_runtime_subprocess.check_call = __browser_runtime_subprocess_check_call
|
|
405
|
+
__browser_runtime_subprocess.Popen = __browser_runtime_BrowserPopen
|
|
406
|
+
`;
|
|
407
|
+
//# sourceMappingURL=subprocess-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subprocess-bridge.js","sourceRoot":"","sources":["../src/subprocess-bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":""}
|