@yume-chan/adb 0.0.17 → 0.0.19
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/CHANGELOG.json +27 -0
- package/CHANGELOG.md +16 -1
- package/LICENSE +1 -1
- package/esm/adb.d.ts +63 -60
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +257 -229
- package/esm/adb.js.map +1 -1
- package/esm/auth.d.ts +51 -51
- package/esm/auth.d.ts.map +1 -1
- package/esm/auth.js +95 -96
- package/esm/auth.js.map +1 -1
- package/esm/backend.d.ts +8 -8
- package/esm/backend.d.ts.map +1 -1
- package/esm/backend.js +1 -1
- package/esm/commands/base.d.ts +6 -6
- package/esm/commands/base.js +8 -8
- package/esm/commands/framebuffer.d.ts +53 -53
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +46 -47
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/index.d.ts +7 -8
- package/esm/commands/index.d.ts.map +1 -1
- package/esm/commands/index.js +7 -8
- package/esm/commands/index.js.map +1 -1
- package/esm/commands/install.d.ts +9 -3
- package/esm/commands/install.d.ts.map +1 -1
- package/esm/commands/install.js +27 -21
- package/esm/commands/install.js.map +1 -1
- package/esm/commands/power.d.ts +22 -22
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js +48 -44
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts +41 -28
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +125 -98
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +57 -51
- package/esm/commands/subprocess/command.d.ts.map +1 -1
- package/esm/commands/subprocess/command.js +86 -82
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/index.d.ts +3 -3
- package/esm/commands/subprocess/index.js +3 -3
- package/esm/commands/subprocess/protocols/index.d.ts +3 -3
- package/esm/commands/subprocess/protocols/index.js +3 -3
- package/esm/commands/subprocess/protocols/none.d.ts +35 -35
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +65 -55
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +39 -38
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +166 -154
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +49 -49
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/types.js +1 -1
- package/esm/commands/subprocess/utils.d.ts +1 -1
- package/esm/commands/subprocess/utils.js +18 -18
- package/esm/commands/sync/index.d.ts +8 -7
- package/esm/commands/sync/index.d.ts.map +1 -1
- package/esm/commands/sync/index.js +8 -7
- package/esm/commands/sync/index.js.map +1 -1
- package/esm/commands/sync/list.d.ts +42 -40
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +67 -35
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +13 -11
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +35 -36
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +46 -7
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +89 -23
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +26 -23
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +40 -42
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +19 -19
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +54 -54
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +27 -0
- package/esm/commands/sync/socket.d.ts.map +1 -0
- package/esm/commands/sync/socket.js +66 -0
- package/esm/commands/sync/socket.js.map +1 -0
- package/esm/commands/sync/stat.d.ts +72 -72
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +116 -94
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +72 -60
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +127 -148
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +5 -5
- package/esm/commands/tcpip.js +18 -18
- package/esm/crypto.d.ts +36 -36
- package/esm/crypto.d.ts.map +1 -1
- package/esm/crypto.js +248 -238
- package/esm/crypto.js.map +1 -1
- package/esm/features.d.ts +10 -7
- package/esm/features.d.ts.map +1 -1
- package/esm/features.js +13 -10
- package/esm/features.js.map +1 -1
- package/esm/index.d.ts +9 -9
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +9 -9
- package/esm/index.js.map +1 -1
- package/esm/packet.d.ts +45 -46
- package/esm/packet.d.ts.map +1 -1
- package/esm/packet.js +43 -46
- package/esm/packet.js.map +1 -1
- package/esm/socket/dispatcher.d.ts +59 -59
- package/esm/socket/dispatcher.d.ts.map +1 -1
- package/esm/socket/dispatcher.js +223 -231
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/socket/index.d.ts +2 -2
- package/esm/socket/index.js +2 -2
- package/esm/socket/socket.d.ts +59 -59
- package/esm/socket/socket.d.ts.map +1 -1
- package/esm/socket/socket.js +118 -98
- package/esm/socket/socket.js.map +1 -1
- package/esm/utils/auto-reset-event.d.ts +9 -9
- package/esm/utils/auto-reset-event.d.ts.map +1 -1
- package/esm/utils/auto-reset-event.js +33 -33
- package/esm/utils/auto-reset-event.js.map +1 -1
- package/esm/utils/base64.d.ts +27 -27
- package/esm/utils/base64.d.ts.map +1 -1
- package/esm/utils/base64.js +246 -245
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/conditional-variable.d.ts +9 -0
- package/esm/utils/conditional-variable.d.ts.map +1 -0
- package/esm/utils/conditional-variable.js +34 -0
- package/esm/utils/conditional-variable.js.map +1 -0
- package/esm/utils/index.d.ts +4 -3
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +4 -3
- package/esm/utils/index.js.map +1 -1
- package/package.json +17 -13
- package/src/adb.ts +160 -101
- package/src/auth.ts +31 -22
- package/src/backend.ts +6 -4
- package/src/commands/base.ts +2 -2
- package/src/commands/framebuffer.ts +37 -41
- package/src/commands/index.ts +7 -8
- package/src/commands/power.ts +15 -11
- package/src/commands/reverse.ts +74 -30
- package/src/commands/subprocess/command.ts +34 -23
- package/src/commands/subprocess/index.ts +3 -3
- package/src/commands/subprocess/protocols/index.ts +3 -3
- package/src/commands/subprocess/protocols/none.ts +26 -11
- package/src/commands/subprocess/protocols/shell.ts +110 -56
- package/src/commands/subprocess/protocols/types.ts +10 -6
- package/src/commands/subprocess/utils.ts +1 -1
- package/src/commands/sync/index.ts +8 -7
- package/src/commands/sync/list.ts +74 -28
- package/src/commands/sync/pull.ts +49 -37
- package/src/commands/sync/push.ts +153 -32
- package/src/commands/sync/request.ts +37 -34
- package/src/commands/sync/response.ts +34 -27
- package/src/commands/sync/socket.ts +97 -0
- package/src/commands/sync/stat.ts +98 -70
- package/src/commands/sync/sync.ts +78 -97
- package/src/commands/tcpip.ts +5 -5
- package/src/crypto.ts +60 -32
- package/src/features.ts +9 -6
- package/src/index.ts +9 -10
- package/src/packet.ts +41 -46
- package/src/socket/dispatcher.ts +130 -108
- package/src/socket/index.ts +2 -2
- package/src/socket/socket.ts +84 -34
- package/src/utils/auto-reset-event.ts +16 -17
- package/src/utils/base64.ts +51 -41
- package/src/utils/conditional-variable.ts +45 -0
- package/src/utils/index.ts +4 -3
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/src/commands/install.ts +0 -32
package/src/commands/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from './tcpip.js';
|
|
1
|
+
export * from "./base.js";
|
|
2
|
+
export * from "./framebuffer.js";
|
|
3
|
+
export * from "./power.js";
|
|
4
|
+
export * from "./reverse.js";
|
|
5
|
+
export * from "./subprocess/index.js";
|
|
6
|
+
export * from "./sync/index.js";
|
|
7
|
+
export * from "./tcpip.js";
|
package/src/commands/power.ts
CHANGED
|
@@ -3,27 +3,27 @@
|
|
|
3
3
|
// cspell: ignore keyevent
|
|
4
4
|
// cspell: ignore longpress
|
|
5
5
|
|
|
6
|
-
import { AdbCommandBase } from
|
|
6
|
+
import { AdbCommandBase } from "./base.js";
|
|
7
7
|
|
|
8
8
|
export class AdbPower extends AdbCommandBase {
|
|
9
|
-
public reboot(name
|
|
9
|
+
public reboot(name = "") {
|
|
10
10
|
return this.adb.createSocketAndWait(`reboot:${name}`);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
public bootloader() {
|
|
14
|
-
return this.reboot(
|
|
14
|
+
return this.reboot("bootloader");
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
public fastboot() {
|
|
18
|
-
return this.reboot(
|
|
18
|
+
return this.reboot("fastboot");
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
public recovery() {
|
|
22
|
-
return this.reboot(
|
|
22
|
+
return this.reboot("recovery");
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
public sideload() {
|
|
26
|
-
return this.reboot(
|
|
26
|
+
return this.reboot("sideload");
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
@@ -32,15 +32,19 @@ export class AdbPower extends AdbCommandBase {
|
|
|
32
32
|
* Only works on some Qualcomm devices.
|
|
33
33
|
*/
|
|
34
34
|
public qualcommEdlMode() {
|
|
35
|
-
return this.reboot(
|
|
35
|
+
return this.reboot("edl");
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
public powerOff() {
|
|
39
|
-
return this.adb.subprocess.spawnAndWaitLegacy([
|
|
39
|
+
return this.adb.subprocess.spawnAndWaitLegacy(["reboot", "-p"]);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
public powerButton(longPress
|
|
43
|
-
return this.adb.subprocess.spawnAndWaitLegacy([
|
|
42
|
+
public powerButton(longPress = false) {
|
|
43
|
+
return this.adb.subprocess.spawnAndWaitLegacy([
|
|
44
|
+
"input",
|
|
45
|
+
"keyevent",
|
|
46
|
+
longPress ? "--longpress POWER" : "POWER",
|
|
47
|
+
]);
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
/**
|
|
@@ -49,6 +53,6 @@ export class AdbPower extends AdbCommandBase {
|
|
|
49
53
|
* Only works on Samsung devices.
|
|
50
54
|
*/
|
|
51
55
|
public samsungOdin() {
|
|
52
|
-
return this.reboot(
|
|
56
|
+
return this.reboot("download");
|
|
53
57
|
}
|
|
54
58
|
}
|
package/src/commands/reverse.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
// cspell: ignore killforward
|
|
2
2
|
|
|
3
|
-
import { AutoDisposable } from
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import { AutoDisposable } from "@yume-chan/event";
|
|
4
|
+
import {
|
|
5
|
+
BufferedReadableStream,
|
|
6
|
+
BufferedReadableStreamEndedError,
|
|
7
|
+
} from "@yume-chan/stream-extra";
|
|
8
|
+
import Struct from "@yume-chan/struct";
|
|
6
9
|
|
|
7
|
-
import type { Adb } from
|
|
8
|
-
import type { AdbIncomingSocketHandler, AdbSocket } from
|
|
9
|
-
import { decodeUtf8 } from
|
|
10
|
+
import type { Adb } from "../adb.js";
|
|
11
|
+
import type { AdbIncomingSocketHandler, AdbSocket } from "../socket/index.js";
|
|
12
|
+
import { decodeUtf8 } from "../utils/index.js";
|
|
10
13
|
|
|
11
14
|
export interface AdbForwardListener {
|
|
12
15
|
deviceSerial: string;
|
|
@@ -16,20 +19,44 @@ export interface AdbForwardListener {
|
|
|
16
19
|
remoteName: string;
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
const AdbReverseStringResponse =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.string('content', { lengthField: 'length', lengthFieldRadix: 16 });
|
|
22
|
+
const AdbReverseStringResponse = new Struct()
|
|
23
|
+
.string("length", { length: 4 })
|
|
24
|
+
.string("content", { lengthField: "length", lengthFieldRadix: 16 });
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
.
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
export class AdbReverseError extends Error {
|
|
27
|
+
public constructor(message: string) {
|
|
28
|
+
super(message);
|
|
29
|
+
Object.setPrototypeOf(this, AdbReverseError.prototype);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class AdbReverseNotSupportedError extends Error {
|
|
34
|
+
public constructor() {
|
|
35
|
+
super(
|
|
36
|
+
"ADB reverse tunnel is not supported on this device when connected wirelessly."
|
|
37
|
+
);
|
|
38
|
+
Object.setPrototypeOf(this, AdbReverseNotSupportedError.prototype);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const AdbReverseErrorResponse = new Struct()
|
|
43
|
+
.fields(AdbReverseStringResponse)
|
|
44
|
+
.postDeserialize((value) => {
|
|
45
|
+
// https://issuetracker.google.com/issues/37066218
|
|
46
|
+
// ADB on Android <9 can't create reverse tunnels when connected wirelessly (ADB over WiFi),
|
|
47
|
+
// and returns this confusing "more than one device/emulator" error.
|
|
48
|
+
if (value.content === "more than one device/emulator") {
|
|
49
|
+
throw new AdbReverseNotSupportedError();
|
|
50
|
+
} else {
|
|
51
|
+
throw new AdbReverseError(value.content);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
30
54
|
|
|
31
55
|
export class AdbReverseCommand extends AutoDisposable {
|
|
32
|
-
protected localAddressToHandler = new Map<
|
|
56
|
+
protected localAddressToHandler = new Map<
|
|
57
|
+
string,
|
|
58
|
+
AdbIncomingSocketHandler
|
|
59
|
+
>();
|
|
33
60
|
|
|
34
61
|
protected deviceAddressToLocalAddress = new Map<string, string>();
|
|
35
62
|
|
|
@@ -41,13 +68,15 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
41
68
|
super();
|
|
42
69
|
|
|
43
70
|
this.adb = adb;
|
|
44
|
-
this.addDisposable(
|
|
71
|
+
this.addDisposable(
|
|
72
|
+
this.adb.onIncomingSocket(this.handleIncomingSocket)
|
|
73
|
+
);
|
|
45
74
|
}
|
|
46
75
|
|
|
47
76
|
protected handleIncomingSocket = async (socket: AdbSocket) => {
|
|
48
77
|
let address = socket.serviceString;
|
|
49
78
|
// ADB daemon appends `\0` to the service string
|
|
50
|
-
address = address.replace(/\0/g,
|
|
79
|
+
address = address.replace(/\0/g, "");
|
|
51
80
|
return !!(await this.localAddressToHandler.get(address)?.(socket));
|
|
52
81
|
};
|
|
53
82
|
|
|
@@ -58,7 +87,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
58
87
|
|
|
59
88
|
private async sendRequest(service: string) {
|
|
60
89
|
const stream = await this.createBufferedStream(service);
|
|
61
|
-
const success = decodeUtf8(await stream.read(4)) ===
|
|
90
|
+
const success = decodeUtf8(await stream.read(4)) === "OKAY";
|
|
62
91
|
if (!success) {
|
|
63
92
|
await AdbReverseErrorResponse.deserialize(stream);
|
|
64
93
|
}
|
|
@@ -66,11 +95,15 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
66
95
|
}
|
|
67
96
|
|
|
68
97
|
public async list(): Promise<AdbForwardListener[]> {
|
|
69
|
-
const stream = await this.createBufferedStream(
|
|
98
|
+
const stream = await this.createBufferedStream("reverse:list-forward");
|
|
70
99
|
|
|
71
100
|
const response = await AdbReverseStringResponse.deserialize(stream);
|
|
72
|
-
return response.content!.split(
|
|
73
|
-
const [deviceSerial, localName, remoteName] = line.split(
|
|
101
|
+
return response.content!.split("\n").map((line) => {
|
|
102
|
+
const [deviceSerial, localName, remoteName] = line.split(" ") as [
|
|
103
|
+
string,
|
|
104
|
+
string,
|
|
105
|
+
string
|
|
106
|
+
];
|
|
74
107
|
return { deviceSerial, localName, remoteName };
|
|
75
108
|
});
|
|
76
109
|
|
|
@@ -78,21 +111,30 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
78
111
|
}
|
|
79
112
|
|
|
80
113
|
/**
|
|
81
|
-
* @param deviceAddress
|
|
82
|
-
*
|
|
114
|
+
* @param deviceAddress
|
|
115
|
+
* The address to be listened on device by ADB daemon. Or `tcp:0` to choose an available TCP port.
|
|
116
|
+
* @param localAddress
|
|
117
|
+
* An identifier for the reverse tunnel.
|
|
118
|
+
*
|
|
119
|
+
* When a socket wants to connect to {@link deviceAddress}, native ADB client will forward that connection to {@link localAddress}.
|
|
120
|
+
* However in this library, the {@link handler} is invoked instead. So this parameter is only used to identify the reverse tunnel.
|
|
83
121
|
* @param handler A callback to handle incoming connections. It must return `true` if it accepts the connection.
|
|
84
122
|
* @returns `tcp:{ACTUAL_LISTENING_PORT}`, If `deviceAddress` is `tcp:0`; otherwise, `deviceAddress`.
|
|
123
|
+
* @throws {AdbReverseNotSupportedError} If ADB reverse tunnel is not supported on this device when connected wirelessly.
|
|
124
|
+
* @throws {AdbReverseError} If ADB daemon returns an error.
|
|
85
125
|
*/
|
|
86
126
|
public async add(
|
|
87
127
|
deviceAddress: string,
|
|
88
128
|
localAddress: string,
|
|
89
|
-
handler: AdbIncomingSocketHandler
|
|
129
|
+
handler: AdbIncomingSocketHandler
|
|
90
130
|
): Promise<string> {
|
|
91
|
-
const stream = await this.sendRequest(
|
|
131
|
+
const stream = await this.sendRequest(
|
|
132
|
+
`reverse:forward:${deviceAddress};${localAddress}`
|
|
133
|
+
);
|
|
92
134
|
|
|
93
135
|
// `tcp:0` tells the device to pick an available port.
|
|
94
136
|
// On Android >=8, device will respond with the selected port for all `tcp:` requests.
|
|
95
|
-
if (deviceAddress.startsWith(
|
|
137
|
+
if (deviceAddress.startsWith("tcp:")) {
|
|
96
138
|
let length: number | undefined;
|
|
97
139
|
try {
|
|
98
140
|
length = Number.parseInt(decodeUtf8(await stream.read(4)), 16);
|
|
@@ -107,7 +149,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
107
149
|
}
|
|
108
150
|
|
|
109
151
|
if (length !== undefined) {
|
|
110
|
-
const port = decodeUtf8(await stream.read(length
|
|
152
|
+
const port = decodeUtf8(await stream.read(length));
|
|
111
153
|
deviceAddress = `tcp:${Number.parseInt(port, 10)}`;
|
|
112
154
|
}
|
|
113
155
|
}
|
|
@@ -123,7 +165,9 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
123
165
|
await this.sendRequest(`reverse:killforward:${deviceAddress}`);
|
|
124
166
|
|
|
125
167
|
if (this.deviceAddressToLocalAddress.has(deviceAddress)) {
|
|
126
|
-
this.localAddressToHandler.delete(
|
|
168
|
+
this.localAddressToHandler.delete(
|
|
169
|
+
this.deviceAddressToLocalAddress.get(deviceAddress)!
|
|
170
|
+
);
|
|
127
171
|
this.deviceAddressToLocalAddress.delete(deviceAddress);
|
|
128
172
|
}
|
|
129
173
|
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DecodeUtf8Stream, GatherStringStream } from "@yume-chan/stream-extra";
|
|
2
2
|
|
|
3
|
-
import { AdbCommandBase } from
|
|
4
|
-
|
|
3
|
+
import { AdbCommandBase } from "../base.js";
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
AdbSubprocessProtocol,
|
|
7
|
+
AdbSubprocessProtocolConstructor,
|
|
8
|
+
} from "./protocols/index.js";
|
|
9
|
+
import {
|
|
10
|
+
AdbSubprocessNoneProtocol,
|
|
11
|
+
AdbSubprocessShellProtocol,
|
|
12
|
+
} from "./protocols/index.js";
|
|
5
13
|
|
|
6
14
|
export interface AdbSubprocessOptions {
|
|
7
15
|
/**
|
|
@@ -30,7 +38,7 @@ export interface AdbSubprocessWaitResult {
|
|
|
30
38
|
|
|
31
39
|
export class AdbSubprocess extends AdbCommandBase {
|
|
32
40
|
private async createProtocol(
|
|
33
|
-
mode:
|
|
41
|
+
mode: "pty" | "raw",
|
|
34
42
|
command?: string | string[],
|
|
35
43
|
options?: Partial<AdbSubprocessOptions>
|
|
36
44
|
): Promise<AdbSubprocessProtocol> {
|
|
@@ -46,20 +54,23 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
if (!Constructor) {
|
|
49
|
-
throw new Error(
|
|
57
|
+
throw new Error("No specified protocol is supported by the device");
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
if (Array.isArray(command)) {
|
|
53
|
-
command = command.join(
|
|
61
|
+
command = command.join(" ");
|
|
54
62
|
} else if (command === undefined) {
|
|
55
63
|
// spawn the default shell
|
|
56
|
-
command =
|
|
64
|
+
command = "";
|
|
57
65
|
}
|
|
58
66
|
return await Constructor[mode](this.adb, command);
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
/**
|
|
62
|
-
* Spawns an executable in PTY
|
|
70
|
+
* Spawns an executable in PTY mode.
|
|
71
|
+
*
|
|
72
|
+
* Redirection mode is enough for most simple commands, but PTY mode is required for
|
|
73
|
+
* commands that manipulate the terminal, such as `vi` and `less`.
|
|
63
74
|
* @param command The command to run. If omitted, the default shell will be spawned.
|
|
64
75
|
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
65
76
|
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
@@ -68,11 +79,14 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
68
79
|
command?: string | string[],
|
|
69
80
|
options?: Partial<AdbSubprocessOptions>
|
|
70
81
|
): Promise<AdbSubprocessProtocol> {
|
|
71
|
-
return this.createProtocol(
|
|
82
|
+
return this.createProtocol("pty", command, options);
|
|
72
83
|
}
|
|
73
84
|
|
|
74
85
|
/**
|
|
75
|
-
* Spawns an executable and
|
|
86
|
+
* Spawns an executable and redirect the standard input/output stream.
|
|
87
|
+
*
|
|
88
|
+
* Redirection mode is enough for most simple commands, but PTY mode is required for
|
|
89
|
+
* commands that manipulate the terminal, such as `vi` and `less`.
|
|
76
90
|
* @param command The command to run, or an array of strings containing both command and args.
|
|
77
91
|
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
78
92
|
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
@@ -81,7 +95,7 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
81
95
|
command: string | string[],
|
|
82
96
|
options?: Partial<AdbSubprocessOptions>
|
|
83
97
|
): Promise<AdbSubprocessProtocol> {
|
|
84
|
-
return this.createProtocol(
|
|
98
|
+
return this.createProtocol("raw", command, options);
|
|
85
99
|
}
|
|
86
100
|
|
|
87
101
|
/**
|
|
@@ -100,13 +114,9 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
100
114
|
const stderr = new GatherStringStream();
|
|
101
115
|
|
|
102
116
|
const [, , exitCode] = await Promise.all([
|
|
103
|
-
shell.stdout
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
shell.stderr
|
|
107
|
-
.pipeThrough(new DecodeUtf8Stream())
|
|
108
|
-
.pipeTo(stderr),
|
|
109
|
-
shell.exit
|
|
117
|
+
shell.stdout.pipeThrough(new DecodeUtf8Stream()).pipeTo(stdout),
|
|
118
|
+
shell.stderr.pipeThrough(new DecodeUtf8Stream()).pipeTo(stderr),
|
|
119
|
+
shell.exit,
|
|
110
120
|
]);
|
|
111
121
|
|
|
112
122
|
return {
|
|
@@ -121,11 +131,12 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
121
131
|
* @param command The command to run
|
|
122
132
|
* @returns The entire output of the command
|
|
123
133
|
*/
|
|
124
|
-
public async spawnAndWaitLegacy(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
public async spawnAndWaitLegacy(
|
|
135
|
+
command: string | string[]
|
|
136
|
+
): Promise<string> {
|
|
137
|
+
const { stdout } = await this.spawnAndWait(command, {
|
|
138
|
+
protocols: [AdbSubprocessNoneProtocol],
|
|
139
|
+
});
|
|
129
140
|
return stdout;
|
|
130
141
|
}
|
|
131
142
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
1
|
+
export * from "./command.js";
|
|
2
|
+
export * from "./protocols/index.js";
|
|
3
|
+
export * from "./utils.js";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
1
|
+
export * from "./none.js";
|
|
2
|
+
export * from "./shell.js";
|
|
3
|
+
export * from "./types.js";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { DuplexStreamFactory, ReadableStream } from
|
|
1
|
+
import { DuplexStreamFactory, ReadableStream } from "@yume-chan/stream-extra";
|
|
2
2
|
|
|
3
|
-
import type { Adb } from
|
|
4
|
-
import type { AdbSocket } from
|
|
5
|
-
|
|
3
|
+
import type { Adb } from "../../../adb.js";
|
|
4
|
+
import type { AdbSocket } from "../../../socket/index.js";
|
|
5
|
+
|
|
6
|
+
import type { AdbSubprocessProtocol } from "./types.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* The legacy shell
|
|
@@ -13,16 +14,22 @@ import type { AdbSubprocessProtocol } from './types.js';
|
|
|
13
14
|
* * `resize`: No
|
|
14
15
|
*/
|
|
15
16
|
export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
16
|
-
public static isSupported() {
|
|
17
|
+
public static isSupported() {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
public static async pty(adb: Adb, command: string) {
|
|
19
|
-
return new AdbSubprocessNoneProtocol(
|
|
22
|
+
return new AdbSubprocessNoneProtocol(
|
|
23
|
+
await adb.createSocket(`shell:${command}`)
|
|
24
|
+
);
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
public static async raw(adb: Adb, command: string) {
|
|
23
28
|
// `shell,raw:${command}` also triggers raw mode,
|
|
24
29
|
// But is not supported on Android version <7.
|
|
25
|
-
return new AdbSubprocessNoneProtocol(
|
|
30
|
+
return new AdbSubprocessNoneProtocol(
|
|
31
|
+
await adb.createSocket(`exec:${command}`)
|
|
32
|
+
);
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
private readonly socket: AdbSocket;
|
|
@@ -30,22 +37,30 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
30
37
|
private readonly duplex: DuplexStreamFactory<Uint8Array, Uint8Array>;
|
|
31
38
|
|
|
32
39
|
// Legacy shell forwards all data to stdin.
|
|
33
|
-
public get stdin() {
|
|
40
|
+
public get stdin() {
|
|
41
|
+
return this.socket.writable;
|
|
42
|
+
}
|
|
34
43
|
|
|
35
44
|
private _stdout: ReadableStream<Uint8Array>;
|
|
36
45
|
/**
|
|
37
46
|
* Legacy shell mixes stdout and stderr.
|
|
38
47
|
*/
|
|
39
|
-
public get stdout() {
|
|
48
|
+
public get stdout() {
|
|
49
|
+
return this._stdout;
|
|
50
|
+
}
|
|
40
51
|
|
|
41
52
|
private _stderr: ReadableStream<Uint8Array>;
|
|
42
53
|
/**
|
|
43
54
|
* `stderr` will always be empty.
|
|
44
55
|
*/
|
|
45
|
-
public get stderr() {
|
|
56
|
+
public get stderr() {
|
|
57
|
+
return this._stderr;
|
|
58
|
+
}
|
|
46
59
|
|
|
47
60
|
private _exit: Promise<number>;
|
|
48
|
-
public get exit() {
|
|
61
|
+
public get exit() {
|
|
62
|
+
return this._exit;
|
|
63
|
+
}
|
|
49
64
|
|
|
50
65
|
public constructor(socket: AdbSocket) {
|
|
51
66
|
this.socket = socket;
|