mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-04 18:29:23 +02:00
refactor(stream): move streams to new package
This commit is contained in:
parent
ce8f062e96
commit
6887d8549f
87 changed files with 985 additions and 811 deletions
131
libraries/adb/src/commands/subprocess/command.ts
Normal file
131
libraries/adb/src/commands/subprocess/command.ts
Normal file
|
@ -0,0 +1,131 @@
|
|||
import { GatherStringStream, DecodeUtf8Stream } from '@yume-chan/stream-extra';
|
||||
|
||||
import { AdbCommandBase } from '../base.js';
|
||||
import { AdbSubprocessNoneProtocol, AdbSubprocessProtocol, AdbSubprocessProtocolConstructor, AdbSubprocessShellProtocol } from './protocols/index.js';
|
||||
|
||||
export interface AdbSubprocessOptions {
|
||||
/**
|
||||
* A list of `AdbSubprocessProtocolConstructor`s to be used.
|
||||
*
|
||||
* Different `AdbSubprocessProtocol` has different capabilities, thus requires specific adaptations.
|
||||
* Check their documentations for details.
|
||||
*
|
||||
* The first protocol whose `isSupported` returns `true` will be used.
|
||||
* If no `AdbSubprocessProtocol` is supported, an error will be thrown.
|
||||
*
|
||||
* @default [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol]
|
||||
*/
|
||||
protocols: AdbSubprocessProtocolConstructor[];
|
||||
}
|
||||
|
||||
const DEFAULT_OPTIONS: AdbSubprocessOptions = {
|
||||
protocols: [AdbSubprocessShellProtocol, AdbSubprocessNoneProtocol],
|
||||
};
|
||||
|
||||
export interface AdbSubprocessWaitResult {
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
exitCode: number;
|
||||
}
|
||||
|
||||
export class AdbSubprocess extends AdbCommandBase {
|
||||
private async createProtocol(
|
||||
mode: 'pty' | 'raw',
|
||||
command?: string | string[],
|
||||
options?: Partial<AdbSubprocessOptions>
|
||||
): Promise<AdbSubprocessProtocol> {
|
||||
const { protocols } = { ...DEFAULT_OPTIONS, ...options };
|
||||
|
||||
let Constructor: AdbSubprocessProtocolConstructor | undefined;
|
||||
for (const item of protocols) {
|
||||
// It's async so can't use `Array#find`
|
||||
if (await item.isSupported(this.adb)) {
|
||||
Constructor = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Constructor) {
|
||||
throw new Error('No specified protocol is supported by the device');
|
||||
}
|
||||
|
||||
if (Array.isArray(command)) {
|
||||
command = command.join(' ');
|
||||
} else if (command === undefined) {
|
||||
// spawn the default shell
|
||||
command = '';
|
||||
}
|
||||
return await Constructor[mode](this.adb, command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns an executable in PTY (interactive) mode.
|
||||
* @param command The command to run. If omitted, the default shell will be spawned.
|
||||
* @param options The options for creating the `AdbSubprocessProtocol`
|
||||
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
||||
*/
|
||||
public shell(
|
||||
command?: string | string[],
|
||||
options?: Partial<AdbSubprocessOptions>
|
||||
): Promise<AdbSubprocessProtocol> {
|
||||
return this.createProtocol('pty', command, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns an executable and pipe the output.
|
||||
* @param command The command to run, or an array of strings containing both command and args.
|
||||
* @param options The options for creating the `AdbSubprocessProtocol`
|
||||
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
||||
*/
|
||||
public spawn(
|
||||
command: string | string[],
|
||||
options?: Partial<AdbSubprocessOptions>
|
||||
): Promise<AdbSubprocessProtocol> {
|
||||
return this.createProtocol('raw', command, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns a new process, waits until it exits, and returns the entire output.
|
||||
* @param command The command to run
|
||||
* @param options The options for creating the `AdbSubprocessProtocol`
|
||||
* @returns The entire output of the command
|
||||
*/
|
||||
public async spawnAndWait(
|
||||
command: string | string[],
|
||||
options?: Partial<AdbSubprocessOptions>
|
||||
): Promise<AdbSubprocessWaitResult> {
|
||||
const shell = await this.spawn(command, options);
|
||||
|
||||
const stdout = new GatherStringStream();
|
||||
const stderr = new GatherStringStream();
|
||||
|
||||
const [, , exitCode] = await Promise.all([
|
||||
shell.stdout
|
||||
.pipeThrough(new DecodeUtf8Stream())
|
||||
.pipeTo(stdout),
|
||||
shell.stderr
|
||||
.pipeThrough(new DecodeUtf8Stream())
|
||||
.pipeTo(stderr),
|
||||
shell.exit
|
||||
]);
|
||||
|
||||
return {
|
||||
stdout: stdout.result,
|
||||
stderr: stderr.result,
|
||||
exitCode,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns a new process, waits until it exits, and returns the entire output.
|
||||
* @param command The command to run
|
||||
* @returns The entire output of the command
|
||||
*/
|
||||
public async spawnAndWaitLegacy(command: string | string[]): Promise<string> {
|
||||
const { stdout } = await this.spawnAndWait(
|
||||
command,
|
||||
{ protocols: [AdbSubprocessNoneProtocol] }
|
||||
);
|
||||
return stdout;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue