js: support spawn jsapi

This commit is contained in:
weishu
2024-02-23 00:16:04 +08:00
parent d02855a40a
commit 77d16ac896
3 changed files with 234 additions and 25 deletions

View File

@@ -10,12 +10,12 @@ yarn add kernelsu
### exec
Execute a command in the **root** shell.
Spawns a **root** shell and runs a command within that shell, passing the `stdout` and `stderr` to a Promise when complete.
options:
- `cwd` - Current working directory of the child process
- `env` - Environment key-value pairs
- `command` `<string>` The command to run, with space-separated arguments.
- `options` `<Object>`
- `cwd` - Current working directory of the child process
- `env` - Environment key-value pairs
```javascript
import { exec } from 'kernelsu';
@@ -27,6 +27,71 @@ if (errno === 0) {
}
```
### spawn
Spawns a new process using the given `command` in **root** shell, with command-line arguments in `args`. If omitted, `args` defaults to an empty array.
Returns a `ChildProcess`, Instances of the ChildProcess represent spawned child processes.
- `command` `<string>` The command to run.
- `args` `<string[]>` List of string arguments.
- `options` `<Object>`:
- `cwd` `<string>` - Current working directory of the child process
- `env` `<Object>` - Environment key-value pairs
Example of running `ls -lh /data`, capturing `stdout`, `stderr`, and the exit code:
```javascript
import { spawn } from 'kernelsu';
const ls = spawn('ls', ['-lh', '/data']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
ls.on('exit', (code) => {
console.log(`child process exited with code ${code}`);
});
```
#### ChildProcess
##### Event 'exit'
- `code` `<number>` The exit code if the child exited on its own.
The `'exit'` event is emitted after the child process ends. If the process exited, `code` is the final exit code of the process, otherwise null
##### Event 'error'
- `err` `<Error>` The error.
The `'error'` event is emitted whenever:
- The process could not be spawned.
- The process could not be killed.
##### `stdout`
A `Readable Stream` that represents the child process's `stdout`.
```javascript
const subprocess = spawn('ls');
subprocess.stdout.on('data', (data) => {
console.log(`Received chunk ${data}`);
});
```
#### `stderr`
A `Readable Stream` that represents the child process's `stderr`.
### fullScreen
Request the WebView enter/exit full screen.

View File

@@ -1,6 +1,6 @@
let callbackCounter = 0;
function getUniqueCallbackName() {
return `_callback_${Date.now()}_${callbackCounter++}`;
function getUniqueCallbackName(prefix) {
return `${prefix}_callback_${Date.now()}_${callbackCounter++}`;
}
export function exec(command, options) {
@@ -10,7 +10,7 @@ export function exec(command, options) {
return new Promise((resolve, reject) => {
// Generate a unique callback function name
const callbackFuncName = getUniqueCallbackName();
const callbackFuncName = getUniqueCallbackName("exec");
// Define the success callback function
window[callbackFuncName] = (errno, stdout, stderr) => {
@@ -23,11 +23,7 @@ export function exec(command, options) {
}
try {
ksu.exec(
command,
JSON.stringify(options),
callbackFuncName,
);
ksu.exec(command, JSON.stringify(options), callbackFuncName);
} catch (error) {
reject(error);
cleanup(callbackFuncName);
@@ -35,6 +31,73 @@ export function exec(command, options) {
});
}
function Stdio() {
this.listeners = {};
}
Stdio.prototype.on = function (event, listener) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(listener);
};
Stdio.prototype.emit = function (event, ...args) {
if (this.listeners[event]) {
this.listeners[event].forEach((listener) => listener(...args));
}
};
function ChildProcess() {
this.listeners = {};
this.stdin = new Stdio();
this.stdout = new Stdio();
this.stderr = new Stdio();
}
ChildProcess.prototype.on = function (event, listener) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(listener);
};
ChildProcess.prototype.emit = function (event, ...args) {
if (this.listeners[event]) {
this.listeners[event].forEach((listener) => listener(...args));
}
};
export function spawn(command, args, options) {
if (typeof args === "undefined") {
args = [];
}
if (typeof options === "undefined") {
options = {};
}
const child = new ChildProcess();
const childCallbackName = getUniqueCallbackName("spawn");
window[childCallbackName] = child;
function cleanup(name) {
delete window[name];
}
try {
ksu.spawn(
command,
JSON.stringify(args),
JSON.stringify(options),
childCallbackName
);
} catch (error) {
child.emit("error", error);
cleanup(childCallbackName);
}
return child;
}
export function fullScreen(isFullScreen) {
ksu.fullScreen(isFullScreen);
}