@yume-chan/adb 0.0.20 → 0.0.21
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 +24 -0
- package/CHANGELOG.md +12 -1
- package/README.md +5 -3
- package/esm/adb.d.ts +4 -1
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +21 -11
- package/esm/adb.js.map +1 -1
- package/esm/banner.d.ts.map +1 -1
- package/esm/banner.js +1 -1
- package/esm/banner.js.map +1 -1
- package/esm/commands/base.d.ts.map +1 -1
- package/esm/commands/base.js.map +1 -1
- package/esm/commands/framebuffer.d.ts +9 -0
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +27 -3
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +1 -1
- package/esm/commands/subprocess/command.d.ts.map +1 -1
- package/esm/commands/subprocess/command.js +15 -13
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +15 -15
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/sync/push.js +1 -1
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.js +1 -1
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +2 -0
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +4 -2
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +0 -1
- package/esm/commands/sync/socket.d.ts.map +1 -1
- package/esm/commands/sync/socket.js +3 -3
- package/esm/commands/sync/socket.js.map +1 -1
- package/esm/commands/sync/stat.js +2 -2
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +15 -0
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +17 -2
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts.map +1 -1
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/daemon/auth.d.ts +11 -9
- package/esm/daemon/auth.d.ts.map +1 -1
- package/esm/daemon/auth.js +21 -12
- package/esm/daemon/auth.js.map +1 -1
- package/esm/daemon/crypto.js +2 -2
- package/esm/daemon/crypto.js.map +1 -1
- package/esm/daemon/dispatcher.d.ts +4 -4
- package/esm/daemon/dispatcher.d.ts.map +1 -1
- package/esm/daemon/dispatcher.js +16 -16
- package/esm/daemon/dispatcher.js.map +1 -1
- package/esm/daemon/packet.js +1 -1
- package/esm/daemon/packet.js.map +1 -1
- package/esm/daemon/socket.d.ts +0 -2
- package/esm/daemon/socket.d.ts.map +1 -1
- package/esm/daemon/socket.js +12 -8
- package/esm/daemon/socket.js.map +1 -1
- package/esm/daemon/transport.d.ts +10 -2
- package/esm/daemon/transport.d.ts.map +1 -1
- package/esm/daemon/transport.js +5 -3
- package/esm/daemon/transport.js.map +1 -1
- package/esm/features.js +1 -1
- package/esm/features.js.map +1 -1
- package/esm/server/client.d.ts.map +1 -1
- package/esm/server/client.js +1 -2
- package/esm/server/client.js.map +1 -1
- package/esm/server/transport.d.ts.map +1 -1
- package/esm/server/transport.js.map +1 -1
- package/esm/utils/auto-reset-event.d.ts.map +1 -1
- package/esm/utils/auto-reset-event.js.map +1 -1
- package/esm/utils/conditional-variable.d.ts.map +1 -1
- package/esm/utils/conditional-variable.js.map +1 -1
- package/package.json +12 -13
- package/src/adb.ts +42 -30
- package/src/banner.ts +7 -7
- package/src/commands/base.ts +1 -1
- package/src/commands/framebuffer.ts +31 -3
- package/src/commands/power.ts +9 -9
- package/src/commands/reverse.ts +13 -13
- package/src/commands/subprocess/command.ts +24 -25
- package/src/commands/subprocess/protocols/none.ts +12 -12
- package/src/commands/subprocess/protocols/shell.ts +35 -35
- package/src/commands/sync/list.ts +5 -5
- package/src/commands/sync/pull.ts +4 -4
- package/src/commands/sync/push.ts +6 -6
- package/src/commands/sync/request.ts +3 -3
- package/src/commands/sync/response.ts +7 -5
- package/src/commands/sync/socket.ts +14 -14
- package/src/commands/sync/stat.ts +5 -5
- package/src/commands/sync/sync.ts +32 -17
- package/src/commands/tcpip.ts +2 -2
- package/src/daemon/auth.ts +49 -30
- package/src/daemon/crypto.ts +9 -9
- package/src/daemon/dispatcher.ts +40 -39
- package/src/daemon/packet.ts +1 -1
- package/src/daemon/socket.ts +34 -30
- package/src/daemon/transport.ts +32 -20
- package/src/server/client.ts +38 -41
- package/src/server/transport.ts +13 -13
- package/src/utils/auto-reset-event.ts +4 -4
- package/src/utils/base64.ts +5 -5
- package/src/utils/conditional-variable.ts +4 -4
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/daemon/connection.d.ts +0 -11
- package/esm/daemon/connection.d.ts.map +0 -1
- package/esm/daemon/connection.js +0 -2
- package/esm/daemon/connection.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BufferedReadableStream } from "@yume-chan/stream-extra";
|
|
2
|
-
import Struct from "@yume-chan/struct";
|
|
2
|
+
import Struct, { StructEmptyError } from "@yume-chan/struct";
|
|
3
3
|
|
|
4
4
|
import type { Adb } from "../adb.js";
|
|
5
5
|
|
|
@@ -58,10 +58,38 @@ export type AdbFrameBufferV2 = (typeof AdbFrameBufferV2)["TDeserializeResult"];
|
|
|
58
58
|
*/
|
|
59
59
|
export type AdbFrameBuffer = AdbFrameBufferV1 | AdbFrameBufferV2;
|
|
60
60
|
|
|
61
|
+
export class AdbFrameBufferError extends Error {
|
|
62
|
+
constructor(message: string, options?: ErrorOptions) {
|
|
63
|
+
super(message, options);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class AdbFrameBufferUnsupportedVersionError extends AdbFrameBufferError {
|
|
68
|
+
constructor(version: number) {
|
|
69
|
+
super(`Unsupported FrameBuffer version ${version}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class AdbFrameBufferForbiddenError extends AdbFrameBufferError {
|
|
74
|
+
constructor() {
|
|
75
|
+
super("FrameBuffer is disabled by current app");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
61
79
|
export async function framebuffer(adb: Adb): Promise<AdbFrameBuffer> {
|
|
62
80
|
const socket = await adb.createSocket("framebuffer:");
|
|
63
81
|
const stream = new BufferedReadableStream(socket.readable);
|
|
64
|
-
|
|
82
|
+
|
|
83
|
+
let version: number;
|
|
84
|
+
try {
|
|
85
|
+
({ version } = await Version.deserialize(stream));
|
|
86
|
+
} catch (e) {
|
|
87
|
+
if (e instanceof StructEmptyError) {
|
|
88
|
+
throw new AdbFrameBufferForbiddenError();
|
|
89
|
+
}
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
92
|
+
|
|
65
93
|
switch (version) {
|
|
66
94
|
case 1:
|
|
67
95
|
// TODO: AdbFrameBuffer: does all v1 responses uses the same color space? Add it so the command returns same format for all versions.
|
|
@@ -69,6 +97,6 @@ export async function framebuffer(adb: Adb): Promise<AdbFrameBuffer> {
|
|
|
69
97
|
case 2:
|
|
70
98
|
return AdbFrameBufferV2.deserialize(stream);
|
|
71
99
|
default:
|
|
72
|
-
throw new
|
|
100
|
+
throw new AdbFrameBufferUnsupportedVersionError(version);
|
|
73
101
|
}
|
|
74
102
|
}
|
package/src/commands/power.ts
CHANGED
|
@@ -6,23 +6,23 @@
|
|
|
6
6
|
import { AdbCommandBase } from "./base.js";
|
|
7
7
|
|
|
8
8
|
export class AdbPower extends AdbCommandBase {
|
|
9
|
-
|
|
9
|
+
reboot(mode = "") {
|
|
10
10
|
return this.adb.createSocketAndWait(`reboot:${mode}`);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
bootloader() {
|
|
14
14
|
return this.reboot("bootloader");
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
fastboot() {
|
|
18
18
|
return this.reboot("fastboot");
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
recovery() {
|
|
22
22
|
return this.reboot("recovery");
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
sideload() {
|
|
26
26
|
return this.reboot("sideload");
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -31,15 +31,15 @@ export class AdbPower extends AdbCommandBase {
|
|
|
31
31
|
*
|
|
32
32
|
* Only works on some Qualcomm devices.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
qualcommEdlMode() {
|
|
35
35
|
return this.reboot("edl");
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
powerOff() {
|
|
39
39
|
return this.adb.subprocess.spawnAndWaitLegacy(["reboot", "-p"]);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
powerButton(longPress = false) {
|
|
43
43
|
return this.adb.subprocess.spawnAndWaitLegacy([
|
|
44
44
|
"input",
|
|
45
45
|
"keyevent",
|
|
@@ -52,7 +52,7 @@ export class AdbPower extends AdbCommandBase {
|
|
|
52
52
|
*
|
|
53
53
|
* Only works on Samsung devices.
|
|
54
54
|
*/
|
|
55
|
-
|
|
55
|
+
samsungOdin() {
|
|
56
56
|
return this.reboot("download");
|
|
57
57
|
}
|
|
58
58
|
}
|
package/src/commands/reverse.ts
CHANGED
|
@@ -20,16 +20,16 @@ const AdbReverseStringResponse = new Struct()
|
|
|
20
20
|
.string("content", { lengthField: "length", lengthFieldRadix: 16 });
|
|
21
21
|
|
|
22
22
|
export class AdbReverseError extends Error {
|
|
23
|
-
|
|
23
|
+
constructor(message: string) {
|
|
24
24
|
super(message);
|
|
25
25
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export class AdbReverseNotSupportedError extends AdbReverseError {
|
|
30
|
-
|
|
30
|
+
constructor() {
|
|
31
31
|
super(
|
|
32
|
-
"ADB reverse tunnel is not supported on this device when connected wirelessly."
|
|
32
|
+
"ADB reverse tunnel is not supported on this device when connected wirelessly.",
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -57,7 +57,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
57
57
|
|
|
58
58
|
readonly #deviceAddressToLocalAddress = new Map<string, string>();
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
constructor(adb: Adb) {
|
|
61
61
|
super();
|
|
62
62
|
|
|
63
63
|
this.adb = adb;
|
|
@@ -77,7 +77,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
77
77
|
return stream;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
async list(): Promise<AdbForwardListener[]> {
|
|
81
81
|
const stream = await this.createBufferedStream("reverse:list-forward");
|
|
82
82
|
|
|
83
83
|
const response = await AdbReverseStringResponse.deserialize(stream);
|
|
@@ -85,7 +85,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
85
85
|
const [deviceSerial, localName, remoteName] = line.split(" ") as [
|
|
86
86
|
string,
|
|
87
87
|
string,
|
|
88
|
-
string
|
|
88
|
+
string,
|
|
89
89
|
];
|
|
90
90
|
return { deviceSerial, localName, remoteName };
|
|
91
91
|
});
|
|
@@ -99,9 +99,9 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
99
99
|
* @param localAddress The address that listens on the local machine.
|
|
100
100
|
* @returns `tcp:{ACTUAL_LISTENING_PORT}`, If `deviceAddress` is `tcp:0`; otherwise, `deviceAddress`.
|
|
101
101
|
*/
|
|
102
|
-
|
|
102
|
+
async addExternal(deviceAddress: string, localAddress: string) {
|
|
103
103
|
const stream = await this.sendRequest(
|
|
104
|
-
`reverse:forward:${deviceAddress};${localAddress}
|
|
104
|
+
`reverse:forward:${deviceAddress};${localAddress}`,
|
|
105
105
|
);
|
|
106
106
|
|
|
107
107
|
// `tcp:0` tells the device to pick an available port.
|
|
@@ -137,14 +137,14 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
137
137
|
* @throws {AdbReverseNotSupportedError} If ADB reverse tunnel is not supported on this device when connected wirelessly.
|
|
138
138
|
* @throws {AdbReverseError} If ADB daemon returns an error.
|
|
139
139
|
*/
|
|
140
|
-
|
|
140
|
+
async add(
|
|
141
141
|
deviceAddress: string,
|
|
142
142
|
handler: AdbIncomingSocketHandler,
|
|
143
|
-
localAddress?: string
|
|
143
|
+
localAddress?: string,
|
|
144
144
|
): Promise<string> {
|
|
145
145
|
localAddress = await this.adb.transport.addReverseTunnel(
|
|
146
146
|
handler,
|
|
147
|
-
localAddress
|
|
147
|
+
localAddress,
|
|
148
148
|
);
|
|
149
149
|
|
|
150
150
|
try {
|
|
@@ -157,7 +157,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
async remove(deviceAddress: string): Promise<void> {
|
|
161
161
|
const localAddress =
|
|
162
162
|
this.#deviceAddressToLocalAddress.get(deviceAddress);
|
|
163
163
|
if (localAddress) {
|
|
@@ -169,7 +169,7 @@ export class AdbReverseCommand extends AutoDisposable {
|
|
|
169
169
|
// No need to close the stream, device will close it
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
async removeAll(): Promise<void> {
|
|
173
173
|
await this.adb.transport.clearReverseTunnels();
|
|
174
174
|
this.#deviceAddressToLocalAddress.clear();
|
|
175
175
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConcatStringStream, DecodeUtf8Stream } from "@yume-chan/stream-extra";
|
|
2
2
|
|
|
3
3
|
import { AdbCommandBase } from "../base.js";
|
|
4
4
|
|
|
@@ -37,10 +37,10 @@ export interface AdbSubprocessWaitResult {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export class AdbSubprocess extends AdbCommandBase {
|
|
40
|
-
|
|
40
|
+
async #createProtocol(
|
|
41
41
|
mode: "pty" | "raw",
|
|
42
42
|
command?: string | string[],
|
|
43
|
-
options?: Partial<AdbSubprocessOptions
|
|
43
|
+
options?: Partial<AdbSubprocessOptions>,
|
|
44
44
|
): Promise<AdbSubprocessProtocol> {
|
|
45
45
|
const { protocols } = { ...DEFAULT_OPTIONS, ...options };
|
|
46
46
|
|
|
@@ -75,11 +75,11 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
75
75
|
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
76
76
|
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
77
77
|
*/
|
|
78
|
-
|
|
78
|
+
shell(
|
|
79
79
|
command?: string | string[],
|
|
80
|
-
options?: Partial<AdbSubprocessOptions
|
|
80
|
+
options?: Partial<AdbSubprocessOptions>,
|
|
81
81
|
): Promise<AdbSubprocessProtocol> {
|
|
82
|
-
return this
|
|
82
|
+
return this.#createProtocol("pty", command, options);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
@@ -91,11 +91,11 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
91
91
|
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
92
92
|
* @returns A new `AdbSubprocessProtocol` instance connecting to the spawned process.
|
|
93
93
|
*/
|
|
94
|
-
|
|
94
|
+
spawn(
|
|
95
95
|
command: string | string[],
|
|
96
|
-
options?: Partial<AdbSubprocessOptions
|
|
96
|
+
options?: Partial<AdbSubprocessOptions>,
|
|
97
97
|
): Promise<AdbSubprocessProtocol> {
|
|
98
|
-
return this
|
|
98
|
+
return this.#createProtocol("raw", command, options);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/**
|
|
@@ -104,24 +104,25 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
104
104
|
* @param options The options for creating the `AdbSubprocessProtocol`
|
|
105
105
|
* @returns The entire output of the command
|
|
106
106
|
*/
|
|
107
|
-
|
|
107
|
+
async spawnAndWait(
|
|
108
108
|
command: string | string[],
|
|
109
|
-
options?: Partial<AdbSubprocessOptions
|
|
109
|
+
options?: Partial<AdbSubprocessOptions>,
|
|
110
110
|
): Promise<AdbSubprocessWaitResult> {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
const stdout =
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
111
|
+
const process = await this.spawn(command, options);
|
|
112
|
+
|
|
113
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
114
|
+
process.stdout
|
|
115
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
116
|
+
.pipeThrough(new ConcatStringStream()),
|
|
117
|
+
process.stderr
|
|
118
|
+
.pipeThrough(new DecodeUtf8Stream())
|
|
119
|
+
.pipeThrough(new ConcatStringStream()),
|
|
120
|
+
process.exit,
|
|
120
121
|
]);
|
|
121
122
|
|
|
122
123
|
return {
|
|
123
|
-
stdout
|
|
124
|
-
stderr
|
|
124
|
+
stdout,
|
|
125
|
+
stderr,
|
|
125
126
|
exitCode,
|
|
126
127
|
};
|
|
127
128
|
}
|
|
@@ -131,9 +132,7 @@ export class AdbSubprocess extends AdbCommandBase {
|
|
|
131
132
|
* @param command The command to run
|
|
132
133
|
* @returns The entire output of the command
|
|
133
134
|
*/
|
|
134
|
-
|
|
135
|
-
command: string | string[]
|
|
136
|
-
): Promise<string> {
|
|
135
|
+
async spawnAndWaitLegacy(command: string | string[]): Promise<string> {
|
|
137
136
|
const { stdout } = await this.spawnAndWait(command, {
|
|
138
137
|
protocols: [AdbSubprocessNoneProtocol],
|
|
139
138
|
});
|
|
@@ -13,21 +13,21 @@ import type { AdbSubprocessProtocol } from "./types.js";
|
|
|
13
13
|
* * `resize`: No
|
|
14
14
|
*/
|
|
15
15
|
export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
16
|
-
|
|
16
|
+
static isSupported() {
|
|
17
17
|
return true;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
static async pty(adb: Adb, command: string) {
|
|
21
21
|
return new AdbSubprocessNoneProtocol(
|
|
22
|
-
await adb.createSocket(`shell:${command}`)
|
|
22
|
+
await adb.createSocket(`shell:${command}`),
|
|
23
23
|
);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
static async raw(adb: Adb, command: string) {
|
|
27
27
|
// `shell,raw:${command}` also triggers raw mode,
|
|
28
28
|
// But is not supported on Android version <7.
|
|
29
29
|
return new AdbSubprocessNoneProtocol(
|
|
30
|
-
await adb.createSocket(`exec:${command}`)
|
|
30
|
+
await adb.createSocket(`exec:${command}`),
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -36,7 +36,7 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
36
36
|
readonly #duplex: DuplexStreamFactory<Uint8Array, Uint8Array>;
|
|
37
37
|
|
|
38
38
|
// Legacy shell forwards all data to stdin.
|
|
39
|
-
|
|
39
|
+
get stdin() {
|
|
40
40
|
return this.#socket.writable;
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -44,7 +44,7 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
44
44
|
/**
|
|
45
45
|
* Legacy shell mixes stdout and stderr.
|
|
46
46
|
*/
|
|
47
|
-
|
|
47
|
+
get stdout() {
|
|
48
48
|
return this.#stdout;
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -52,16 +52,16 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
52
52
|
/**
|
|
53
53
|
* `stderr` will always be empty.
|
|
54
54
|
*/
|
|
55
|
-
|
|
55
|
+
get stderr() {
|
|
56
56
|
return this.#stderr;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
#exit: Promise<number>;
|
|
60
|
-
|
|
60
|
+
get exit() {
|
|
61
61
|
return this.#exit;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
constructor(socket: AdbSocket) {
|
|
65
65
|
this.#socket = socket;
|
|
66
66
|
|
|
67
67
|
// Link `stdout`, `stderr` and `stdin` together,
|
|
@@ -77,11 +77,11 @@ export class AdbSubprocessNoneProtocol implements AdbSubprocessProtocol {
|
|
|
77
77
|
this.#exit = this.#duplex.closed.then(() => 0);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
resize() {
|
|
81
81
|
// Not supported, but don't throw.
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
kill() {
|
|
85
85
|
return this.#duplex.close();
|
|
86
86
|
}
|
|
87
87
|
}
|
|
@@ -61,38 +61,38 @@ class StdinSerializeStream extends ConsumableTransformStream<
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
class MultiplexStream<T> {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return this
|
|
64
|
+
#readable: PushReadableStream<T>;
|
|
65
|
+
#readableController!: PushReadableStreamController<T>;
|
|
66
|
+
get readable() {
|
|
67
|
+
return this.#readable;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
#activeCount = 0;
|
|
71
71
|
|
|
72
72
|
constructor() {
|
|
73
|
-
this
|
|
74
|
-
this
|
|
73
|
+
this.#readable = new PushReadableStream((controller) => {
|
|
74
|
+
this.#readableController = controller;
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
createWriteable() {
|
|
79
79
|
return new WritableStream<T>({
|
|
80
80
|
start: () => {
|
|
81
|
-
this
|
|
81
|
+
this.#activeCount += 1;
|
|
82
82
|
},
|
|
83
83
|
write: async (chunk) => {
|
|
84
|
-
await this.
|
|
84
|
+
await this.#readableController.enqueue(chunk);
|
|
85
85
|
},
|
|
86
86
|
abort: () => {
|
|
87
|
-
this
|
|
88
|
-
if (this
|
|
89
|
-
this.
|
|
87
|
+
this.#activeCount -= 1;
|
|
88
|
+
if (this.#activeCount === 0) {
|
|
89
|
+
this.#readableController.close();
|
|
90
90
|
}
|
|
91
91
|
},
|
|
92
92
|
close: () => {
|
|
93
|
-
this
|
|
94
|
-
if (this
|
|
95
|
-
this.
|
|
93
|
+
this.#activeCount -= 1;
|
|
94
|
+
if (this.#activeCount === 0) {
|
|
95
|
+
this.#readableController.close();
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
});
|
|
@@ -108,20 +108,20 @@ class MultiplexStream<T> {
|
|
|
108
108
|
* * `resize`: Yes
|
|
109
109
|
*/
|
|
110
110
|
export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
111
|
-
|
|
111
|
+
static isSupported(adb: Adb) {
|
|
112
112
|
return adb.supportsFeature(AdbFeature.ShellV2);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
static async pty(adb: Adb, command: string) {
|
|
116
116
|
// TODO: AdbShellSubprocessProtocol: Support setting `XTERM` environment variable
|
|
117
117
|
return new AdbSubprocessShellProtocol(
|
|
118
|
-
await adb.createSocket(`shell,v2,pty:${command}`)
|
|
118
|
+
await adb.createSocket(`shell,v2,pty:${command}`),
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
static async raw(adb: Adb, command: string) {
|
|
123
123
|
return new AdbSubprocessShellProtocol(
|
|
124
|
-
await adb.createSocket(`shell,v2,raw:${command}`)
|
|
124
|
+
await adb.createSocket(`shell,v2,raw:${command}`),
|
|
125
125
|
);
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -131,26 +131,26 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
131
131
|
>;
|
|
132
132
|
|
|
133
133
|
#stdin: WritableStream<Consumable<Uint8Array>>;
|
|
134
|
-
|
|
134
|
+
get stdin() {
|
|
135
135
|
return this.#stdin;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
#stdout: ReadableStream<Uint8Array>;
|
|
139
|
-
|
|
139
|
+
get stdout() {
|
|
140
140
|
return this.#stdout;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
#stderr: ReadableStream<Uint8Array>;
|
|
144
|
-
|
|
144
|
+
get stderr() {
|
|
145
145
|
return this.#stderr;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
readonly #exit = new PromiseResolver<number>();
|
|
149
|
-
|
|
149
|
+
get exit() {
|
|
150
150
|
return this.#exit.promise;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
constructor(socket: AdbSocket) {
|
|
154
154
|
this.#socket = socket;
|
|
155
155
|
|
|
156
156
|
// Check this image to help you understand the stream graph
|
|
@@ -183,7 +183,7 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
183
183
|
break;
|
|
184
184
|
}
|
|
185
185
|
},
|
|
186
|
-
})
|
|
186
|
+
}),
|
|
187
187
|
)
|
|
188
188
|
.then(
|
|
189
189
|
() => {
|
|
@@ -191,7 +191,7 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
191
191
|
stderrController.close();
|
|
192
192
|
// If `#exit` has already resolved, this will be a no-op
|
|
193
193
|
this.#exit.reject(
|
|
194
|
-
new Error("Socket ended without exit message")
|
|
194
|
+
new Error("Socket ended without exit message"),
|
|
195
195
|
);
|
|
196
196
|
},
|
|
197
197
|
(e) => {
|
|
@@ -199,7 +199,7 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
199
199
|
stderrController.error(e);
|
|
200
200
|
// If `#exit` has already resolved, this will be a no-op
|
|
201
201
|
this.#exit.reject(e);
|
|
202
|
-
}
|
|
202
|
+
},
|
|
203
203
|
);
|
|
204
204
|
|
|
205
205
|
const multiplexer = new MultiplexStream<
|
|
@@ -210,34 +210,34 @@ export class AdbSubprocessShellProtocol implements AdbSubprocessProtocol {
|
|
|
210
210
|
new ConsumableTransformStream({
|
|
211
211
|
async transform(chunk, controller) {
|
|
212
212
|
await controller.enqueue(
|
|
213
|
-
AdbShellProtocolPacket.serialize(chunk)
|
|
213
|
+
AdbShellProtocolPacket.serialize(chunk),
|
|
214
214
|
);
|
|
215
215
|
},
|
|
216
|
-
})
|
|
216
|
+
}),
|
|
217
217
|
)
|
|
218
218
|
.pipeTo(socket.writable);
|
|
219
219
|
|
|
220
220
|
this.#stdin = pipeFrom(
|
|
221
221
|
multiplexer.createWriteable(),
|
|
222
|
-
new StdinSerializeStream()
|
|
222
|
+
new StdinSerializeStream(),
|
|
223
223
|
);
|
|
224
224
|
|
|
225
225
|
this.#socketWriter = multiplexer.createWriteable().getWriter();
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
|
|
228
|
+
async resize(rows: number, cols: number) {
|
|
229
229
|
await ConsumableWritableStream.write(this.#socketWriter, {
|
|
230
230
|
id: AdbShellProtocolId.WindowSizeChange,
|
|
231
231
|
data: encodeUtf8(
|
|
232
232
|
// The "correct" format is `${rows}x${cols},${x_pixels}x${y_pixels}`
|
|
233
233
|
// However, according to https://linux.die.net/man/4/tty_ioctl
|
|
234
234
|
// `x_pixels` and `y_pixels` are unused, so always sending `0` should be fine.
|
|
235
|
-
`${rows}x${cols},0x0\0
|
|
235
|
+
`${rows}x${cols},0x0\0`,
|
|
236
236
|
),
|
|
237
237
|
});
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
|
|
240
|
+
kill() {
|
|
241
241
|
return this.#socket.close();
|
|
242
242
|
}
|
|
243
243
|
}
|
|
@@ -30,7 +30,7 @@ export type AdbSyncEntry2Response =
|
|
|
30
30
|
|
|
31
31
|
export async function* adbSyncOpenDirV2(
|
|
32
32
|
socket: AdbSyncSocket,
|
|
33
|
-
path: string
|
|
33
|
+
path: string,
|
|
34
34
|
): AsyncGenerator<AdbSyncEntry2Response, void, void> {
|
|
35
35
|
const locked = await socket.lock();
|
|
36
36
|
try {
|
|
@@ -38,7 +38,7 @@ export async function* adbSyncOpenDirV2(
|
|
|
38
38
|
for await (const item of adbSyncReadResponses(
|
|
39
39
|
locked,
|
|
40
40
|
AdbSyncResponseId.Entry2,
|
|
41
|
-
AdbSyncEntry2Response
|
|
41
|
+
AdbSyncEntry2Response,
|
|
42
42
|
)) {
|
|
43
43
|
// `LST2` can return error codes for failed `lstat` calls.
|
|
44
44
|
// `LIST` just ignores them.
|
|
@@ -55,7 +55,7 @@ export async function* adbSyncOpenDirV2(
|
|
|
55
55
|
|
|
56
56
|
export async function* adbSyncOpenDirV1(
|
|
57
57
|
socket: AdbSyncSocket,
|
|
58
|
-
path: string
|
|
58
|
+
path: string,
|
|
59
59
|
): AsyncGenerator<AdbSyncEntryResponse, void, void> {
|
|
60
60
|
const locked = await socket.lock();
|
|
61
61
|
try {
|
|
@@ -63,7 +63,7 @@ export async function* adbSyncOpenDirV1(
|
|
|
63
63
|
for await (const item of adbSyncReadResponses(
|
|
64
64
|
locked,
|
|
65
65
|
AdbSyncResponseId.Entry,
|
|
66
|
-
AdbSyncEntryResponse
|
|
66
|
+
AdbSyncEntryResponse,
|
|
67
67
|
)) {
|
|
68
68
|
yield item;
|
|
69
69
|
}
|
|
@@ -75,7 +75,7 @@ export async function* adbSyncOpenDirV1(
|
|
|
75
75
|
export async function* adbSyncOpenDir(
|
|
76
76
|
socket: AdbSyncSocket,
|
|
77
77
|
path: string,
|
|
78
|
-
v2: boolean
|
|
78
|
+
v2: boolean,
|
|
79
79
|
): AsyncGenerator<AdbSyncEntry, void, void> {
|
|
80
80
|
if (v2) {
|
|
81
81
|
yield* adbSyncOpenDirV2(socket, path);
|
|
@@ -16,7 +16,7 @@ export type AdbSyncDataResponse =
|
|
|
16
16
|
|
|
17
17
|
export async function* adbSyncPullGenerator(
|
|
18
18
|
socket: AdbSyncSocket,
|
|
19
|
-
path: string
|
|
19
|
+
path: string,
|
|
20
20
|
): AsyncGenerator<Uint8Array, void, void> {
|
|
21
21
|
const locked = await socket.lock();
|
|
22
22
|
let done = false;
|
|
@@ -25,7 +25,7 @@ export async function* adbSyncPullGenerator(
|
|
|
25
25
|
for await (const packet of adbSyncReadResponses(
|
|
26
26
|
locked,
|
|
27
27
|
AdbSyncResponseId.Data,
|
|
28
|
-
AdbSyncDataResponse
|
|
28
|
+
AdbSyncDataResponse,
|
|
29
29
|
)) {
|
|
30
30
|
yield packet.data;
|
|
31
31
|
}
|
|
@@ -36,7 +36,7 @@ export async function* adbSyncPullGenerator(
|
|
|
36
36
|
for await (const packet of adbSyncReadResponses(
|
|
37
37
|
locked,
|
|
38
38
|
AdbSyncResponseId.Data,
|
|
39
|
-
AdbSyncDataResponse
|
|
39
|
+
AdbSyncDataResponse,
|
|
40
40
|
)) {
|
|
41
41
|
void packet;
|
|
42
42
|
}
|
|
@@ -47,7 +47,7 @@ export async function* adbSyncPullGenerator(
|
|
|
47
47
|
|
|
48
48
|
export function adbSyncPull(
|
|
49
49
|
socket: AdbSyncSocket,
|
|
50
|
-
path: string
|
|
50
|
+
path: string,
|
|
51
51
|
): ReadableStream<Uint8Array> {
|
|
52
52
|
return new PushReadableStream(async (controller) => {
|
|
53
53
|
for await (const data of adbSyncPullGenerator(socket, path)) {
|